vulkan: support multiple streams of buffers

This commit is contained in:
Wim Taymans 2022-05-30 18:34:31 +02:00
parent 332e8b7029
commit e6f01563ab
4 changed files with 214 additions and 137 deletions

View file

@ -47,8 +47,6 @@
#define NAME "vulkan-compute-filter" #define NAME "vulkan-compute-filter"
#define MAX_PORTS 1
struct buffer { struct buffer {
uint32_t id; uint32_t id;
#define BUFFER_FLAG_OUT (1<<0) #define BUFFER_FLAG_OUT (1<<0)
@ -75,6 +73,7 @@ struct port {
struct spa_list empty; struct spa_list empty;
struct spa_list ready; struct spa_list ready;
uint32_t stream_id;
}; };
struct impl { struct impl {
@ -103,7 +102,7 @@ struct impl {
struct port port[2]; struct port port[2];
}; };
#define CHECK_PORT(this,d,p) ((p) < MAX_PORTS) #define CHECK_PORT(this,d,p) ((p) < 1)
static int impl_node_enum_params(void *object, int seq, static int impl_node_enum_params(void *object, int seq,
uint32_t id, uint32_t start, uint32_t num, uint32_t id, uint32_t start, uint32_t num,
@ -416,7 +415,7 @@ static int clear_buffers(struct impl *this, struct port *port)
{ {
if (port->n_buffers > 0) { if (port->n_buffers > 0) {
spa_log_debug(this->log, NAME " %p: clear buffers", this); spa_log_debug(this->log, NAME " %p: clear buffers", this);
spa_vulkan_use_buffers(&this->state, 0, 0, NULL); spa_vulkan_use_buffers(&this->state, &this->state.streams[port->stream_id], 0, 0, NULL);
port->n_buffers = 0; port->n_buffers = 0;
spa_list_init(&port->empty); spa_list_init(&port->empty);
spa_list_init(&port->ready); spa_list_init(&port->ready);
@ -528,7 +527,7 @@ impl_node_port_use_buffers(void *object,
spa_list_append(&port->empty, &b->link); spa_list_append(&port->empty, &b->link);
} }
spa_vulkan_use_buffers(&this->state, flags, n_buffers, buffers); spa_vulkan_use_buffers(&this->state, &this->state.streams[port->stream_id], flags, n_buffers, buffers);
port->n_buffers = n_buffers; port->n_buffers = n_buffers;
return 0; return 0;
@ -693,24 +692,8 @@ impl_init(const struct spa_handle_factory *factory,
this->info.params = this->params; this->info.params = this->params;
this->info.n_params = 2; this->info.n_params = 2;
port = &this->port[SPA_DIRECTION_OUTPUT]; port = &this->port[0];
port->direction = SPA_DIRECTION_OUTPUT; port->stream_id = 0;
port->info_all = SPA_PORT_CHANGE_MASK_FLAGS |
SPA_PORT_CHANGE_MASK_PARAMS |
SPA_PORT_CHANGE_MASK_PROPS;
port->info = SPA_PORT_INFO_INIT();
port->info.flags = SPA_PORT_FLAG_NO_REF | SPA_PORT_FLAG_CAN_ALLOC_BUFFERS;
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
port->info.params = port->params;
port->info.n_params = 5;
spa_list_init(&port->empty);
spa_list_init(&port->ready);
port = &this->port[SPA_DIRECTION_INPUT];
port->direction = SPA_DIRECTION_INPUT; port->direction = SPA_DIRECTION_INPUT;
port->info_all = SPA_PORT_CHANGE_MASK_FLAGS | port->info_all = SPA_PORT_CHANGE_MASK_FLAGS |
SPA_PORT_CHANGE_MASK_PARAMS | SPA_PORT_CHANGE_MASK_PARAMS |
@ -727,7 +710,30 @@ impl_init(const struct spa_handle_factory *factory,
spa_list_init(&port->empty); spa_list_init(&port->empty);
spa_list_init(&port->ready); spa_list_init(&port->ready);
port = &this->port[1];
port->stream_id = 1;
port->direction = SPA_DIRECTION_OUTPUT;
port->info_all = SPA_PORT_CHANGE_MASK_FLAGS |
SPA_PORT_CHANGE_MASK_PARAMS |
SPA_PORT_CHANGE_MASK_PROPS;
port->info = SPA_PORT_INFO_INIT();
port->info.flags = SPA_PORT_FLAG_NO_REF | SPA_PORT_FLAG_CAN_ALLOC_BUFFERS;
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
port->info.params = port->params;
port->info.n_params = 5;
spa_list_init(&port->empty);
spa_list_init(&port->ready);
this->state.log = this->log; this->state.log = this->log;
spa_vulkan_init_stream(&this->state, &this->state.streams[0],
SPA_DIRECTION_INPUT, NULL);
spa_vulkan_init_stream(&this->state, &this->state.streams[1],
SPA_DIRECTION_OUTPUT, NULL);
this->state.n_streams = 2;
return 0; return 0;
} }

View file

@ -61,8 +61,6 @@ static void reset_props(struct props *props)
props->live = DEFAULT_LIVE; props->live = DEFAULT_LIVE;
} }
#define MAX_PORTS 1
struct buffer { struct buffer {
uint32_t id; uint32_t id;
#define BUFFER_FLAG_OUT (1<<0) #define BUFFER_FLAG_OUT (1<<0)
@ -122,7 +120,7 @@ struct impl {
struct port port; struct port port;
}; };
#define CHECK_PORT(this,d,p) ((d) == SPA_DIRECTION_OUTPUT && (p) < MAX_PORTS) #define CHECK_PORT(this,d,p) ((d) == SPA_DIRECTION_OUTPUT && (p) < 1)
static int impl_node_enum_params(void *object, int seq, static int impl_node_enum_params(void *object, int seq,
uint32_t id, uint32_t start, uint32_t num, uint32_t id, uint32_t start, uint32_t num,
@ -308,12 +306,13 @@ static int make_buffer(struct impl *this)
this->state.constants.time = this->elapsed_time / (float) SPA_NSEC_PER_SEC; this->state.constants.time = this->elapsed_time / (float) SPA_NSEC_PER_SEC;
this->state.constants.frame = this->frame_count; this->state.constants.frame = this->frame_count;
spa_vulkan_process(&this->state, b->id); this->state.streams[0].pending_buffer_id = b->id;
spa_vulkan_process(&this->state);
if (this->state.ready_buffer_id != SPA_ID_INVALID) { if (this->state.streams[0].ready_buffer_id != SPA_ID_INVALID) {
struct buffer *b = &port->buffers[this->state.ready_buffer_id]; struct buffer *b = &port->buffers[this->state.streams[0].ready_buffer_id];
this->state.ready_buffer_id = SPA_ID_INVALID; this->state.streams[0].ready_buffer_id = SPA_ID_INVALID;
spa_log_trace(this->log, NAME " %p: ready buffer %d", this, b->id); spa_log_trace(this->log, NAME " %p: ready buffer %d", this, b->id);
@ -636,7 +635,7 @@ static int clear_buffers(struct impl *this, struct port *port)
{ {
if (port->n_buffers > 0) { if (port->n_buffers > 0) {
spa_log_debug(this->log, NAME " %p: clear buffers", this); spa_log_debug(this->log, NAME " %p: clear buffers", this);
spa_vulkan_use_buffers(&this->state, 0, 0, NULL); spa_vulkan_use_buffers(&this->state, &this->state.streams[0], 0, 0, NULL);
port->n_buffers = 0; port->n_buffers = 0;
spa_list_init(&port->empty); spa_list_init(&port->empty);
spa_list_init(&port->ready); spa_list_init(&port->ready);
@ -749,7 +748,7 @@ impl_node_port_use_buffers(void *object,
spa_list_append(&port->empty, &b->link); spa_list_append(&port->empty, &b->link);
} }
spa_vulkan_use_buffers(&this->state, flags, n_buffers, buffers); spa_vulkan_use_buffers(&this->state, &this->state.streams[0], flags, n_buffers, buffers);
port->n_buffers = n_buffers; port->n_buffers = n_buffers;
return 0; return 0;
@ -958,6 +957,9 @@ impl_init(const struct spa_handle_factory *factory,
spa_list_init(&port->ready); spa_list_init(&port->ready);
this->state.log = this->log; this->state.log = this->log;
spa_vulkan_init_stream(&this->state, &this->state.streams[0],
SPA_DIRECTION_OUTPUT, NULL);
this->state.n_streams = 1;
return 0; return 0;
} }

View file

@ -217,31 +217,36 @@ static uint32_t findMemoryType(struct vulkan_state *s,
static int createDescriptors(struct vulkan_state *s) static int createDescriptors(struct vulkan_state *s)
{ {
static const VkDescriptorPoolSize descriptorPoolSize = { uint32_t i;
VkDescriptorPoolSize descriptorPoolSize = {
.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1 .descriptorCount = s->n_streams,
}; };
static const VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = { const VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
.maxSets = 1, .maxSets = 1,
.poolSizeCount = 1, .poolSizeCount = 1,
.pPoolSizes = &descriptorPoolSize, .pPoolSizes = &descriptorPoolSize,
}; };
VkDescriptorSetLayoutBinding descriptorSetLayoutBinding[s->n_streams];
VK_CHECK_RESULT(vkCreateDescriptorPool(s->device, VK_CHECK_RESULT(vkCreateDescriptorPool(s->device,
&descriptorPoolCreateInfo, NULL, &descriptorPoolCreateInfo, NULL,
&s->descriptorPool)); &s->descriptorPool));
static const VkDescriptorSetLayoutBinding descriptorSetLayoutBinding = { for (i = 0; i < s->n_streams; i++) {
.binding = 0, descriptorSetLayoutBinding[i] = (VkDescriptorSetLayoutBinding) {
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .binding = i,
.descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT .descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT
};
}; };
static const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = { const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.bindingCount = 1, .bindingCount = s->n_streams,
.pBindings = &descriptorSetLayoutBinding .pBindings = descriptorSetLayoutBinding
}; };
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(s->device, VK_CHECK_RESULT(vkCreateDescriptorSetLayout(s->device,
&descriptorSetLayoutCreateInfo, NULL, &descriptorSetLayoutCreateInfo, NULL,
@ -256,63 +261,42 @@ static int createDescriptors(struct vulkan_state *s)
VK_CHECK_RESULT(vkAllocateDescriptorSets(s->device, VK_CHECK_RESULT(vkAllocateDescriptorSets(s->device,
&descriptorSetAllocateInfo, &descriptorSetAllocateInfo,
&s->descriptorSet)); s->descriptorSet));
return 0; return 0;
} }
static int createBuffer(struct vulkan_state *s, uint32_t id) static int updateDescriptors(struct vulkan_state *s)
{ {
const VkBufferCreateInfo bufferCreateInfo = { uint32_t i;
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, VkDescriptorBufferInfo descriptorBufferInfo[s->n_streams];
.size = s->bufferSize, VkWriteDescriptorSet writeDescriptorSet[s->n_streams];
.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
};
VkMemoryRequirements memoryRequirements;
VK_CHECK_RESULT(vkCreateBuffer(s->device, for (i = 0; i < s->n_streams; i++) {
&bufferCreateInfo, NULL, &s->buffers[id].buffer)); struct vulkan_stream *p = &s->streams[i];
vkGetBufferMemoryRequirements(s->device, if (p->current_buffer_id == p->pending_buffer_id ||
s->buffers[id].buffer, &memoryRequirements); p->pending_buffer_id == SPA_ID_INVALID)
continue;
const VkMemoryAllocateInfo allocateInfo = { p->current_buffer_id = p->pending_buffer_id;
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, p->busy_buffer_id = p->current_buffer_id;
.allocationSize = memoryRequirements.size, p->pending_buffer_id = SPA_ID_INVALID;
.memoryTypeIndex = findMemoryType(s,
memoryRequirements.memoryTypeBits,
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT),
};
VK_CHECK_RESULT(vkAllocateMemory(s->device, descriptorBufferInfo[i] = (VkDescriptorBufferInfo) {
&allocateInfo, NULL, &s->buffers[id].memory)); .buffer = p->buffers[p->current_buffer_id].buffer,
VK_CHECK_RESULT(vkBindBufferMemory(s->device, .offset = 0,
s->buffers[id].buffer, s->buffers[id].memory, 0)); .range = p->bufferSize,
};
return 0; writeDescriptorSet[i] = (VkWriteDescriptorSet) {
} .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = s->descriptorSet[i],
static int updateDescriptors(struct vulkan_state *s, uint32_t buffer_id) .dstBinding = i,
{ .descriptorCount = 1,
if (s->current_buffer_id == buffer_id) .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
return 0; .pBufferInfo = &descriptorBufferInfo[i],
};
const VkDescriptorBufferInfo descriptorBufferInfo = { }
.buffer = s->buffers[buffer_id].buffer, vkUpdateDescriptorSets(s->device, s->n_streams, writeDescriptorSet, 0, NULL);
.offset = 0,
.range = s->bufferSize,
};
const VkWriteDescriptorSet writeDescriptorSet = {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = s->descriptorSet,
.dstBinding = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.pBufferInfo = &descriptorBufferInfo,
};
vkUpdateDescriptorSets(s->device, 1, &writeDescriptorSet, 0, NULL);
s->current_buffer_id = buffer_id;
return 0; return 0;
} }
@ -432,7 +416,7 @@ static int runCommandBuffer(struct vulkan_state *s)
s->pipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, s->pipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT,
0, sizeof(struct push_constants), (const void *) &s->constants); 0, sizeof(struct push_constants), (const void *) &s->constants);
vkCmdBindDescriptorSets(s->commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, vkCmdBindDescriptorSets(s->commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE,
s->pipelineLayout, 0, 1, &s->descriptorSet, 0, NULL); s->pipelineLayout, 0, s->n_streams, s->descriptorSet, 0, NULL);
vkCmdDispatch(s->commandBuffer, vkCmdDispatch(s->commandBuffer,
(uint32_t)ceil(s->constants.width / (float)WORKGROUP_SIZE), (uint32_t)ceil(s->constants.width / (float)WORKGROUP_SIZE),
@ -448,58 +432,117 @@ static int runCommandBuffer(struct vulkan_state *s)
.pCommandBuffers = &s->commandBuffer, .pCommandBuffers = &s->commandBuffer,
}; };
VK_CHECK_RESULT(vkQueueSubmit(s->queue, 1, &submitInfo, s->fence)); VK_CHECK_RESULT(vkQueueSubmit(s->queue, 1, &submitInfo, s->fence));
s->busy_buffer_id = s->current_buffer_id; s->started = true;
return 0; return 0;
} }
static void clear_buffers(struct vulkan_state *s) static void clear_buffers(struct vulkan_state *s, struct vulkan_stream *p)
{ {
uint32_t i; uint32_t i;
for (i = 0; i < s->n_buffers; i++) { for (i = 0; i < p->n_buffers; i++) {
close(s->buffers[i].buf->datas[0].fd); if (p->buffers[i].fd != -1)
vkFreeMemory(s->device, s->buffers[i].memory, NULL); close(p->buffers[i].fd);
vkDestroyBuffer(s->device, s->buffers[i].buffer, NULL); vkFreeMemory(s->device, p->buffers[i].memory, NULL);
vkDestroyBuffer(s->device, p->buffers[i].buffer, NULL);
} }
s->n_buffers = 0; p->n_buffers = 0;
} }
int spa_vulkan_use_buffers(struct vulkan_state *s, uint32_t flags, static void clear_streams(struct vulkan_state *s)
{
uint32_t i;
for (i = 0; i < s->n_streams; i++) {
struct vulkan_stream *p = &s->streams[i];
clear_buffers(s, p);
}
}
int spa_vulkan_use_buffers(struct vulkan_state *s, struct vulkan_stream *p, uint32_t flags,
uint32_t n_buffers, struct spa_buffer **buffers) uint32_t n_buffers, struct spa_buffer **buffers)
{ {
uint32_t i; uint32_t i;
VULKAN_INSTANCE_FUNCTION(vkGetMemoryFdKHR); VULKAN_INSTANCE_FUNCTION(vkGetMemoryFdKHR);
clear_buffers(s); clear_buffers(s, p);
s->bufferSize = s->constants.width * s->constants.height * sizeof(struct pixel); p->bufferSize = s->constants.width * s->constants.height * sizeof(struct pixel);
for (i = 0; i < n_buffers; i++) { for (i = 0; i < n_buffers; i++) {
createBuffer(s, i); const VkBufferCreateInfo bufferCreateInfo = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
const VkMemoryGetFdInfoKHR getFdInfo = { .size = p->bufferSize,
.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR, .usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
.memory = s->buffers[i].memory, .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT
}; };
int fd; VK_CHECK_RESULT(vkCreateBuffer(s->device,
&bufferCreateInfo, NULL, &p->buffers[i].buffer));
s->buffers[i].buf = buffers[i]; VkMemoryRequirements memoryRequirements;
vkGetBufferMemoryRequirements(s->device,
p->buffers[i].buffer, &memoryRequirements);
VK_CHECK_RESULT(vkGetMemoryFdKHR(s->device, &getFdInfo, &fd)); VkMemoryAllocateInfo allocateInfo = {
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.allocationSize = memoryRequirements.size,
.memoryTypeIndex = findMemoryType(s,
memoryRequirements.memoryTypeBits,
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT),
};
buffers[i]->datas[0].type = SPA_DATA_DmaBuf; if (flags & SPA_NODE_BUFFERS_FLAG_ALLOC) {
buffers[i]->datas[0].flags = SPA_DATA_FLAG_READABLE; VK_CHECK_RESULT(vkAllocateMemory(s->device,
buffers[i]->datas[0].fd = fd; &allocateInfo, NULL, &p->buffers[i].memory));
buffers[i]->datas[0].mapoffset = 0;
buffers[i]->datas[0].maxsize = s->bufferSize; const VkMemoryGetFdInfoKHR getFdInfo = {
.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
.memory = p->buffers[i].memory,
.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT
};
int fd;
VK_CHECK_RESULT(vkGetMemoryFdKHR(s->device, &getFdInfo, &fd));
// buffers[i]->datas[0].type = SPA_DATA_DmaBuf;
buffers[i]->datas[0].type = SPA_DATA_MemFd;
buffers[i]->datas[0].fd = fd;
buffers[i]->datas[0].flags = SPA_DATA_FLAG_READABLE;
buffers[i]->datas[0].mapoffset = 0;
buffers[i]->datas[0].maxsize = p->bufferSize;
p->buffers[i].fd = fd;
} else {
VkImportMemoryFdInfoKHR importInfo = {
.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
.fd = fcntl(buffers[i]->datas[0].fd, F_DUPFD_CLOEXEC, 0),
};
allocateInfo.pNext = &importInfo;
p->buffers[i].fd = -1;
VK_CHECK_RESULT(vkAllocateMemory(s->device,
&allocateInfo, NULL, &p->buffers[i].memory));
}
VK_CHECK_RESULT(vkBindBufferMemory(s->device,
p->buffers[i].buffer, p->buffers[i].memory, 0));
} }
s->n_buffers = n_buffers; p->n_buffers = n_buffers;
return 0; return 0;
} }
int spa_vulkan_init_stream(struct vulkan_state *s, struct vulkan_stream *stream,
enum spa_direction direction, struct spa_dict *props)
{
spa_zero(*stream);
stream->direction = direction;
stream->current_buffer_id = SPA_ID_INVALID;
stream->busy_buffer_id = SPA_ID_INVALID;
stream->ready_buffer_id = SPA_ID_INVALID;
return 0;
}
int spa_vulkan_prepare(struct vulkan_state *s) int spa_vulkan_prepare(struct vulkan_state *s)
{ {
if (!s->prepared) { if (!s->prepared) {
@ -532,23 +575,31 @@ int spa_vulkan_unprepare(struct vulkan_state *s)
int spa_vulkan_start(struct vulkan_state *s) int spa_vulkan_start(struct vulkan_state *s)
{ {
s->current_buffer_id = SPA_ID_INVALID; uint32_t i;
s->busy_buffer_id = SPA_ID_INVALID;
s->ready_buffer_id = SPA_ID_INVALID; for (i = 0; i < s->n_streams; i++) {
struct vulkan_stream *p = &s->streams[i];
p->current_buffer_id = SPA_ID_INVALID;
p->busy_buffer_id = SPA_ID_INVALID;
p->ready_buffer_id = SPA_ID_INVALID;
}
return 0; return 0;
} }
int spa_vulkan_stop(struct vulkan_state *s) int spa_vulkan_stop(struct vulkan_state *s)
{ {
VK_CHECK_RESULT(vkDeviceWaitIdle(s->device)); VK_CHECK_RESULT(vkDeviceWaitIdle(s->device));
clear_streams(s);
s->started = false;
return 0; return 0;
} }
int spa_vulkan_ready(struct vulkan_state *s) int spa_vulkan_ready(struct vulkan_state *s)
{ {
uint32_t i;
VkResult result; VkResult result;
if (s->busy_buffer_id == SPA_ID_INVALID) if (!s->started)
return 0; return 0;
result = vkGetFenceStatus(s->device, s->fence); result = vkGetFenceStatus(s->device, s->fence);
@ -556,15 +607,19 @@ int spa_vulkan_ready(struct vulkan_state *s)
return -EBUSY; return -EBUSY;
VK_CHECK_RESULT(result); VK_CHECK_RESULT(result);
s->ready_buffer_id = s->busy_buffer_id; s->started = false;
s->busy_buffer_id = SPA_ID_INVALID;
for (i = 0; i < s->n_streams; i++) {
struct vulkan_stream *p = &s->streams[i];
p->ready_buffer_id = p->busy_buffer_id;
p->busy_buffer_id = SPA_ID_INVALID;
}
return 0; return 0;
} }
int spa_vulkan_process(struct vulkan_state *s, uint32_t buffer_id) int spa_vulkan_process(struct vulkan_state *s)
{ {
updateDescriptors(s, buffer_id); updateDescriptors(s);
runCommandBuffer(s); runCommandBuffer(s);
return 0; return 0;

View file

@ -1,7 +1,9 @@
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include <spa/buffer/buffer.h> #include <spa/buffer/buffer.h>
#include <spa/node/node.h>
#define MAX_STREAMS 2
#define MAX_BUFFERS 16 #define MAX_BUFFERS 16
#define WORKGROUP_SIZE 32 #define WORKGROUP_SIZE 32
@ -17,11 +19,24 @@ struct push_constants {
}; };
struct vulkan_buffer { struct vulkan_buffer {
struct spa_buffer *buf; int fd;
VkBuffer buffer; VkBuffer buffer;
VkDeviceMemory memory; VkDeviceMemory memory;
}; };
struct vulkan_stream {
enum spa_direction direction;
uint32_t pending_buffer_id;
uint32_t current_buffer_id;
uint32_t busy_buffer_id;
uint32_t ready_buffer_id;
uint32_t bufferSize;
struct vulkan_buffer buffers[MAX_BUFFERS];
uint32_t n_buffers;
};
struct vulkan_state { struct vulkan_state {
struct spa_log *log; struct spa_log *log;
@ -43,27 +58,26 @@ struct vulkan_state {
uint32_t queueFamilyIndex; uint32_t queueFamilyIndex;
VkFence fence; VkFence fence;
unsigned int prepared:1; unsigned int prepared:1;
uint32_t busy_buffer_id; unsigned int started:1;
uint32_t ready_buffer_id;
VkDescriptorPool descriptorPool; VkDescriptorPool descriptorPool;
VkDescriptorSet descriptorSet;
VkDescriptorSetLayout descriptorSetLayout; VkDescriptorSetLayout descriptorSetLayout;
uint32_t current_buffer_id;
uint32_t bufferSize;
struct vulkan_buffer buffers[MAX_BUFFERS];
uint32_t n_buffers;
uint32_t n_streams;
VkDescriptorSet descriptorSet[MAX_STREAMS];
struct vulkan_stream streams[MAX_STREAMS];
}; };
int spa_vulkan_init_stream(struct vulkan_state *s, struct vulkan_stream *stream, enum spa_direction,
struct spa_dict *props);
int spa_vulkan_prepare(struct vulkan_state *s); int spa_vulkan_prepare(struct vulkan_state *s);
int spa_vulkan_use_buffers(struct vulkan_state *s, uint32_t flags, int spa_vulkan_use_buffers(struct vulkan_state *s, struct vulkan_stream *stream, uint32_t flags,
uint32_t n_buffers, struct spa_buffer **buffers); uint32_t n_buffers, struct spa_buffer **buffers);
int spa_vulkan_unprepare(struct vulkan_state *s); int spa_vulkan_unprepare(struct vulkan_state *s);
int spa_vulkan_start(struct vulkan_state *s); int spa_vulkan_start(struct vulkan_state *s);
int spa_vulkan_stop(struct vulkan_state *s); int spa_vulkan_stop(struct vulkan_state *s);
int spa_vulkan_ready(struct vulkan_state *s); int spa_vulkan_ready(struct vulkan_state *s);
int spa_vulkan_process(struct vulkan_state *s, uint32_t buffer_id); int spa_vulkan_process(struct vulkan_state *s);
int spa_vulkan_cleanup(struct vulkan_state *s); int spa_vulkan_cleanup(struct vulkan_state *s);