blob: 7ea951f4db749e8ee49893e002af7bd6e0c72137 [file] [log] [blame]
/*
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
* SPDX-License-Identifier: MIT
*/
#ifndef NVK_CMD_BUFFER_H
#define NVK_CMD_BUFFER_H 1
#include "nvk_private.h"
#include "nv_push.h"
#include "nvk_cmd_pool.h"
#include "nvk_descriptor_set.h"
#include "nvk_image.h"
#include "nvk_shader.h"
#include "util/u_dynarray.h"
#include "vk_command_buffer.h"
#include <stdio.h>
struct nvk_buffer;
struct nvk_cbuf;
struct nvk_cmd_mem;
struct nvk_cmd_buffer;
struct nvk_cmd_pool;
struct nvk_image_view;
struct nvk_push_descriptor_set;
struct nvk_shader;
struct vk_shader;
/** Root descriptor table. This gets pushed to the GPU directly */
struct nvk_root_descriptor_table {
union {
struct {
uint32_t base_vertex;
uint32_t base_instance;
uint32_t draw_index;
uint32_t view_index;
struct nak_sample_location sample_locations[NVK_MAX_SAMPLES];
struct nak_sample_mask sample_masks[NVK_MAX_SAMPLES];
} draw;
struct {
uint32_t base_group[3];
uint32_t group_count[3];
} cs;
};
/* Client push constants */
uint8_t push[NVK_MAX_PUSH_SIZE];
/* Descriptor set addresses */
struct nvk_buffer_address sets[NVK_MAX_SETS];
/* For each descriptor set, the index in dynamic_buffers where that set's
* the dynamic buffers start. This is maintained for every set, regardless
* of whether or not anything is bound there.
*/
uint8_t set_dynamic_buffer_start[NVK_MAX_SETS];
/* Dynamic buffer bindings */
union nvk_buffer_descriptor dynamic_buffers[NVK_MAX_DYNAMIC_BUFFERS];
/* enfore alignment to 0x100 as needed pre pascal */
uint8_t __padding[0x38];
};
/* helper macro for computing root descriptor byte offsets */
#define nvk_root_descriptor_offset(member)\
offsetof(struct nvk_root_descriptor_table, member)
enum ENUM_PACKED nvk_descriptor_set_type {
NVK_DESCRIPTOR_SET_TYPE_NONE,
NVK_DESCRIPTOR_SET_TYPE_SET,
NVK_DESCRIPTOR_SET_TYPE_PUSH,
NVK_DESCRIPTOR_SET_TYPE_BUFFER,
};
struct nvk_descriptor_set_binding {
enum nvk_descriptor_set_type type;
struct nvk_descriptor_set *set;
struct nvk_push_descriptor_set *push;
};
struct nvk_descriptor_state {
alignas(16) char root[sizeof(struct nvk_root_descriptor_table)];
void (*flush_root)(struct nvk_cmd_buffer *cmd,
struct nvk_descriptor_state *desc,
size_t offset, size_t size);
struct nvk_descriptor_set_binding sets[NVK_MAX_SETS];
uint32_t push_dirty;
};
#define nvk_descriptor_state_get_root(desc, member, dst) do { \
const struct nvk_root_descriptor_table *root = \
(const struct nvk_root_descriptor_table *)(desc)->root; \
*dst = root->member; \
} while (0)
#define nvk_descriptor_state_get_root_array(desc, member, \
start, count, dst) do { \
const struct nvk_root_descriptor_table *root = \
(const struct nvk_root_descriptor_table *)(desc)->root; \
unsigned _start = start; \
assert(_start + count <= ARRAY_SIZE(root->member)); \
for (unsigned i = 0; i < count; i++) \
(dst)[i] = root->member[i + _start]; \
} while (0)
#define nvk_descriptor_state_set_root(cmd, desc, member, src) do { \
struct nvk_descriptor_state *_desc = (desc); \
struct nvk_root_descriptor_table *root = \
(struct nvk_root_descriptor_table *)_desc->root; \
root->member = (src); \
if (_desc->flush_root != NULL) { \
size_t offset = (char *)&root->member - (char *)root; \
_desc->flush_root((cmd), _desc, offset, sizeof(root->member)); \
} \
} while (0)
#define nvk_descriptor_state_set_root_array(cmd, desc, member, \
start, count, src) do { \
struct nvk_descriptor_state *_desc = (desc); \
struct nvk_root_descriptor_table *root = \
(struct nvk_root_descriptor_table *)_desc->root; \
unsigned _start = start; \
assert(_start + count <= ARRAY_SIZE(root->member)); \
for (unsigned i = 0; i < count; i++) \
root->member[i + _start] = (src)[i]; \
if (_desc->flush_root != NULL) { \
size_t offset = (char *)&root->member[_start] - (char *)root; \
_desc->flush_root((cmd), _desc, offset, \
count * sizeof(root->member[0])); \
} \
} while (0)
struct nvk_attachment {
VkFormat vk_format;
struct nvk_image_view *iview;
VkResolveModeFlagBits resolve_mode;
struct nvk_image_view *resolve_iview;
/* Needed to track the value of storeOp in case we need to copy images for
* the DRM_FORMAT_MOD_LINEAR case */
VkAttachmentStoreOp store_op;
};
struct nvk_rendering_state {
VkRenderingFlagBits flags;
VkRect2D area;
uint32_t layer_count;
uint32_t view_mask;
uint32_t samples;
uint32_t color_att_count;
struct nvk_attachment color_att[NVK_MAX_RTS];
struct nvk_attachment depth_att;
struct nvk_attachment stencil_att;
bool all_linear;
};
struct nvk_graphics_state {
struct nvk_rendering_state render;
struct nvk_descriptor_state descriptors;
uint32_t shaders_dirty;
struct nvk_shader *shaders[MESA_SHADER_MESH + 1];
struct nvk_cbuf_group {
uint16_t dirty;
struct nvk_cbuf cbufs[16];
} cbuf_groups[5];
/* Used for meta save/restore */
struct nvk_addr_range vb0;
/* Needed by vk_command_buffer::dynamic_graphics_state */
struct vk_vertex_input_state _dynamic_vi;
struct vk_sample_locations_state _dynamic_sl;
};
struct nvk_compute_state {
struct nvk_descriptor_state descriptors;
struct nvk_shader *shader;
};
struct nvk_cmd_push {
void *map;
uint64_t addr;
uint32_t range;
bool no_prefetch;
};
struct nvk_cmd_buffer {
struct vk_command_buffer vk;
struct {
uint64_t descriptor_buffers[NVK_MAX_SETS];
struct nvk_graphics_state gfx;
struct nvk_compute_state cs;
} state;
/** List of nvk_cmd_mem
*
* This list exists entirely for ownership tracking. Everything in here
* must also be in pushes or bo_refs if it is to be referenced by this
* command buffer.
*/
struct list_head owned_mem;
struct list_head owned_gart_mem;
struct nvk_cmd_mem *upload_mem;
uint32_t upload_offset;
struct nvk_cmd_mem *cond_render_gart_mem;
uint32_t cond_render_gart_offset;
struct nvk_cmd_mem *push_mem;
uint32_t *push_mem_limit;
struct nv_push push;
/** Array of struct nvk_cmd_push
*
* This acts both as a BO reference as well as provides a range in the
* buffer to use as a pushbuf.
*/
struct util_dynarray pushes;
uint64_t tls_space_needed;
};
VK_DEFINE_HANDLE_CASTS(nvk_cmd_buffer, vk.base, VkCommandBuffer,
VK_OBJECT_TYPE_COMMAND_BUFFER)
extern const struct vk_command_buffer_ops nvk_cmd_buffer_ops;
static inline struct nvk_device *
nvk_cmd_buffer_device(struct nvk_cmd_buffer *cmd)
{
return (struct nvk_device *)cmd->vk.base.device;
}
static inline struct nvk_cmd_pool *
nvk_cmd_buffer_pool(struct nvk_cmd_buffer *cmd)
{
return (struct nvk_cmd_pool *)cmd->vk.pool;
}
void nvk_cmd_buffer_new_push(struct nvk_cmd_buffer *cmd);
#define NVK_CMD_BUFFER_MAX_PUSH 512
static inline struct nv_push *
nvk_cmd_buffer_push(struct nvk_cmd_buffer *cmd, uint32_t dw_count)
{
assert(dw_count <= NVK_CMD_BUFFER_MAX_PUSH);
/* Compare to the actual limit on our push bo */
if (unlikely(cmd->push.end + dw_count > cmd->push_mem_limit))
nvk_cmd_buffer_new_push(cmd);
cmd->push.limit = cmd->push.end + dw_count;
return &cmd->push;
}
void
nvk_cmd_buffer_push_indirect(struct nvk_cmd_buffer *cmd,
uint64_t addr, uint32_t dw_count);
void nvk_cmd_buffer_begin_graphics(struct nvk_cmd_buffer *cmd,
const VkCommandBufferBeginInfo *pBeginInfo);
void nvk_cmd_buffer_begin_compute(struct nvk_cmd_buffer *cmd,
const VkCommandBufferBeginInfo *pBeginInfo);
void nvk_cmd_invalidate_graphics_state(struct nvk_cmd_buffer *cmd);
void nvk_cmd_invalidate_compute_state(struct nvk_cmd_buffer *cmd);
void nvk_cmd_bind_shaders(struct vk_command_buffer *vk_cmd,
uint32_t stage_count,
const gl_shader_stage *stages,
struct vk_shader ** const shaders);
void nvk_cmd_bind_graphics_shader(struct nvk_cmd_buffer *cmd,
const gl_shader_stage stage,
struct nvk_shader *shader);
void nvk_cmd_bind_compute_shader(struct nvk_cmd_buffer *cmd,
struct nvk_shader *shader);
void nvk_cmd_dirty_cbufs_for_descriptors(struct nvk_cmd_buffer *cmd,
VkShaderStageFlags stages,
uint32_t sets_start, uint32_t sets_end,
uint32_t dyn_start, uint32_t dyn_end);
void nvk_cmd_bind_vertex_buffer(struct nvk_cmd_buffer *cmd, uint32_t vb_idx,
struct nvk_addr_range addr_range);
static inline struct nvk_descriptor_state *
nvk_get_descriptors_state(struct nvk_cmd_buffer *cmd,
VkPipelineBindPoint bind_point)
{
switch (bind_point) {
case VK_PIPELINE_BIND_POINT_GRAPHICS:
return &cmd->state.gfx.descriptors;
case VK_PIPELINE_BIND_POINT_COMPUTE:
return &cmd->state.cs.descriptors;
default:
unreachable("Unhandled bind point");
}
};
VkResult nvk_cmd_buffer_upload_alloc(struct nvk_cmd_buffer *cmd,
uint32_t size, uint32_t alignment,
uint64_t *addr, void **ptr);
VkResult nvk_cmd_buffer_upload_data(struct nvk_cmd_buffer *cmd,
const void *data, uint32_t size,
uint32_t alignment, uint64_t *addr);
VkResult nvk_cmd_buffer_cond_render_alloc(struct nvk_cmd_buffer *cmd,
uint64_t *addr);
void nvk_cmd_flush_wait_dep(struct nvk_cmd_buffer *cmd,
const VkDependencyInfo *dep,
bool wait);
void nvk_cmd_invalidate_deps(struct nvk_cmd_buffer *cmd,
uint32_t dep_count,
const VkDependencyInfo *deps);
void
nvk_cmd_buffer_flush_push_descriptors(struct nvk_cmd_buffer *cmd,
struct nvk_descriptor_state *desc);
bool
nvk_cmd_buffer_get_cbuf_addr(struct nvk_cmd_buffer *cmd,
const struct nvk_descriptor_state *desc,
const struct nvk_shader *shader,
const struct nvk_cbuf *cbuf,
struct nvk_buffer_address *addr_out);
uint64_t
nvk_cmd_buffer_get_cbuf_descriptor_addr(struct nvk_cmd_buffer *cmd,
const struct nvk_descriptor_state *desc,
const struct nvk_cbuf *cbuf);
void nvk_cmd_dispatch_shader(struct nvk_cmd_buffer *cmd,
struct nvk_shader *shader,
const void *push_data, size_t push_size,
uint32_t groupCountX,
uint32_t groupCountY,
uint32_t groupCountZ);
void nvk_meta_resolve_rendering(struct nvk_cmd_buffer *cmd,
const VkRenderingInfo *pRenderingInfo);
void nvk_cmd_buffer_dump(struct nvk_cmd_buffer *cmd, FILE *fp);
void nvk_linear_render_copy(struct nvk_cmd_buffer *cmd,
const struct nvk_image_view *iview,
VkRect2D copy_rect,
bool copy_to_tiled_shadow);
#endif