mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-02 09:01:50 -05:00
vulkan: use images
The filter can now run shadertoy filters.
This commit is contained in:
parent
24fc972164
commit
b02ebec954
5 changed files with 102 additions and 63 deletions
|
|
@ -4,14 +4,7 @@
|
|||
#define WORKGROUP_SIZE 32
|
||||
layout (local_size_x = WORKGROUP_SIZE, local_size_y = WORKGROUP_SIZE, local_size_z = 1 ) in;
|
||||
|
||||
struct Pixel{
|
||||
vec4 value;
|
||||
};
|
||||
|
||||
layout(std140, binding = 0) buffer buf
|
||||
{
|
||||
Pixel imageData[];
|
||||
};
|
||||
layout(rgba32f, binding = 0) uniform image2D resultImage;
|
||||
|
||||
layout( push_constant ) uniform Constants {
|
||||
float time;
|
||||
|
|
@ -42,8 +35,7 @@ void main()
|
|||
|
||||
mainImage(outColor, coord);
|
||||
|
||||
imageData[PushConstant.width * gl_GlobalInvocationID.y +
|
||||
gl_GlobalInvocationID.x].value = outColor;
|
||||
imageStore(resultImage, ivec2(gl_GlobalInvocationID.xy), outColor);
|
||||
}
|
||||
|
||||
//#include "plasma-globe.comp"
|
||||
|
|
|
|||
|
|
@ -91,12 +91,7 @@ struct impl {
|
|||
struct spa_hook_list hooks;
|
||||
struct spa_callbacks callbacks;
|
||||
|
||||
bool async;
|
||||
struct spa_source timer_source;
|
||||
struct itimerspec timerspec;
|
||||
|
||||
bool started;
|
||||
uint64_t frame_count;
|
||||
|
||||
struct vulkan_state state;
|
||||
struct port port[2];
|
||||
|
|
@ -177,7 +172,7 @@ static inline void reuse_buffer(struct impl *this, struct port *port, uint32_t i
|
|||
struct buffer *b = &port->buffers[id];
|
||||
|
||||
if (SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_OUT)) {
|
||||
spa_log_info(this->log, NAME " %p: reuse buffer %d", this, id);
|
||||
spa_log_debug(this->log, NAME " %p: reuse buffer %d", this, id);
|
||||
|
||||
SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_OUT);
|
||||
spa_list_append(&port->empty, &b->link);
|
||||
|
|
@ -196,7 +191,6 @@ static int impl_node_send_command(void *object, const struct spa_command *comman
|
|||
if (this->started)
|
||||
return 0;
|
||||
|
||||
this->frame_count = 0;
|
||||
this->started = true;
|
||||
spa_vulkan_start(&this->state);
|
||||
break;
|
||||
|
|
@ -608,21 +602,31 @@ static int impl_node_process(void *object)
|
|||
}
|
||||
|
||||
if (spa_list_is_empty(&outport->empty)) {
|
||||
spa_log_error(this->log, NAME " %p: out of buffers", this);
|
||||
spa_log_debug(this->log, NAME " %p: out of buffers", this);
|
||||
return -EPIPE;
|
||||
}
|
||||
b = &inport->buffers[inio->buffer_id];
|
||||
this->state.streams[0].pending_buffer_id = b->id;
|
||||
this->state.streams[inport->stream_id].pending_buffer_id = b->id;
|
||||
inio->status = SPA_STATUS_NEED_DATA;
|
||||
|
||||
b = spa_list_first(&outport->empty, struct buffer, link);
|
||||
spa_list_remove(&b->link);
|
||||
this->state.streams[1].pending_buffer_id = b->id;
|
||||
SPA_FLAG_SET(b->flags, BUFFER_FLAG_OUT);
|
||||
this->state.streams[outport->stream_id].pending_buffer_id = b->id;
|
||||
|
||||
this->state.constants.time += 0.025;
|
||||
this->state.constants.frame++;
|
||||
|
||||
spa_log_debug(this->log, "filter into %d", b->id);
|
||||
|
||||
spa_vulkan_process(&this->state);
|
||||
|
||||
b->outbuf->datas[0].chunk->offset = 0;
|
||||
b->outbuf->datas[0].chunk->size = b->outbuf->datas[0].maxsize;
|
||||
b->outbuf->datas[0].chunk->stride = this->position->video.stride;
|
||||
|
||||
outio->buffer_id = b->id;
|
||||
outio->status = SPA_STATUS_HAVE_DATA;
|
||||
inio->status = SPA_STATUS_NEED_DATA;
|
||||
|
||||
return SPA_STATUS_NEED_DATA | SPA_STATUS_HAVE_DATA;
|
||||
}
|
||||
|
|
@ -694,6 +698,7 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
|
||||
this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
|
||||
this->state.log = this->log;
|
||||
this->state.shaderName = "spa/plugins/vulkan/shaders/filter.spv";
|
||||
|
||||
spa_hook_list_init(&this->hooks);
|
||||
|
||||
|
|
@ -715,7 +720,7 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
this->info.n_params = 2;
|
||||
|
||||
port = &this->port[0];
|
||||
port->stream_id = 0;
|
||||
port->stream_id = 1;
|
||||
port->direction = SPA_DIRECTION_INPUT;
|
||||
port->info_all = SPA_PORT_CHANGE_MASK_FLAGS |
|
||||
SPA_PORT_CHANGE_MASK_PARAMS |
|
||||
|
|
@ -729,13 +734,13 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 5;
|
||||
spa_vulkan_init_stream(&this->state, &this->state.streams[0],
|
||||
spa_vulkan_init_stream(&this->state, &this->state.streams[port->stream_id],
|
||||
SPA_DIRECTION_INPUT, NULL);
|
||||
spa_list_init(&port->empty);
|
||||
spa_list_init(&port->ready);
|
||||
|
||||
port = &this->port[1];
|
||||
port->stream_id = 1;
|
||||
port->stream_id = 0;
|
||||
port->direction = SPA_DIRECTION_OUTPUT;
|
||||
port->info_all = SPA_PORT_CHANGE_MASK_FLAGS |
|
||||
SPA_PORT_CHANGE_MASK_PARAMS |
|
||||
|
|
@ -751,7 +756,7 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
port->info.n_params = 5;
|
||||
spa_list_init(&port->empty);
|
||||
spa_list_init(&port->ready);
|
||||
spa_vulkan_init_stream(&this->state, &this->state.streams[1],
|
||||
spa_vulkan_init_stream(&this->state, &this->state.streams[port->stream_id],
|
||||
SPA_DIRECTION_OUTPUT, NULL);
|
||||
|
||||
this->state.n_streams = 2;
|
||||
|
|
|
|||
|
|
@ -959,6 +959,7 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
this->state.log = this->log;
|
||||
spa_vulkan_init_stream(&this->state, &this->state.streams[0],
|
||||
SPA_DIRECTION_OUTPUT, NULL);
|
||||
this->state.shaderName = "spa/plugins/vulkan/shaders/main.spv";
|
||||
this->state.n_streams = 1;
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include <time.h>
|
||||
|
||||
#include <spa/utils/result.h>
|
||||
#include <spa/utils/string.h>
|
||||
#include <spa/support/log.h>
|
||||
#include <spa/debug/mem.h>
|
||||
|
||||
|
|
@ -91,10 +92,10 @@ static int vkresult_to_errno(VkResult result)
|
|||
#define VK_CHECK_RESULT(f) \
|
||||
{ \
|
||||
VkResult _result = (f); \
|
||||
int _res = -vkresult_to_errno(_result); \
|
||||
int _r = -vkresult_to_errno(_result); \
|
||||
if (_result != VK_SUCCESS) { \
|
||||
spa_log_error(s->log, "error: %d (%s)", _result, spa_strerror(_res)); \
|
||||
return _res; \
|
||||
spa_log_error(s->log, "error: %d (%d %s)", _result, _r, spa_strerror(_r)); \
|
||||
return _r; \
|
||||
} \
|
||||
}
|
||||
#define CHECK(f) \
|
||||
|
|
@ -117,24 +118,32 @@ static int createInstance(struct vulkan_state *s)
|
|||
static const char * const extensions[] = {
|
||||
VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME
|
||||
};
|
||||
static const char * const layers[] = {
|
||||
static const char * const checkLayers[] = {
|
||||
#ifdef ENABLE_VALIDATION
|
||||
"VK_LAYER_KHRONOS_validation",
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
uint32_t i, layerCount;
|
||||
uint32_t i, j, layerCount, n_layers = 0;
|
||||
const char *layers[1];
|
||||
vkEnumerateInstanceLayerProperties(&layerCount, NULL);
|
||||
|
||||
VkLayerProperties availableLayers[layerCount];
|
||||
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers);
|
||||
|
||||
for (i = 0; i < layerCount; i++)
|
||||
spa_log_info(s->log, "%s", availableLayers[i].layerName);
|
||||
for (i = 0; i < layerCount; i++) {
|
||||
for (j = 0; j < SPA_N_ELEMENTS(checkLayers); j++) {
|
||||
if (spa_streq(availableLayers[i].layerName, checkLayers[j]))
|
||||
layers[n_layers++] = checkLayers[j];
|
||||
}
|
||||
}
|
||||
|
||||
const VkInstanceCreateInfo createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||
.pApplicationInfo = &applicationInfo,
|
||||
.enabledExtensionCount = 1,
|
||||
.ppEnabledExtensionNames = extensions,
|
||||
.enabledLayerCount = 1,
|
||||
.enabledLayerCount = n_layers,
|
||||
.ppEnabledLayerNames = layers,
|
||||
};
|
||||
|
||||
|
|
@ -239,7 +248,7 @@ static int createDescriptors(struct vulkan_state *s)
|
|||
uint32_t i;
|
||||
|
||||
VkDescriptorPoolSize descriptorPoolSize = {
|
||||
.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
||||
.descriptorCount = s->n_streams,
|
||||
};
|
||||
const VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = {
|
||||
|
|
@ -257,7 +266,7 @@ static int createDescriptors(struct vulkan_state *s)
|
|||
for (i = 0; i < s->n_streams; i++) {
|
||||
descriptorSetLayoutBinding[i] = (VkDescriptorSetLayoutBinding) {
|
||||
.binding = i,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT
|
||||
};
|
||||
|
|
@ -281,13 +290,16 @@ static int createDescriptors(struct vulkan_state *s)
|
|||
VK_CHECK_RESULT(vkAllocateDescriptorSets(s->device,
|
||||
&descriptorSetAllocateInfo,
|
||||
&s->descriptorSet));
|
||||
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int updateDescriptors(struct vulkan_state *s)
|
||||
{
|
||||
uint32_t i;
|
||||
VkDescriptorBufferInfo descriptorBufferInfo[s->n_streams];
|
||||
VkDescriptorImageInfo descriptorImageInfo[s->n_streams];
|
||||
VkWriteDescriptorSet writeDescriptorSet[s->n_streams];
|
||||
|
||||
for (i = 0; i < s->n_streams; i++) {
|
||||
|
|
@ -301,18 +313,17 @@ static int updateDescriptors(struct vulkan_state *s)
|
|||
p->busy_buffer_id = p->current_buffer_id;
|
||||
p->pending_buffer_id = SPA_ID_INVALID;
|
||||
|
||||
descriptorBufferInfo[i] = (VkDescriptorBufferInfo) {
|
||||
.buffer = p->buffers[p->current_buffer_id].buffer,
|
||||
.offset = 0,
|
||||
.range = p->bufferSize,
|
||||
descriptorImageInfo[i] = (VkDescriptorImageInfo) {
|
||||
.imageView = p->buffers[p->current_buffer_id].view,
|
||||
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
};
|
||||
writeDescriptorSet[i] = (VkWriteDescriptorSet) {
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.dstSet = s->descriptorSet,
|
||||
.dstBinding = i,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
.pBufferInfo = &descriptorBufferInfo[i],
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
||||
.pImageInfo = &descriptorImageInfo[i],
|
||||
};
|
||||
}
|
||||
vkUpdateDescriptorSets(s->device, s->n_streams,
|
||||
|
|
@ -465,7 +476,8 @@ static void clear_buffers(struct vulkan_state *s, struct vulkan_stream *p)
|
|||
if (p->buffers[i].fd != -1)
|
||||
close(p->buffers[i].fd);
|
||||
vkFreeMemory(s->device, p->buffers[i].memory, NULL);
|
||||
vkDestroyBuffer(s->device, p->buffers[i].buffer, NULL);
|
||||
vkDestroyImage(s->device, p->buffers[i].image, NULL);
|
||||
vkDestroyImageView(s->device, p->buffers[i].view, NULL);
|
||||
}
|
||||
p->n_buffers = 0;
|
||||
}
|
||||
|
|
@ -487,30 +499,37 @@ int spa_vulkan_use_buffers(struct vulkan_state *s, struct vulkan_stream *p, uint
|
|||
|
||||
clear_buffers(s, p);
|
||||
|
||||
p->bufferSize = s->constants.width * s->constants.height * sizeof(struct pixel);
|
||||
|
||||
for (i = 0; i < n_buffers; i++) {
|
||||
VkExternalMemoryBufferCreateInfo extInfo;
|
||||
VkBufferCreateInfo bufferCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.size = p->bufferSize,
|
||||
.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
|
||||
VkExternalMemoryImageCreateInfo extInfo;
|
||||
VkImageCreateInfo imageCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
.imageType = VK_IMAGE_TYPE_2D,
|
||||
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||
.extent.width = s->constants.width,
|
||||
.extent.height = s->constants.height,
|
||||
.extent.depth = 1,
|
||||
.mipLevels = 1,
|
||||
.arrayLayers = 1,
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.tiling = VK_IMAGE_TILING_LINEAR,
|
||||
.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
};
|
||||
if (!(flags & SPA_NODE_BUFFERS_FLAG_ALLOC)) {
|
||||
extInfo = (VkExternalMemoryBufferCreateInfo) {
|
||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
|
||||
extInfo = (VkExternalMemoryImageCreateInfo) {
|
||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
|
||||
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
|
||||
};
|
||||
bufferCreateInfo.pNext = &extInfo;
|
||||
imageCreateInfo.pNext = &extInfo;
|
||||
}
|
||||
|
||||
VK_CHECK_RESULT(vkCreateBuffer(s->device,
|
||||
&bufferCreateInfo, NULL, &p->buffers[i].buffer));
|
||||
VK_CHECK_RESULT(vkCreateImage(s->device,
|
||||
&imageCreateInfo, NULL, &p->buffers[i].image));
|
||||
|
||||
VkMemoryRequirements memoryRequirements;
|
||||
vkGetBufferMemoryRequirements(s->device,
|
||||
p->buffers[i].buffer, &memoryRequirements);
|
||||
vkGetImageMemoryRequirements(s->device,
|
||||
p->buffers[i].image, &memoryRequirements);
|
||||
|
||||
VkMemoryAllocateInfo allocateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
|
|
@ -534,12 +553,14 @@ int spa_vulkan_use_buffers(struct vulkan_state *s, struct vulkan_stream *p, uint
|
|||
|
||||
VK_CHECK_RESULT(vkGetMemoryFdKHR(s->device, &getFdInfo, &fd));
|
||||
|
||||
spa_log_info(s->log, "export DMABUF %zd", memoryRequirements.size);
|
||||
|
||||
// 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;
|
||||
buffers[i]->datas[0].maxsize = memoryRequirements.size;
|
||||
p->buffers[i].fd = fd;
|
||||
} else {
|
||||
VkImportMemoryFdInfoKHR importInfo = {
|
||||
|
|
@ -549,12 +570,30 @@ int spa_vulkan_use_buffers(struct vulkan_state *s, struct vulkan_stream *p, uint
|
|||
};
|
||||
allocateInfo.pNext = &importInfo;
|
||||
p->buffers[i].fd = -1;
|
||||
spa_log_info(s->log, "import DMABUF");
|
||||
|
||||
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));
|
||||
VK_CHECK_RESULT(vkBindImageMemory(s->device,
|
||||
p->buffers[i].image, p->buffers[i].memory, 0));
|
||||
|
||||
VkImageViewCreateInfo viewInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
.image = p->buffers[i].image,
|
||||
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
||||
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||
.components.r = VK_COMPONENT_SWIZZLE_R,
|
||||
.components.g = VK_COMPONENT_SWIZZLE_G,
|
||||
.components.b = VK_COMPONENT_SWIZZLE_B,
|
||||
.components.a = VK_COMPONENT_SWIZZLE_A,
|
||||
.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.subresourceRange.levelCount = 1,
|
||||
.subresourceRange.layerCount = 1,
|
||||
};
|
||||
|
||||
VK_CHECK_RESULT(vkCreateImageView(s->device,
|
||||
&viewInfo, NULL, &p->buffers[i].view));
|
||||
}
|
||||
p->n_buffers = n_buffers;
|
||||
|
||||
|
|
@ -579,7 +618,7 @@ int spa_vulkan_prepare(struct vulkan_state *s)
|
|||
CHECK(findPhysicalDevice(s));
|
||||
CHECK(createDevice(s));
|
||||
CHECK(createDescriptors(s));
|
||||
CHECK(createComputePipeline(s, "spa/plugins/vulkan/shaders/main.spv"));
|
||||
CHECK(createComputePipeline(s, s->shaderName));
|
||||
CHECK(createCommandBuffer(s));
|
||||
s->prepared = true;
|
||||
}
|
||||
|
|
@ -651,6 +690,7 @@ int spa_vulkan_process(struct vulkan_state *s)
|
|||
{
|
||||
CHECK(updateDescriptors(s));
|
||||
CHECK(runCommandBuffer(s));
|
||||
VK_CHECK_RESULT(vkDeviceWaitIdle(s->device));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ struct push_constants {
|
|||
|
||||
struct vulkan_buffer {
|
||||
int fd;
|
||||
VkBuffer buffer;
|
||||
VkImage image;
|
||||
VkImageView view;
|
||||
VkDeviceMemory memory;
|
||||
};
|
||||
|
||||
|
|
@ -32,7 +33,6 @@ struct vulkan_stream {
|
|||
uint32_t busy_buffer_id;
|
||||
uint32_t ready_buffer_id;
|
||||
|
||||
uint32_t bufferSize;
|
||||
struct vulkan_buffer buffers[MAX_BUFFERS];
|
||||
uint32_t n_buffers;
|
||||
};
|
||||
|
|
@ -49,6 +49,7 @@ struct vulkan_state {
|
|||
|
||||
VkPipeline pipeline;
|
||||
VkPipelineLayout pipelineLayout;
|
||||
const char *shaderName;
|
||||
VkShaderModule computeShaderModule;
|
||||
|
||||
VkCommandPool commandPool;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue