mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-21 06:46:46 -04:00
Merge branch 'vulkan-software' into 'master'
Draft: render/vulkan: add support for software rendering See merge request wlroots/wlroots!3440
This commit is contained in:
commit
ea2a22d4b4
6 changed files with 215 additions and 26 deletions
|
|
@ -58,12 +58,14 @@ struct wlr_vk_device {
|
|||
|
||||
struct {
|
||||
PFN_vkGetMemoryFdPropertiesKHR getMemoryFdPropertiesKHR;
|
||||
PFN_vkGetMemoryHostPointerPropertiesEXT getMemoryHostPointerPropertiesEXT;
|
||||
} api;
|
||||
|
||||
uint32_t format_prop_count;
|
||||
struct wlr_vk_format_props *format_props;
|
||||
struct wlr_drm_format_set dmabuf_render_formats;
|
||||
struct wlr_drm_format_set dmabuf_texture_formats;
|
||||
struct wlr_drm_format_set shm_render_formats;
|
||||
|
||||
// supported formats for textures (contains only those formats
|
||||
// that support everything we need for textures)
|
||||
|
|
@ -260,6 +262,9 @@ VkImage vulkan_import_dmabuf(struct wlr_vk_renderer *renderer,
|
|||
const struct wlr_dmabuf_attributes *attribs,
|
||||
VkDeviceMemory mems[static WLR_DMABUF_MAX_PLANES], uint32_t *n_mems,
|
||||
bool for_render);
|
||||
VkImage vulkan_import_host_memory(struct wlr_vk_renderer *renderer,
|
||||
void *host_ptr, uint32_t format, uint32_t width, uint32_t height,
|
||||
uint32_t stride, VkDeviceMemory *mem, bool for_render);
|
||||
struct wlr_texture *vulkan_texture_from_buffer(
|
||||
struct wlr_renderer *wlr_renderer, struct wlr_buffer *buffer);
|
||||
void vulkan_texture_destroy(struct wlr_vk_texture *texture);
|
||||
|
|
|
|||
|
|
@ -261,6 +261,12 @@ void vulkan_format_props_query(struct wlr_vk_device *dev,
|
|||
}
|
||||
|
||||
// non-dmabuf texture properties
|
||||
if (fmtp.formatProperties.optimalTilingFeatures & render_features) {
|
||||
wlr_drm_format_set_add(&dev->shm_render_formats,
|
||||
format->drm_format, DRM_FORMAT_MOD_INVALID);
|
||||
add_fmt_props = true;
|
||||
}
|
||||
|
||||
if (fmtp.formatProperties.optimalTilingFeatures & tex_features) {
|
||||
fmti.pNext = NULL;
|
||||
ifmtp.pNext = NULL;
|
||||
|
|
|
|||
|
|
@ -426,26 +426,47 @@ static struct wlr_vk_render_buffer *create_render_buffer(
|
|||
buffer->wlr_buffer = wlr_buffer;
|
||||
buffer->renderer = renderer;
|
||||
|
||||
uint32_t format = DRM_FORMAT_INVALID;
|
||||
struct wlr_dmabuf_attributes dmabuf = {0};
|
||||
if (!wlr_buffer_get_dmabuf(wlr_buffer, &dmabuf)) {
|
||||
void *data_ptr;
|
||||
uint32_t data_ptr_format;
|
||||
size_t data_ptr_stride;
|
||||
if (wlr_buffer_get_dmabuf(wlr_buffer, &dmabuf)) {
|
||||
format = dmabuf.format;
|
||||
wlr_log(WLR_DEBUG, "vulkan create_render_buffer: DMA-BUF %.4s, %dx%d",
|
||||
(const char *) &format, dmabuf.width, dmabuf.height);
|
||||
|
||||
buffer->image = vulkan_import_dmabuf(renderer, &dmabuf,
|
||||
buffer->memories, &buffer->mem_count, true);
|
||||
} else if (wlr_buffer_begin_data_ptr_access(wlr_buffer,
|
||||
WLR_BUFFER_DATA_PTR_ACCESS_READ, &data_ptr, &data_ptr_format,
|
||||
&data_ptr_stride)) {
|
||||
format = data_ptr_format;
|
||||
wlr_log(WLR_DEBUG, "vulkan create_render_buffer: data ptr %.4s, %dx%d",
|
||||
(const char *) &format, wlr_buffer->width, wlr_buffer->height);
|
||||
|
||||
buffer->image = vulkan_import_host_memory(renderer, data_ptr,
|
||||
data_ptr_format, wlr_buffer->width, wlr_buffer->height,
|
||||
data_ptr_stride, &buffer->memories[0], true);
|
||||
if (buffer->image) {
|
||||
buffer->mem_count = 1;
|
||||
}
|
||||
|
||||
wlr_buffer_end_data_ptr_access(wlr_buffer);
|
||||
} else {
|
||||
wlr_log(WLR_ERROR, "Unsupported render buffer");
|
||||
goto error_buffer;
|
||||
}
|
||||
|
||||
wlr_log(WLR_DEBUG, "vulkan create_render_buffer: %.4s, %dx%d",
|
||||
(const char*) &dmabuf.format, dmabuf.width, dmabuf.height);
|
||||
|
||||
buffer->image = vulkan_import_dmabuf(renderer, &dmabuf,
|
||||
buffer->memories, &buffer->mem_count, true);
|
||||
if (!buffer->image) {
|
||||
goto error_buffer;
|
||||
}
|
||||
|
||||
VkDevice dev = renderer->dev->dev;
|
||||
const struct wlr_vk_format_props *fmt = vulkan_format_props_from_drm(
|
||||
renderer->dev, dmabuf.format);
|
||||
renderer->dev, format);
|
||||
if (fmt == NULL) {
|
||||
wlr_log(WLR_ERROR, "Unsupported pixel format %"PRIx32 " (%.4s)",
|
||||
dmabuf.format, (const char*) &dmabuf.format);
|
||||
format, (const char *) &format);
|
||||
goto error_buffer;
|
||||
}
|
||||
|
||||
|
|
@ -479,8 +500,8 @@ static struct wlr_vk_render_buffer *create_render_buffer(
|
|||
fb_info.attachmentCount = 1u;
|
||||
fb_info.pAttachments = &buffer->image_view;
|
||||
fb_info.flags = 0u;
|
||||
fb_info.width = dmabuf.width;
|
||||
fb_info.height = dmabuf.height;
|
||||
fb_info.width = wlr_buffer->width;
|
||||
fb_info.height = wlr_buffer->height;
|
||||
fb_info.layers = 1u;
|
||||
fb_info.renderPass = buffer->render_setup->render_pass;
|
||||
|
||||
|
|
@ -504,7 +525,6 @@ error_view:
|
|||
vkFreeMemory(dev, buffer->memories[i], NULL);
|
||||
}
|
||||
error_buffer:
|
||||
wlr_dmabuf_attributes_finish(&dmabuf);
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -893,7 +913,11 @@ static const struct wlr_drm_format_set *vulkan_get_dmabuf_texture_formats(
|
|||
static const struct wlr_drm_format_set *vulkan_get_render_formats(
|
||||
struct wlr_renderer *wlr_renderer) {
|
||||
struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer);
|
||||
return &renderer->dev->dmabuf_render_formats;
|
||||
if (renderer->dev->drm_fd >= 0) {
|
||||
return &renderer->dev->dmabuf_render_formats;
|
||||
} else {
|
||||
return &renderer->dev->shm_render_formats;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t vulkan_preferred_read_format(
|
||||
|
|
@ -973,7 +997,12 @@ static int vulkan_get_drm_fd(struct wlr_renderer *wlr_renderer) {
|
|||
}
|
||||
|
||||
static uint32_t vulkan_get_render_buffer_caps(struct wlr_renderer *wlr_renderer) {
|
||||
return WLR_BUFFER_CAP_DMABUF;
|
||||
struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer);
|
||||
if (renderer->dev->drm_fd >= 0) {
|
||||
return WLR_BUFFER_CAP_DMABUF;
|
||||
} else {
|
||||
return WLR_BUFFER_CAP_DATA_PTR;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct wlr_renderer_impl renderer_impl = {
|
||||
|
|
@ -1504,12 +1533,16 @@ struct wlr_renderer *wlr_vk_renderer_create_with_drm_fd(int drm_fd) {
|
|||
}
|
||||
|
||||
// We duplicate it so it's not closed while we still need it.
|
||||
dev->drm_fd = fcntl(drm_fd, F_DUPFD_CLOEXEC, 0);
|
||||
if (dev->drm_fd < 0) {
|
||||
wlr_log_errno(WLR_ERROR, "fcntl(F_DUPFD_CLOEXEC) failed");
|
||||
vulkan_device_destroy(dev);
|
||||
vulkan_instance_destroy(ini);
|
||||
return NULL;
|
||||
if (drm_fd >= 0) {
|
||||
dev->drm_fd = fcntl(drm_fd, F_DUPFD_CLOEXEC, 0);
|
||||
if (dev->drm_fd < 0) {
|
||||
wlr_log_errno(WLR_ERROR, "fcntl(F_DUPFD_CLOEXEC) failed");
|
||||
vulkan_device_destroy(dev);
|
||||
vulkan_instance_destroy(ini);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
dev->drm_fd = -1;
|
||||
}
|
||||
|
||||
return vulkan_renderer_create_for_device(dev);
|
||||
|
|
|
|||
|
|
@ -606,6 +606,133 @@ error_image:
|
|||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
VkImage vulkan_import_host_memory(struct wlr_vk_renderer *renderer,
|
||||
void *host_ptr, uint32_t format, uint32_t width, uint32_t height,
|
||||
uint32_t stride, VkDeviceMemory *mem, bool for_render) {
|
||||
VkResult res;
|
||||
VkDevice dev = renderer->dev->dev;
|
||||
|
||||
*mem = VK_NULL_HANDLE;
|
||||
|
||||
struct wlr_vk_format_props *fmt =
|
||||
vulkan_format_props_from_drm(renderer->dev, format);
|
||||
if (fmt == NULL) {
|
||||
wlr_log(WLR_ERROR, "Unsupported pixel format %"PRIx32 " (%.4s)",
|
||||
format, (const char*) &format);
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
VkExternalMemoryHandleTypeFlagBits htype =
|
||||
VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT;
|
||||
|
||||
VkImageCreateInfo img_info = {0};
|
||||
img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
img_info.imageType = VK_IMAGE_TYPE_2D;
|
||||
img_info.format = fmt->format.vk_format;
|
||||
img_info.mipLevels = 1;
|
||||
img_info.arrayLayers = 1;
|
||||
img_info.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
img_info.extent = (VkExtent3D) { width, height, 1 };
|
||||
img_info.usage = for_render ?
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT :
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
|
||||
VkExternalMemoryImageCreateInfo eimg = {0};
|
||||
eimg.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
|
||||
eimg.handleTypes = htype;
|
||||
img_info.pNext = &eimg;
|
||||
|
||||
VkImage image;
|
||||
res = vkCreateImage(dev, &img_info, NULL, &image);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkCreateImage", res);
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
VkMemoryHostPointerPropertiesEXT host_ptr_props = {0};
|
||||
host_ptr_props.sType = VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT;
|
||||
res = renderer->dev->api.getMemoryHostPointerPropertiesEXT(dev, htype,
|
||||
host_ptr, &host_ptr_props);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("getMemoryHostPointerPropertiesEXT", res);
|
||||
goto error_image;
|
||||
}
|
||||
|
||||
VkImageMemoryRequirementsInfo2 memri = {0};
|
||||
memri.image = image;
|
||||
memri.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2;
|
||||
|
||||
VkMemoryRequirements2 memr = {0};
|
||||
memr.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
|
||||
|
||||
vkGetImageMemoryRequirements2(dev, &memri, &memr);
|
||||
|
||||
int mem_index = vulkan_find_mem_type(renderer->dev, 0,
|
||||
memr.memoryRequirements.memoryTypeBits & host_ptr_props.memoryTypeBits);
|
||||
if (mem_index < 0) {
|
||||
wlr_log(WLR_ERROR, "no valid memory type index");
|
||||
goto error_image;
|
||||
}
|
||||
|
||||
if ((uintptr_t)host_ptr % memr.memoryRequirements.alignment != 0) {
|
||||
wlr_log(WLR_ERROR, "Invalid memory alignment "
|
||||
"(%p not aligned to %zu bytes)", host_ptr,
|
||||
(size_t)memr.memoryRequirements.alignment);
|
||||
goto error_image;
|
||||
}
|
||||
|
||||
if (height * stride < memr.memoryRequirements.size) {
|
||||
wlr_log(WLR_ERROR, "Invalid memory size (%zu bytes required, "
|
||||
"but has %zu bytes)", (size_t)memr.memoryRequirements.size,
|
||||
(size_t)height * stride);
|
||||
goto error_image;
|
||||
}
|
||||
|
||||
VkMemoryAllocateInfo memi = {0};
|
||||
memi.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
memi.allocationSize = memr.memoryRequirements.size;
|
||||
memi.memoryTypeIndex = mem_index;
|
||||
|
||||
VkImportMemoryHostPointerInfoEXT importi = {0};
|
||||
importi.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT;
|
||||
importi.handleType = htype;
|
||||
importi.pHostPointer = host_ptr;
|
||||
memi.pNext = &importi;
|
||||
|
||||
VkMemoryDedicatedAllocateInfo dedi = {0};
|
||||
dedi.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
|
||||
dedi.image = image;
|
||||
importi.pNext = &dedi;
|
||||
|
||||
res = vkAllocateMemory(dev, &memi, NULL, mem);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkAllocateMemory failed", res);
|
||||
goto error_image;
|
||||
}
|
||||
|
||||
VkBindImageMemoryInfo bindi = {0};
|
||||
bindi.image = image;
|
||||
bindi.memory = *mem;
|
||||
bindi.memoryOffset = 0;
|
||||
bindi.sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
|
||||
|
||||
res = vkBindImageMemory2(dev, 1, &bindi);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("vkBindMemory failed", res);
|
||||
goto error_image;
|
||||
}
|
||||
|
||||
return image;
|
||||
|
||||
error_image:
|
||||
vkFreeMemory(dev, *mem, NULL);
|
||||
vkDestroyImage(dev, image, NULL);
|
||||
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
static struct wlr_texture *vulkan_texture_from_dmabuf(struct wlr_renderer *wlr_renderer,
|
||||
struct wlr_dmabuf_attributes *attribs) {
|
||||
struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer);
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ VkPhysicalDevice vulkan_find_drm_phdev(struct wlr_vk_instance *ini, int drm_fd)
|
|||
}
|
||||
|
||||
struct stat drm_stat = {0};
|
||||
if (fstat(drm_fd, &drm_stat) != 0) {
|
||||
if (drm_fd >= 0 && fstat(drm_fd, &drm_stat) != 0) {
|
||||
wlr_log_errno(WLR_ERROR, "fstat failed");
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
|
@ -370,6 +370,15 @@ VkPhysicalDevice vulkan_find_drm_phdev(struct wlr_vk_instance *ini, int drm_fd)
|
|||
wlr_log(WLR_INFO, " Driver name: %s (%s)", driver_props.driverName, driver_props.driverInfo);
|
||||
}
|
||||
|
||||
if (drm_fd < 0) {
|
||||
if (phdev_props.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) {
|
||||
wlr_log(WLR_INFO, "Found matching Vulkan physical device: %s",
|
||||
phdev_props.deviceName);
|
||||
return phdev;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!has_drm_props) {
|
||||
wlr_log(WLR_DEBUG, " Ignoring physical device \"%s\": "
|
||||
"VK_EXT_physical_device_drm not supported",
|
||||
|
|
@ -449,9 +458,9 @@ struct wlr_vk_device *vulkan_device_create(struct wlr_vk_instance *ini,
|
|||
const char *names[] = {
|
||||
VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
|
||||
VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME, // or vulkan 1.2
|
||||
VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME,
|
||||
VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME,
|
||||
VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME,
|
||||
//VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME,
|
||||
//VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME,
|
||||
//VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME,
|
||||
};
|
||||
|
||||
unsigned nc = sizeof(names) / sizeof(names[0]);
|
||||
|
|
@ -466,6 +475,11 @@ struct wlr_vk_device *vulkan_device_create(struct wlr_vk_instance *ini,
|
|||
dev->extensions[dev->extension_count++] = names[i];
|
||||
}
|
||||
|
||||
const char *name = "VK_EXT_external_memory_host";
|
||||
if (find_extensions(avail_ext_props, avail_extc, &name, 1) == NULL) {
|
||||
dev->extensions[dev->extension_count++] = name;
|
||||
}
|
||||
|
||||
// queue families
|
||||
{
|
||||
uint32_t qfam_count;
|
||||
|
|
@ -514,12 +528,15 @@ struct wlr_vk_device *vulkan_device_create(struct wlr_vk_instance *ini,
|
|||
// load api
|
||||
dev->api.getMemoryFdPropertiesKHR = (PFN_vkGetMemoryFdPropertiesKHR)
|
||||
vkGetDeviceProcAddr(dev->dev, "vkGetMemoryFdPropertiesKHR");
|
||||
|
||||
if (!dev->api.getMemoryFdPropertiesKHR) {
|
||||
wlr_log(WLR_ERROR, "Failed to retrieve required dev function pointers");
|
||||
goto error;
|
||||
}
|
||||
|
||||
dev->api.getMemoryHostPointerPropertiesEXT =
|
||||
(PFN_vkGetMemoryHostPointerPropertiesEXT)
|
||||
vkGetDeviceProcAddr(dev->dev, "vkGetMemoryHostPointerPropertiesEXT");
|
||||
|
||||
// - check device format support -
|
||||
size_t max_fmts;
|
||||
const struct wlr_vk_format *fmts = vulkan_get_format_list(&max_fmts);
|
||||
|
|
@ -556,6 +573,7 @@ void vulkan_device_destroy(struct wlr_vk_device *dev) {
|
|||
|
||||
wlr_drm_format_set_finish(&dev->dmabuf_render_formats);
|
||||
wlr_drm_format_set_finish(&dev->dmabuf_texture_formats);
|
||||
wlr_drm_format_set_finish(&dev->shm_render_formats);
|
||||
|
||||
for (unsigned i = 0u; i < dev->format_prop_count; ++i) {
|
||||
vulkan_format_props_finish(&dev->format_props[i]);
|
||||
|
|
|
|||
|
|
@ -284,7 +284,7 @@ struct wlr_renderer *renderer_autocreate_with_drm_fd(int drm_fd) {
|
|||
#endif
|
||||
#if WLR_HAS_VULKAN_RENDERER
|
||||
if (strcmp(name, "vulkan") == 0) {
|
||||
return wlr_vk_renderer_create_with_drm_fd(drm_fd);
|
||||
return wlr_vk_renderer_create_with_drm_fd(-1);
|
||||
}
|
||||
#endif
|
||||
if (strcmp(name, "pixman") == 0) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue