mirror of
https://gitlab.freedesktop.org/wayland/weston.git
synced 2025-12-20 04:40:07 +01:00
libweston: Vulkan renderer
A Vulkan renderer for weston, based on the GL renderer. The goal is to impose the least requirements as possible on Vulkan implementations, as to allow even Vulkan 1.0 (or early development) drivers to run a Wayland compositor. Any additional features or extensions are made optional if possible. Currently supports drm, wayland, x11 and headless backends. As of this implementation, this is still considered an experimental renderer. Signed-off-by: Erico Nunes <nunes.erico@gmail.com>
This commit is contained in:
parent
60f7b59d8f
commit
8f56d03d4b
32 changed files with 6029 additions and 17 deletions
|
|
@ -35,12 +35,15 @@ stitching them together is performed by a *renderer*. By doing so, it is
|
|||
compositing all surfaces into a single image, which is being handed out to a
|
||||
back-end, and finally, displayed on the screen.
|
||||
|
||||
libweston provides two useful renderers. One uses
|
||||
`OpenGL ES <https://www.khronos.org/opengles/>`_, which will often be accelerated
|
||||
by your GPU when suitable drivers are installed. The other uses the
|
||||
`Pixman <http://www.pixman.org>`_ library which is entirely CPU (software)
|
||||
rendered. You can select between these with the ``--renderer=gl`` and
|
||||
``--renderer=pixman`` arguments when starting Weston.
|
||||
libweston provides multiple useful renderers. There are
|
||||
`OpenGL ES <https://www.khronos.org/opengles/>`_ and
|
||||
`Vulkan <https://www.vulkan.org/>`_ renderers, which will often be accelerated
|
||||
by your GPU when suitable drivers are installed.
|
||||
Another uses the `Pixman <http://www.pixman.org>`_ library which is entirely
|
||||
CPU (software) rendered.
|
||||
|
||||
You can select between these with the ``--renderer=gl``, ``--renderer=vulkan``
|
||||
and ``--renderer=pixman`` arguments when starting Weston.
|
||||
|
||||
Multi-back-end support
|
||||
----------------------
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ struct {
|
|||
} renderer_name_map[] = {
|
||||
{ "auto", WESTON_RENDERER_AUTO },
|
||||
{ "gl", WESTON_RENDERER_GL },
|
||||
{ "vulkan", WESTON_RENDERER_VULKAN },
|
||||
{ "noop", WESTON_RENDERER_NOOP },
|
||||
{ "pixman", WESTON_RENDERER_PIXMAN },
|
||||
};
|
||||
|
|
|
|||
|
|
@ -710,6 +710,9 @@ usage(int error_code)
|
|||
"\t\t\t\tauto\tAutomatic selection of one of the below renderers\n"
|
||||
#if defined(ENABLE_EGL)
|
||||
"\t\t\t\tgl\tOpenGL ES\n"
|
||||
#endif
|
||||
#if defined(ENABLE_VULKAN)
|
||||
"\t\t\t\tvulkan\tVulkan\n"
|
||||
#endif
|
||||
"\t\t\t\tnoop\tNo-op renderer for testing only\n"
|
||||
"\t\t\t\tpixman\tPixman software renderer\n"
|
||||
|
|
@ -755,6 +758,7 @@ usage(int error_code)
|
|||
"\tflipped-rotate-270\n"
|
||||
" --use-pixman\t\tUse the pixman (CPU) renderer (deprecated alias for --renderer=pixman)\n"
|
||||
" --use-gl\t\tUse the GL renderer (deprecated alias for --renderer=gl)\n"
|
||||
" --use-vulkan\t\tUse the Vulkan renderer (deprecated alias for --renderer=vulkan)\n"
|
||||
" --no-outputs\t\tDo not create any virtual outputs\n"
|
||||
" --refresh-rate=RATE\tThe output refresh rate (in mHz)\n"
|
||||
"\n");
|
||||
|
|
@ -3532,6 +3536,7 @@ load_headless_backend(struct weston_compositor *c,
|
|||
struct wet_backend *wb;
|
||||
bool force_pixman;
|
||||
bool force_gl;
|
||||
bool force_vulkan;
|
||||
bool no_outputs = false;
|
||||
char *transform = NULL;
|
||||
|
||||
|
|
@ -3544,6 +3549,8 @@ load_headless_backend(struct weston_compositor *c,
|
|||
false);
|
||||
weston_config_section_get_bool(section, "use-gl", &force_gl,
|
||||
false);
|
||||
weston_config_section_get_bool(section, "use-vulkan", &force_vulkan,
|
||||
false);
|
||||
weston_config_section_get_bool(section, "output-decorations", &config.decorate,
|
||||
false);
|
||||
|
||||
|
|
@ -3553,6 +3560,7 @@ load_headless_backend(struct weston_compositor *c,
|
|||
{ WESTON_OPTION_INTEGER, "scale", 0, &parsed_options->scale },
|
||||
{ WESTON_OPTION_BOOLEAN, "use-pixman", 0, &force_pixman },
|
||||
{ WESTON_OPTION_BOOLEAN, "use-gl", 0, &force_gl },
|
||||
{ WESTON_OPTION_BOOLEAN, "use-vulkan", 0, &force_vulkan },
|
||||
{ WESTON_OPTION_STRING, "transform", 0, &transform },
|
||||
{ WESTON_OPTION_BOOLEAN, "no-outputs", 0, &no_outputs },
|
||||
{ WESTON_OPTION_INTEGER, "refresh-rate", 0, &config.refresh },
|
||||
|
|
@ -3562,13 +3570,17 @@ load_headless_backend(struct weston_compositor *c,
|
|||
parse_options(options, ARRAY_LENGTH(options), argc, argv);
|
||||
|
||||
if ((force_pixman && force_gl) ||
|
||||
(renderer != WESTON_RENDERER_AUTO && (force_pixman || force_gl))) {
|
||||
(force_pixman && force_vulkan) ||
|
||||
(force_gl && force_vulkan) ||
|
||||
(renderer != WESTON_RENDERER_AUTO && (force_pixman || force_gl || force_vulkan))) {
|
||||
weston_log("Conflicting renderer specifications\n");
|
||||
return -1;
|
||||
} else if (force_pixman) {
|
||||
config.renderer = WESTON_RENDERER_PIXMAN;
|
||||
} else if (force_gl) {
|
||||
config.renderer = WESTON_RENDERER_GL;
|
||||
} else if (force_vulkan) {
|
||||
config.renderer = WESTON_RENDERER_VULKAN;
|
||||
} else {
|
||||
config.renderer = renderer;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ enum weston_hdcp_protection {
|
|||
* \ingroup testharness
|
||||
*/
|
||||
struct weston_testsuite_quirks {
|
||||
/** Force GL-renderer to do a full upload of wl_shm buffers. */
|
||||
/** Force GL/Vulkan-renderer to do a full upload of wl_shm buffers. */
|
||||
bool force_full_upload;
|
||||
/** Ensure GL shadow fb is used, and always repaint it fully. */
|
||||
bool gl_force_full_redraw_of_shadow_fb;
|
||||
|
|
@ -2278,6 +2278,7 @@ enum weston_renderer_type {
|
|||
WESTON_RENDERER_NOOP = 1,
|
||||
WESTON_RENDERER_PIXMAN = 2,
|
||||
WESTON_RENDERER_GL = 3,
|
||||
WESTON_RENDERER_VULKAN = 4,
|
||||
};
|
||||
|
||||
struct weston_backend *
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#include "pixel-formats.h"
|
||||
#include "renderer-gl/gl-renderer.h"
|
||||
#include "shared/weston-egl-ext.h"
|
||||
#include "renderer-vulkan/vulkan-renderer.h"
|
||||
#include "linux-dmabuf.h"
|
||||
#include "linux-explicit-synchronization.h"
|
||||
|
||||
|
|
@ -82,6 +83,27 @@ drm_backend_create_gl_renderer(struct drm_backend *b)
|
|||
&options.base);
|
||||
}
|
||||
|
||||
static int
|
||||
drm_backend_create_vulkan_renderer(struct drm_backend *b)
|
||||
{
|
||||
const struct pixel_format_info *format[3] = {
|
||||
b->format,
|
||||
fallback_format_for(b->format),
|
||||
};
|
||||
struct vulkan_renderer_display_options options = {
|
||||
.gbm_device = b->gbm,
|
||||
.formats = format,
|
||||
.formats_count = 1,
|
||||
};
|
||||
|
||||
if (format[1])
|
||||
options.formats_count = 2;
|
||||
|
||||
return weston_compositor_init_renderer(b->compositor,
|
||||
WESTON_RENDERER_VULKAN,
|
||||
&options.base);
|
||||
}
|
||||
|
||||
int
|
||||
init_egl(struct drm_backend *b)
|
||||
{
|
||||
|
|
@ -100,6 +122,24 @@ init_egl(struct drm_backend *b)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
init_vulkan(struct drm_backend *b)
|
||||
{
|
||||
struct drm_device *device = b->drm;
|
||||
|
||||
b->gbm = gbm_create_device(device->drm.fd);
|
||||
if (!b->gbm)
|
||||
return -1;
|
||||
|
||||
if (drm_backend_create_vulkan_renderer(b) < 0) {
|
||||
gbm_device_destroy(b->gbm);
|
||||
b->gbm = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void drm_output_fini_cursor_egl(struct drm_output *output)
|
||||
{
|
||||
unsigned int i;
|
||||
|
|
@ -113,6 +153,19 @@ static void drm_output_fini_cursor_egl(struct drm_output *output)
|
|||
}
|
||||
}
|
||||
|
||||
static void drm_output_fini_cursor_vulkan(struct drm_output *output)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
|
||||
/* This cursor does not have a GBM device */
|
||||
if (output->gbm_cursor_fb[i] && !output->gbm_cursor_fb[i]->bo)
|
||||
output->gbm_cursor_fb[i]->type = BUFFER_PIXMAN_DUMB;
|
||||
drm_fb_unref(output->gbm_cursor_fb[i]);
|
||||
output->gbm_cursor_fb[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
drm_output_init_cursor_egl(struct drm_output *output, struct drm_backend *b)
|
||||
{
|
||||
|
|
@ -162,6 +215,55 @@ err:
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
drm_output_init_cursor_vulkan(struct drm_output *output, struct drm_backend *b)
|
||||
{
|
||||
struct drm_device *device = output->device;
|
||||
unsigned int i;
|
||||
|
||||
/* No point creating cursors if we don't have a plane for them. */
|
||||
if (!output->cursor_plane)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
|
||||
struct gbm_bo *bo;
|
||||
|
||||
if (gbm_device_get_fd(b->gbm) != output->device->drm.fd) {
|
||||
output->gbm_cursor_fb[i] =
|
||||
drm_fb_create_dumb(output->device,
|
||||
device->cursor_width,
|
||||
device->cursor_height,
|
||||
DRM_FORMAT_ARGB8888);
|
||||
/* Override buffer type, since we know it is a cursor */
|
||||
output->gbm_cursor_fb[i]->type = BUFFER_CURSOR;
|
||||
output->gbm_cursor_handle[i] =
|
||||
output->gbm_cursor_fb[i]->handles[0];
|
||||
} else {
|
||||
bo = gbm_bo_create(b->gbm, device->cursor_width, device->cursor_height,
|
||||
GBM_FORMAT_ARGB8888,
|
||||
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
|
||||
if (!bo)
|
||||
goto err;
|
||||
|
||||
output->gbm_cursor_fb[i] =
|
||||
drm_fb_get_from_bo(bo, device, false, BUFFER_CURSOR);
|
||||
if (!output->gbm_cursor_fb[i]) {
|
||||
gbm_bo_destroy(bo);
|
||||
goto err;
|
||||
}
|
||||
output->gbm_cursor_handle[i] = gbm_bo_get_handle(bo).s32;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
weston_log("cursor buffers unavailable, using vulkan cursors\n");
|
||||
device->cursors_are_broken = true;
|
||||
drm_output_fini_cursor_vulkan(output);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
create_gbm_surface(struct gbm_device *gbm, struct drm_output *output)
|
||||
{
|
||||
|
|
@ -256,6 +358,123 @@ drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
create_gbm_bos(struct gbm_device *gbm, struct drm_output *output, unsigned int n)
|
||||
{
|
||||
struct weston_mode *mode = output->base.current_mode;
|
||||
struct drm_plane *plane = output->scanout_plane;
|
||||
struct weston_drm_format *fmt;
|
||||
const uint64_t *modifiers;
|
||||
unsigned int num_modifiers;
|
||||
|
||||
fmt = weston_drm_format_array_find_format(&plane->formats,
|
||||
output->format->format);
|
||||
if (!fmt) {
|
||||
weston_log("format %s not supported by output %s\n",
|
||||
output->format->drm_format_name,
|
||||
output->base.name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!weston_drm_format_has_modifier(fmt, DRM_FORMAT_MOD_INVALID)) {
|
||||
modifiers = weston_drm_format_get_modifiers(fmt, &num_modifiers);
|
||||
for (unsigned int i = 0; i < n; i++) {
|
||||
output->gbm_bos[i] =
|
||||
gbm_bo_create_with_modifiers(gbm,
|
||||
mode->width, mode->height,
|
||||
output->format->format,
|
||||
modifiers, num_modifiers);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we cannot use modifiers to allocate the GBM surface and
|
||||
* the GBM device differs from the KMS display device, try to
|
||||
* use linear buffers and hope that the allocated GBM surface
|
||||
* is correctly displayed on the KMS device.
|
||||
*/
|
||||
if (gbm_device_get_fd(gbm) != output->device->drm.fd)
|
||||
output->gbm_bo_flags |= GBM_BO_USE_LINEAR;
|
||||
|
||||
if (!output->gbm_bos[0]) {
|
||||
for (unsigned int i = 0; i < n; i++) {
|
||||
output->gbm_bos[i] = gbm_bo_create(gbm,
|
||||
mode->width, mode->height,
|
||||
output->format->format,
|
||||
output->gbm_bo_flags);
|
||||
}
|
||||
}
|
||||
|
||||
struct drm_device *device = output->device;
|
||||
for (unsigned int i = 0; i < n; i++) {
|
||||
assert(output->gbm_bos[i]);
|
||||
drm_fb_get_from_bo(output->gbm_bos[i], device, !output->format->opaque_substitute,
|
||||
BUFFER_GBM_BO);
|
||||
}
|
||||
|
||||
assert(output->gbm_surface == NULL);
|
||||
}
|
||||
|
||||
/* Init output state that depends on vulkan or gbm */
|
||||
int
|
||||
drm_output_init_vulkan(struct drm_output *output, struct drm_backend *b)
|
||||
{
|
||||
const struct weston_renderer *renderer = b->compositor->renderer;
|
||||
const struct weston_mode *mode = output->base.current_mode;
|
||||
const struct pixel_format_info *format[2] = {
|
||||
output->format,
|
||||
fallback_format_for(output->format),
|
||||
};
|
||||
struct vulkan_renderer_output_options options = {
|
||||
.formats = format,
|
||||
.formats_count = 1,
|
||||
.area.x = 0,
|
||||
.area.y = 0,
|
||||
.area.width = mode->width,
|
||||
.area.height = mode->height,
|
||||
.fb_size.width = mode->width,
|
||||
.fb_size.height = mode->height,
|
||||
};
|
||||
|
||||
assert(output->gbm_surface == NULL);
|
||||
|
||||
/*
|
||||
* TODO: This method for BO allocation needs to be reworked.
|
||||
* Currently, it allocates a buffer based on the list of acceptable
|
||||
* modifiers received from the DRM backend but does not check it
|
||||
* against formats renderable by the renderer (and there is no
|
||||
* straightforward way to do so yet).
|
||||
* Most likely this should be replaced by sending the acceptable
|
||||
* modifiers list from the DRM backend to the renderer and doing the
|
||||
* optimal dmabuf allocation in the renderer. But as of this writing,
|
||||
* this API for dmabuf allocation is not yet implemented in the
|
||||
* Vulkan renderer.
|
||||
*/
|
||||
create_gbm_bos(b->gbm, output, NUM_GBM_BOS);
|
||||
if (!output->gbm_bos[0]) {
|
||||
weston_log("failed to create gbm bos\n");
|
||||
return -1;
|
||||
}
|
||||
options.num_gbm_bos = NUM_GBM_BOS;
|
||||
|
||||
if (options.formats[1])
|
||||
options.formats_count = 2;
|
||||
|
||||
for (unsigned int i = 0; i < options.num_gbm_bos; i++)
|
||||
options.gbm_bos[i] = output->gbm_bos[i];
|
||||
|
||||
if (renderer->vulkan->output_window_create(&output->base, &options) < 0) {
|
||||
weston_log("failed to create vulkan renderer output state\n");
|
||||
gbm_surface_destroy(output->gbm_surface);
|
||||
output->gbm_surface = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
drm_output_init_cursor_vulkan(output, b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
drm_output_fini_egl(struct drm_output *output)
|
||||
{
|
||||
|
|
@ -276,6 +495,27 @@ drm_output_fini_egl(struct drm_output *output)
|
|||
drm_output_fini_cursor_egl(output);
|
||||
}
|
||||
|
||||
void
|
||||
drm_output_fini_vulkan(struct drm_output *output)
|
||||
{
|
||||
struct drm_backend *b = output->backend;
|
||||
const struct weston_renderer *renderer = b->compositor->renderer;
|
||||
|
||||
/* Destroying the GBM surface will destroy all our GBM buffers,
|
||||
* regardless of refcount. Ensure we destroy them here. */
|
||||
if (!b->compositor->shutting_down &&
|
||||
output->scanout_plane->state_cur->fb &&
|
||||
output->scanout_plane->state_cur->fb->type == BUFFER_GBM_BO) {
|
||||
drm_plane_reset_state(output->scanout_plane);
|
||||
}
|
||||
|
||||
renderer->vulkan->output_destroy(&output->base);
|
||||
for (unsigned int i = 0; i < NUM_GBM_BOS; i++)
|
||||
gbm_bo_destroy(output->gbm_bos[i]);
|
||||
output->gbm_surface = NULL;
|
||||
drm_output_fini_cursor_vulkan(output);
|
||||
}
|
||||
|
||||
struct drm_fb *
|
||||
drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
|
||||
{
|
||||
|
|
@ -307,3 +547,36 @@ drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct drm_fb *
|
||||
drm_output_render_vulkan(struct drm_output_state *state, pixman_region32_t *damage)
|
||||
{
|
||||
struct drm_output *output = state->output;
|
||||
struct drm_device *device = output->device;
|
||||
struct gbm_bo *bo;
|
||||
struct drm_fb *ret;
|
||||
|
||||
output->base.compositor->renderer->repaint_output(&output->base,
|
||||
damage, NULL);
|
||||
|
||||
bo = output->gbm_bos[output->current_bo];
|
||||
if (!bo) {
|
||||
weston_log("failed to get gbm_bo\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Output transparent/opaque image according to the format required by
|
||||
* the client. */
|
||||
ret = drm_fb_get_from_bo(bo, device, !output->format->opaque_substitute,
|
||||
BUFFER_GBM_BO);
|
||||
if (!ret) {
|
||||
weston_log("failed to get drm_fb for bo\n");
|
||||
return NULL;
|
||||
}
|
||||
ret->bo = bo;
|
||||
|
||||
ret->gbm_surface = NULL;
|
||||
output->current_bo = (output->current_bo + 1) % NUM_GBM_BOS;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -293,6 +293,7 @@ enum drm_fb_type {
|
|||
BUFFER_PIXMAN_DUMB, /**< internal Pixman rendering */
|
||||
BUFFER_GBM_SURFACE, /**< internal EGL rendering */
|
||||
BUFFER_CURSOR, /**< internal cursor buffer */
|
||||
BUFFER_GBM_BO, /**< internal Vulkan rendering */
|
||||
};
|
||||
|
||||
struct drm_fb {
|
||||
|
|
@ -574,6 +575,8 @@ struct drm_output {
|
|||
int current_cursor;
|
||||
|
||||
struct gbm_surface *gbm_surface;
|
||||
struct gbm_bo *gbm_bos[2];
|
||||
int current_bo;
|
||||
const struct pixel_format_info *format;
|
||||
uint32_t gbm_bo_flags;
|
||||
|
||||
|
|
@ -946,6 +949,18 @@ drm_output_fini_egl(struct drm_output *output);
|
|||
struct drm_fb *
|
||||
drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage);
|
||||
|
||||
int
|
||||
init_vulkan(struct drm_backend *b);
|
||||
|
||||
int
|
||||
drm_output_init_vulkan(struct drm_output *output, struct drm_backend *b);
|
||||
|
||||
void
|
||||
drm_output_fini_vulkan(struct drm_output *output);
|
||||
|
||||
struct drm_fb *
|
||||
drm_output_render_vulkan(struct drm_output_state *state, pixman_region32_t *damage);
|
||||
|
||||
#else
|
||||
inline static int
|
||||
init_egl(struct drm_backend *b)
|
||||
|
|
@ -970,4 +985,29 @@ drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
|
|||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline static int
|
||||
init_vulkan(struct drm_backend *b)
|
||||
{
|
||||
weston_log("Compiled without GBM support\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
inline static int
|
||||
drm_output_init_vulkan(struct drm_output *output, struct drm_backend *b)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
inline static void
|
||||
drm_output_fini_vulkan(struct drm_output *output)
|
||||
{
|
||||
}
|
||||
|
||||
inline static struct drm_fb *
|
||||
drm_output_render_vulkan(struct drm_output_state *state, pixman_region32_t *damage)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -520,13 +520,16 @@ drm_output_render(struct drm_output_state *state)
|
|||
!weston_output_has_renderer_capture_tasks(&output->base) &&
|
||||
scanout_plane->state_cur->fb &&
|
||||
(scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE ||
|
||||
scanout_plane->state_cur->fb->type == BUFFER_GBM_BO ||
|
||||
scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB)) {
|
||||
fb = drm_fb_ref(scanout_plane->state_cur->fb);
|
||||
} else if (c->renderer->type == WESTON_RENDERER_PIXMAN) {
|
||||
fb = drm_output_render_pixman(state, &damage);
|
||||
} else {
|
||||
} else if (c->renderer->type == WESTON_RENDERER_GL) {
|
||||
fb = drm_output_render_gl(state, &damage);
|
||||
}
|
||||
} else if (c->renderer->type == WESTON_RENDERER_VULKAN) {
|
||||
fb = drm_output_render_vulkan(state, &damage);
|
||||
} else assert(0);
|
||||
|
||||
if (!fb) {
|
||||
drm_plane_state_put_back(scanout_state);
|
||||
|
|
@ -1195,6 +1198,13 @@ drm_output_apply_mode(struct drm_output *output)
|
|||
"new mode");
|
||||
return -1;
|
||||
}
|
||||
} else if (b->compositor->renderer->type == WESTON_RENDERER_VULKAN) {
|
||||
drm_output_fini_vulkan(output);
|
||||
if (drm_output_init_vulkan(output, b) < 0) {
|
||||
weston_log("failed to init output vulkan state with "
|
||||
"new mode");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (device->atomic_modeset)
|
||||
|
|
@ -2482,6 +2492,11 @@ drm_output_enable(struct weston_output *base)
|
|||
weston_log("Failed to init output pixman state\n");
|
||||
goto err_planes;
|
||||
}
|
||||
} else if (b->compositor->renderer->type == WESTON_RENDERER_VULKAN) {
|
||||
if (drm_output_init_vulkan(output, b) < 0) {
|
||||
weston_log("Failed to init output vulkan state\n");
|
||||
goto err_planes;
|
||||
}
|
||||
} else if (drm_output_init_egl(output, b) < 0) {
|
||||
weston_log("Failed to init output gl state\n");
|
||||
goto err_planes;
|
||||
|
|
@ -2532,6 +2547,8 @@ drm_output_deinit(struct weston_output *base)
|
|||
|
||||
if (b->compositor->renderer->type == WESTON_RENDERER_PIXMAN)
|
||||
drm_output_fini_pixman(output);
|
||||
else if (b->compositor->renderer->type == WESTON_RENDERER_VULKAN)
|
||||
drm_output_fini_vulkan(output);
|
||||
else
|
||||
drm_output_fini_egl(output);
|
||||
|
||||
|
|
@ -4218,9 +4235,14 @@ drm_backend_create(struct weston_compositor *compositor,
|
|||
if (config->additional_devices)
|
||||
open_additional_devices(b, config->additional_devices);
|
||||
|
||||
/* GL renderer is the default whenever it is enabled.
|
||||
* Only on a build without GL but with Vulkan, Vulkan is picked
|
||||
* as the default. Otherwise, pick pixman as the default */
|
||||
if (config->renderer == WESTON_RENDERER_AUTO) {
|
||||
#ifdef BUILD_DRM_GBM
|
||||
#if defined(ENABLE_EGL)
|
||||
config->renderer = WESTON_RENDERER_GL;
|
||||
#elif defined(ENABLE_VULKAN)
|
||||
config->renderer = WESTON_RENDERER_VULKAN;
|
||||
#else
|
||||
config->renderer = WESTON_RENDERER_PIXMAN;
|
||||
#endif
|
||||
|
|
@ -4239,6 +4261,12 @@ drm_backend_create(struct weston_compositor *compositor,
|
|||
goto err_udev_dev;
|
||||
}
|
||||
break;
|
||||
case WESTON_RENDERER_VULKAN:
|
||||
if (init_vulkan(b) < 0) {
|
||||
weston_log("failed to initialize vulkan\n");
|
||||
goto err_udev_dev;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
weston_log("unsupported renderer for DRM backend\n");
|
||||
goto err_udev_dev;
|
||||
|
|
|
|||
|
|
@ -366,7 +366,7 @@ drm_fb_destroy_gbm(struct gbm_bo *bo, void *data)
|
|||
struct drm_fb *fb = data;
|
||||
|
||||
assert(fb->type == BUFFER_GBM_SURFACE || fb->type == BUFFER_CLIENT ||
|
||||
fb->type == BUFFER_CURSOR);
|
||||
fb->type == BUFFER_CURSOR || fb->type == BUFFER_GBM_BO);
|
||||
drm_fb_destroy(fb);
|
||||
}
|
||||
|
||||
|
|
@ -622,6 +622,7 @@ drm_fb_unref(struct drm_fb *fb)
|
|||
#ifdef BUILD_DRM_GBM
|
||||
case BUFFER_CURSOR:
|
||||
case BUFFER_CLIENT:
|
||||
case BUFFER_GBM_BO:
|
||||
gbm_bo_destroy(fb->bo);
|
||||
break;
|
||||
case BUFFER_GBM_SURFACE:
|
||||
|
|
|
|||
|
|
@ -1791,6 +1791,9 @@ drm_pending_state_apply(struct drm_pending_state *pending_state)
|
|||
if (b->compositor->renderer->type == WESTON_RENDERER_GL) {
|
||||
drm_output_fini_egl(output);
|
||||
drm_output_init_egl(output, b);
|
||||
} else if (b->compositor->renderer->type == WESTON_RENDERER_VULKAN) {
|
||||
drm_output_fini_vulkan(output);
|
||||
drm_output_init_vulkan(output, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ srcs_drm = [
|
|||
|
||||
deps_drm = [
|
||||
dep_egl, # optional
|
||||
dep_vulkan, # optional
|
||||
dep_libm,
|
||||
dep_libdl,
|
||||
dep_libshared,
|
||||
|
|
@ -55,6 +56,15 @@ if get_option('renderer-gl')
|
|||
config_h.set('BUILD_DRM_GBM', '1')
|
||||
endif
|
||||
|
||||
if get_option('renderer-vulkan')
|
||||
if not dep_gbm.found()
|
||||
error('drm-backend with Vulkan renderer requires gbm which was not found. Or, you can use \'-Drenderer-vulkan=false\'.')
|
||||
endif
|
||||
deps_drm += dep_gbm
|
||||
srcs_drm += 'drm-gbm.c'
|
||||
config_h.set('BUILD_DRM_GBM', '1')
|
||||
endif
|
||||
|
||||
if get_option('backend-drm-screencast-vaapi')
|
||||
foreach name : [ 'libva', 'libva-drm' ]
|
||||
d = dependency(name, version: '>= 0.34.0', required: false)
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
#include "pixel-formats.h"
|
||||
#include "pixman-renderer.h"
|
||||
#include "renderer-gl/gl-renderer.h"
|
||||
#include "renderer-vulkan/vulkan-renderer.h"
|
||||
#include "renderer-borders.h"
|
||||
#include "shared/weston-drm-fourcc.h"
|
||||
#include "shared/weston-egl-ext.h"
|
||||
|
|
@ -198,6 +199,24 @@ headless_output_disable_gl(struct headless_output *output)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
headless_output_disable_vulkan(struct headless_output *output)
|
||||
{
|
||||
struct weston_compositor *compositor = output->base.compositor;
|
||||
const struct weston_renderer *renderer = compositor->renderer;
|
||||
|
||||
weston_renderer_borders_fini(&output->borders, &output->base);
|
||||
|
||||
renderer->destroy_renderbuffer(output->renderbuffer);
|
||||
output->renderbuffer = NULL;
|
||||
renderer->vulkan->output_destroy(&output->base);
|
||||
|
||||
if (output->frame) {
|
||||
frame_destroy(output->frame);
|
||||
output->frame = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
headless_output_disable_pixman(struct headless_output *output)
|
||||
{
|
||||
|
|
@ -227,6 +246,9 @@ headless_output_disable(struct weston_output *base)
|
|||
case WESTON_RENDERER_GL:
|
||||
headless_output_disable_gl(output);
|
||||
break;
|
||||
case WESTON_RENDERER_VULKAN:
|
||||
headless_output_disable_vulkan(output);
|
||||
break;
|
||||
case WESTON_RENDERER_PIXMAN:
|
||||
headless_output_disable_pixman(output);
|
||||
break;
|
||||
|
|
@ -310,6 +332,63 @@ err_renderbuffer:
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
headless_output_enable_vulkan(struct headless_output *output)
|
||||
{
|
||||
struct headless_backend *b = output->backend;
|
||||
const struct weston_renderer *renderer = b->compositor->renderer;
|
||||
const struct weston_mode *mode = output->base.current_mode;
|
||||
struct vulkan_renderer_fbo_options options = { 0 };
|
||||
|
||||
if (b->decorate) {
|
||||
/*
|
||||
* Start with a dummy exterior size and then resize, because
|
||||
* there is no frame_create() with interior size.
|
||||
*/
|
||||
output->frame = frame_create(b->theme, 100, 100,
|
||||
FRAME_BUTTON_CLOSE, NULL, NULL);
|
||||
if (!output->frame) {
|
||||
weston_log("failed to create frame for output\n");
|
||||
return -1;
|
||||
}
|
||||
frame_resize_inside(output->frame, mode->width, mode->height);
|
||||
|
||||
options.fb_size.width = frame_width(output->frame);
|
||||
options.fb_size.height = frame_height(output->frame);
|
||||
frame_interior(output->frame, &options.area.x, &options.area.y,
|
||||
&options.area.width, &options.area.height);
|
||||
} else {
|
||||
options.area.x = 0;
|
||||
options.area.y = 0;
|
||||
options.area.width = mode->width;
|
||||
options.area.height = mode->height;
|
||||
options.fb_size.width = mode->width;
|
||||
options.fb_size.height = mode->height;
|
||||
}
|
||||
|
||||
if (renderer->vulkan->output_fbo_create(&output->base, &options) < 0) {
|
||||
weston_log("failed to create vulkan renderer output state\n");
|
||||
if (output->frame) {
|
||||
frame_destroy(output->frame);
|
||||
output->frame = NULL;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
output->renderbuffer =
|
||||
renderer->create_renderbuffer(&output->base, b->formats[0],
|
||||
NULL, 0, NULL, NULL);
|
||||
if (!output->renderbuffer)
|
||||
goto err_renderbuffer;
|
||||
|
||||
return 0;
|
||||
|
||||
err_renderbuffer:
|
||||
renderer->vulkan->output_destroy(&output->base);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
headless_output_enable_pixman(struct headless_output *output)
|
||||
{
|
||||
|
|
@ -365,6 +444,9 @@ headless_output_enable(struct weston_output *base)
|
|||
case WESTON_RENDERER_GL:
|
||||
ret = headless_output_enable_gl(output);
|
||||
break;
|
||||
case WESTON_RENDERER_VULKAN:
|
||||
ret = headless_output_enable_vulkan(output);
|
||||
break;
|
||||
case WESTON_RENDERER_PIXMAN:
|
||||
ret = headless_output_enable_pixman(output);
|
||||
break;
|
||||
|
|
@ -592,6 +674,16 @@ headless_backend_create(struct weston_compositor *compositor,
|
|||
&options.base);
|
||||
break;
|
||||
}
|
||||
case WESTON_RENDERER_VULKAN: {
|
||||
const struct vulkan_renderer_display_options options = {
|
||||
.formats = b->formats,
|
||||
.formats_count = b->formats_count,
|
||||
};
|
||||
ret = weston_compositor_init_renderer(compositor,
|
||||
WESTON_RENDERER_VULKAN,
|
||||
&options.base);
|
||||
break;
|
||||
}
|
||||
case WESTON_RENDERER_PIXMAN:
|
||||
if (config->decorate) {
|
||||
weston_log("Error: Pixman renderer does not support decorations.\n");
|
||||
|
|
|
|||
|
|
@ -33,6 +33,10 @@ if get_option('renderer-gl')
|
|||
deps_wlwl += dep_egl # for gl-renderer.h
|
||||
endif
|
||||
|
||||
if get_option('renderer-vulkan')
|
||||
deps_wlwl += dep_vulkan # for vulkan-renderer.h
|
||||
endif
|
||||
|
||||
plugin_wlwl = shared_library(
|
||||
'wayland-backend',
|
||||
srcs_wlwl,
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@
|
|||
#include <libweston/libweston.h>
|
||||
#include <libweston/backend-wayland.h>
|
||||
#include "renderer-gl/gl-renderer.h"
|
||||
#include "renderer-vulkan/vulkan-renderer.h"
|
||||
#include "renderer-borders.h"
|
||||
#include "shared/weston-drm-fourcc.h"
|
||||
#include "shared/weston-egl-ext.h"
|
||||
|
|
@ -456,8 +457,12 @@ static const struct wl_callback_listener frame_listener = {
|
|||
static void
|
||||
draw_initial_frame(struct wayland_output *output)
|
||||
{
|
||||
struct wayland_backend *b = output->backend;
|
||||
struct wayland_shm_buffer *sb;
|
||||
|
||||
assert(b->compositor);
|
||||
assert(b->compositor->renderer);
|
||||
|
||||
sb = wayland_output_get_shm_buffer(output);
|
||||
|
||||
/* If we are rendering with GL, then orphan it so that it gets
|
||||
|
|
@ -465,12 +470,15 @@ draw_initial_frame(struct wayland_output *output)
|
|||
if (output->gl.egl_window)
|
||||
sb->output = NULL;
|
||||
|
||||
if (b->compositor->renderer->type == WESTON_RENDERER_VULKAN)
|
||||
sb->output = NULL;
|
||||
|
||||
wl_surface_attach(output->parent.surface, sb->buffer, 0, 0);
|
||||
wl_surface_damage(output->parent.surface, 0, 0,
|
||||
sb->width, sb->height);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_EGL
|
||||
#if defined(ENABLE_EGL) || defined(ENABLE_VULKAN)
|
||||
static void
|
||||
wayland_output_update_renderer_border(struct wayland_output *output)
|
||||
{
|
||||
|
|
@ -530,6 +538,35 @@ wayland_output_repaint_gl(struct weston_output *output_base)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_VULKAN
|
||||
static int
|
||||
wayland_output_repaint_vulkan(struct weston_output *output_base)
|
||||
{
|
||||
struct wayland_output *output = to_wayland_output(output_base);
|
||||
struct weston_compositor *ec;
|
||||
pixman_region32_t damage;
|
||||
|
||||
assert(output);
|
||||
|
||||
ec = output->base.compositor;
|
||||
|
||||
pixman_region32_init(&damage);
|
||||
|
||||
weston_output_flush_damage_for_primary_plane(output_base, &damage);
|
||||
|
||||
output->frame_cb = wl_surface_frame(output->parent.surface);
|
||||
wl_callback_add_listener(output->frame_cb, &frame_listener, output);
|
||||
|
||||
wayland_output_update_renderer_border(output);
|
||||
|
||||
ec->renderer->repaint_output(&output->base, &damage, NULL);
|
||||
|
||||
pixman_region32_fini(&damage);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
wayland_output_update_shm_border(struct wayland_shm_buffer *buffer)
|
||||
{
|
||||
|
|
@ -709,6 +746,13 @@ wayland_output_disable(struct weston_output *base)
|
|||
renderer->gl->output_destroy(&output->base);
|
||||
wl_egl_window_destroy(output->gl.egl_window);
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_VULKAN
|
||||
case WESTON_RENDERER_VULKAN:
|
||||
weston_renderer_borders_fini(&output->borders, &output->base);
|
||||
|
||||
renderer->vulkan->output_destroy(&output->base);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
unreachable("invalid renderer");
|
||||
|
|
@ -790,6 +834,47 @@ cleanup_window:
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_VULKAN
|
||||
static int
|
||||
wayland_output_init_vulkan_renderer(struct wayland_output *output)
|
||||
{
|
||||
const struct weston_mode *mode = output->base.current_mode;
|
||||
struct wayland_backend *b = output->backend;
|
||||
const struct weston_renderer *renderer;
|
||||
struct vulkan_renderer_output_options options = {
|
||||
.formats = b->formats,
|
||||
.formats_count = b->formats_count,
|
||||
};
|
||||
|
||||
if (output->frame) {
|
||||
frame_interior(output->frame, &options.area.x, &options.area.y,
|
||||
&options.area.width, &options.area.height);
|
||||
options.fb_size.width = frame_width(output->frame);
|
||||
options.fb_size.height = frame_height(output->frame);
|
||||
} else {
|
||||
options.area.x = 0;
|
||||
options.area.y = 0;
|
||||
options.area.width = mode->width;
|
||||
options.area.height = mode->height;
|
||||
options.fb_size.width = mode->width;
|
||||
options.fb_size.height = mode->height;
|
||||
}
|
||||
|
||||
options.wayland_display = b->parent.wl_display;
|
||||
options.wayland_surface = output->parent.surface;
|
||||
|
||||
renderer = output->base.compositor->renderer;
|
||||
|
||||
if (renderer->vulkan->output_window_create(&output->base, &options) < 0)
|
||||
goto cleanup_window;
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup_window:
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
wayland_output_init_pixman_renderer(struct wayland_output *output)
|
||||
{
|
||||
|
|
@ -824,6 +909,9 @@ wayland_output_resize_surface(struct wayland_output *output)
|
|||
struct weston_geometry opa = area;
|
||||
struct wl_region *region;
|
||||
|
||||
assert(b->compositor);
|
||||
assert(b->compositor->renderer);
|
||||
|
||||
if (output->frame) {
|
||||
frame_resize_inside(output->frame, area.width, area.height);
|
||||
frame_interior(output->frame, &area.x, &area.y, NULL, NULL);
|
||||
|
|
@ -862,6 +950,14 @@ wayland_output_resize_surface(struct wayland_output *output)
|
|||
weston_renderer_borders_fini(&output->borders, &output->base);
|
||||
} else
|
||||
#endif
|
||||
#ifdef ENABLE_VULKAN
|
||||
if (b->compositor->renderer->type == WESTON_RENDERER_VULKAN) {
|
||||
weston_renderer_resize_output(&output->base, &fb_size, &area);
|
||||
|
||||
/* These will need to be re-created due to the resize */
|
||||
weston_renderer_borders_fini(&output->borders, &output->base);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/*
|
||||
* Pixman-renderer never knows about decorations, we blit them
|
||||
|
|
@ -1043,6 +1139,13 @@ wayland_output_switch_mode_finish(struct wayland_output *output)
|
|||
if (wayland_output_init_gl_renderer(output) < 0)
|
||||
return -1;
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_VULKAN
|
||||
case WESTON_RENDERER_VULKAN:
|
||||
renderer->vulkan->output_destroy(&output->base);
|
||||
if (wayland_output_init_vulkan_renderer(output) < 0)
|
||||
return -1;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
unreachable("invalid renderer");
|
||||
|
|
@ -1303,6 +1406,14 @@ wayland_output_enable(struct weston_output *base)
|
|||
|
||||
output->base.repaint = wayland_output_repaint_gl;
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_VULKAN
|
||||
case WESTON_RENDERER_VULKAN:
|
||||
if (wayland_output_init_vulkan_renderer(output) < 0)
|
||||
goto err_output;
|
||||
|
||||
output->base.repaint = wayland_output_repaint_vulkan;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
unreachable("invalid renderer");
|
||||
|
|
@ -2961,6 +3072,22 @@ wayland_backend_create(struct weston_compositor *compositor,
|
|||
goto err_display;
|
||||
}
|
||||
break;
|
||||
case WESTON_RENDERER_VULKAN: {
|
||||
const struct vulkan_renderer_display_options options = {
|
||||
.formats = b->formats,
|
||||
.formats_count = b->formats_count,
|
||||
};
|
||||
|
||||
if (weston_compositor_init_renderer(compositor,
|
||||
WESTON_RENDERER_VULKAN,
|
||||
&options.base) < 0) {
|
||||
weston_log("Failed to initialize the Vulkan renderer\n");
|
||||
goto err_display;
|
||||
}
|
||||
/* For now Vulkan does not fall back to anything automatically,
|
||||
* like GL renderer does. */
|
||||
break;
|
||||
}
|
||||
default:
|
||||
weston_log("Unsupported renderer requested\n");
|
||||
goto err_display;
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@
|
|||
#include "shared/timespec-util.h"
|
||||
#include "shared/file-util.h"
|
||||
#include "renderer-gl/gl-renderer.h"
|
||||
#include "renderer-vulkan/vulkan-renderer.h"
|
||||
#include "shared/weston-drm-fourcc.h"
|
||||
#include "shared/weston-egl-ext.h"
|
||||
#include "shared/xalloc.h"
|
||||
|
|
@ -455,6 +456,29 @@ x11_output_repaint_gl(struct weston_output *output_base)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
x11_output_repaint_vulkan(struct weston_output *output_base)
|
||||
{
|
||||
struct x11_output *output = to_x11_output(output_base);
|
||||
struct weston_compositor *ec;
|
||||
pixman_region32_t damage;
|
||||
|
||||
assert(output);
|
||||
|
||||
ec = output->base.compositor;
|
||||
|
||||
pixman_region32_init(&damage);
|
||||
|
||||
weston_output_flush_damage_for_primary_plane(output_base, &damage);
|
||||
|
||||
ec->renderer->repaint_output(output_base, &damage, NULL);
|
||||
|
||||
pixman_region32_fini(&damage);
|
||||
|
||||
weston_output_arm_frame_timer(output_base, output->finish_frame_timer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
set_clip_for_output(struct weston_output *output_base, pixman_region32_t *region)
|
||||
{
|
||||
|
|
@ -929,6 +953,9 @@ x11_output_disable(struct weston_output *base)
|
|||
case WESTON_RENDERER_GL:
|
||||
renderer->gl->output_destroy(&output->base);
|
||||
break;
|
||||
case WESTON_RENDERER_VULKAN:
|
||||
renderer->vulkan->output_destroy(&output->base);
|
||||
break;
|
||||
default:
|
||||
unreachable("invalid renderer");
|
||||
}
|
||||
|
|
@ -1110,6 +1137,29 @@ x11_output_enable(struct weston_output *base)
|
|||
output->base.repaint = x11_output_repaint_gl;
|
||||
break;
|
||||
}
|
||||
case WESTON_RENDERER_VULKAN: {
|
||||
struct vulkan_renderer_output_options options = {
|
||||
.formats = b->formats,
|
||||
.formats_count = b->formats_count,
|
||||
.area.x = 0,
|
||||
.area.y = 0,
|
||||
.area.width = mode->width,
|
||||
.area.height = mode->height,
|
||||
.fb_size.width = mode->width,
|
||||
.fb_size.height = mode->height,
|
||||
};
|
||||
|
||||
options.xcb_connection = b->conn;
|
||||
options.xcb_visualid = screen->root_visual;
|
||||
options.xcb_window = output->window;
|
||||
|
||||
ret = renderer->vulkan->output_window_create(base, &options);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
output->base.repaint = x11_output_repaint_vulkan;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
unreachable("invalid renderer");
|
||||
}
|
||||
|
|
@ -1960,6 +2010,17 @@ x11_backend_create(struct weston_compositor *compositor,
|
|||
goto err_xdisplay;
|
||||
break;
|
||||
}
|
||||
case WESTON_RENDERER_VULKAN: {
|
||||
const struct vulkan_renderer_display_options options = {
|
||||
.formats = b->formats,
|
||||
.formats_count = b->formats_count,
|
||||
};
|
||||
if (weston_compositor_init_renderer(compositor,
|
||||
WESTON_RENDERER_VULKAN,
|
||||
&options.base) < 0)
|
||||
goto err_xdisplay;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
weston_log("Unsupported renderer requested\n");
|
||||
goto err_xdisplay;
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@
|
|||
#include "pixman-renderer.h"
|
||||
#include "renderer-gl/gl-renderer.h"
|
||||
#include "weston-trace.h"
|
||||
#include "renderer-vulkan/vulkan-renderer.h"
|
||||
|
||||
#include "weston-log-internal.h"
|
||||
|
||||
|
|
@ -10514,6 +10515,8 @@ weston_compositor_init_renderer(struct weston_compositor *compositor,
|
|||
{
|
||||
const struct gl_renderer_interface *gl_renderer;
|
||||
const struct gl_renderer_display_options *gl_options;
|
||||
const struct vulkan_renderer_interface *vulkan_renderer;
|
||||
const struct vulkan_renderer_display_options *vulkan_options;
|
||||
int ret;
|
||||
|
||||
switch (renderer_type) {
|
||||
|
|
@ -10534,6 +10537,28 @@ weston_compositor_init_renderer(struct weston_compositor *compositor,
|
|||
compositor->renderer->gl = gl_renderer;
|
||||
weston_log("Using GL renderer\n");
|
||||
break;
|
||||
case WESTON_RENDERER_VULKAN:
|
||||
vulkan_renderer = weston_load_module("vulkan-renderer.so",
|
||||
"vulkan_renderer_interface",
|
||||
LIBWESTON_MODULEDIR);
|
||||
if (!vulkan_renderer)
|
||||
return -1;
|
||||
|
||||
vulkan_options = container_of(options,
|
||||
struct vulkan_renderer_display_options,
|
||||
base);
|
||||
ret = vulkan_renderer->display_create(compositor, vulkan_options);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
compositor->renderer->vulkan = vulkan_renderer;
|
||||
weston_log("Using Vulkan renderer\n");
|
||||
weston_log_continue(STAMP_SPACE "Note: This version of Vulkan renderer "
|
||||
"is still experimental and not expected to be ready "
|
||||
"for production use\n");
|
||||
weston_log("Run with VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation "
|
||||
"to enable the Vulkan validation layers\n");
|
||||
break;
|
||||
case WESTON_RENDERER_PIXMAN:
|
||||
ret = pixman_renderer_init(compositor);
|
||||
if (ret < 0)
|
||||
|
|
|
|||
|
|
@ -208,6 +208,7 @@ struct weston_renderer {
|
|||
|
||||
enum weston_renderer_type type;
|
||||
const struct gl_renderer_interface *gl;
|
||||
const struct vulkan_renderer_interface *vulkan;
|
||||
const struct pixman_renderer_interface *pixman;
|
||||
|
||||
/* Sets the output border.
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ deps_libweston = [
|
|||
dep_xkbcommon,
|
||||
dep_matrix_c,
|
||||
dep_egl,
|
||||
dep_vulkan,
|
||||
]
|
||||
srcs_libweston = [
|
||||
git_version_h,
|
||||
|
|
@ -242,6 +243,7 @@ dep_lib_renderer_borders = declare_dependency(
|
|||
|
||||
subdir('color-lcms')
|
||||
subdir('renderer-gl')
|
||||
subdir('renderer-vulkan')
|
||||
subdir('backend-drm')
|
||||
subdir('backend-headless')
|
||||
subdir('backend-pipewire')
|
||||
|
|
|
|||
|
|
@ -94,6 +94,13 @@
|
|||
#define GL_TYPE(type) .gl_type = 0
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_VULKAN
|
||||
#include <vulkan/vulkan.h>
|
||||
#define VULKAN_FORMAT(fmt) .vulkan_format = (fmt)
|
||||
#else
|
||||
#define VULKAN_FORMAT(fmt) .vulkan_format = 0
|
||||
#endif
|
||||
|
||||
#define DRM_FORMAT(f) .format = DRM_FORMAT_ ## f, .drm_format_name = #f
|
||||
#define BITS_RGBA_FIXED(r_, g_, b_, a_) \
|
||||
.bits.r = r_, \
|
||||
|
|
@ -128,6 +135,7 @@ static const struct pixel_format_info pixel_format_table[] = {
|
|||
GL_FORMAT_INFO(GL_R8, GL_RED, GL_UNSIGNED_BYTE, R001),
|
||||
GL_FORMAT(GL_R8_EXT),
|
||||
GL_TYPE(GL_UNSIGNED_BYTE),
|
||||
VULKAN_FORMAT(VK_FORMAT_R8_UNORM),
|
||||
},
|
||||
{
|
||||
DRM_FORMAT(R16),
|
||||
|
|
@ -146,6 +154,7 @@ static const struct pixel_format_info pixel_format_table[] = {
|
|||
GL_FORMAT_INFO(GL_RG8, GL_RG, GL_UNSIGNED_BYTE, RG01),
|
||||
GL_FORMAT(GL_RG8_EXT),
|
||||
GL_TYPE(GL_UNSIGNED_BYTE),
|
||||
VULKAN_FORMAT(VK_FORMAT_R8G8_UNORM),
|
||||
},
|
||||
{
|
||||
DRM_FORMAT(RG88),
|
||||
|
|
@ -366,6 +375,7 @@ static const struct pixel_format_info pixel_format_table[] = {
|
|||
GL_FORMAT_INFO(GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, BGR1),
|
||||
GL_FORMAT(GL_RGB),
|
||||
GL_TYPE(GL_UNSIGNED_BYTE),
|
||||
VULKAN_FORMAT(VK_FORMAT_B8G8R8_UNORM),
|
||||
},
|
||||
{
|
||||
DRM_FORMAT(BGR888),
|
||||
|
|
@ -375,6 +385,7 @@ static const struct pixel_format_info pixel_format_table[] = {
|
|||
GL_FORMAT_INFO(GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, RGB1),
|
||||
GL_FORMAT(GL_RGB),
|
||||
GL_TYPE(GL_UNSIGNED_BYTE),
|
||||
VULKAN_FORMAT(VK_FORMAT_R8G8B8_UNORM),
|
||||
},
|
||||
{
|
||||
DRM_FORMAT(XRGB8888),
|
||||
|
|
@ -386,6 +397,7 @@ static const struct pixel_format_info pixel_format_table[] = {
|
|||
GL_INTERNALFORMAT(GL_RGB8),
|
||||
GL_FORMAT(GL_BGRA_EXT),
|
||||
GL_TYPE(GL_UNSIGNED_BYTE),
|
||||
VULKAN_FORMAT(VK_FORMAT_B8G8R8A8_UNORM),
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
PIXMAN_FMT(x8r8g8b8),
|
||||
#else
|
||||
|
|
@ -403,6 +415,7 @@ static const struct pixel_format_info pixel_format_table[] = {
|
|||
GL_INTERNALFORMAT(GL_RGBA8),
|
||||
GL_FORMAT(GL_BGRA_EXT),
|
||||
GL_TYPE(GL_UNSIGNED_BYTE),
|
||||
VULKAN_FORMAT(VK_FORMAT_B8G8R8A8_UNORM),
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
PIXMAN_FMT(a8r8g8b8),
|
||||
#else
|
||||
|
|
@ -417,6 +430,7 @@ static const struct pixel_format_info pixel_format_table[] = {
|
|||
GL_FORMAT_INFO(GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, RGB1),
|
||||
GL_FORMAT(GL_RGBA),
|
||||
GL_TYPE(GL_UNSIGNED_BYTE),
|
||||
VULKAN_FORMAT(VK_FORMAT_R8G8B8A8_UNORM),
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
PIXMAN_FMT(x8b8g8r8),
|
||||
#else
|
||||
|
|
@ -432,6 +446,7 @@ static const struct pixel_format_info pixel_format_table[] = {
|
|||
GL_FORMAT_INFO(GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, RGBA),
|
||||
GL_FORMAT(GL_RGBA),
|
||||
GL_TYPE(GL_UNSIGNED_BYTE),
|
||||
VULKAN_FORMAT(VK_FORMAT_R8G8B8A8_UNORM),
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
PIXMAN_FMT(a8b8g8r8),
|
||||
#else
|
||||
|
|
@ -538,6 +553,7 @@ static const struct pixel_format_info pixel_format_table[] = {
|
|||
BITS_RGBA_FIXED(10, 10, 10, 2),
|
||||
.bpp = 32,
|
||||
.opaque_substitute = DRM_FORMAT_XBGR2101010,
|
||||
VULKAN_FORMAT(VK_FORMAT_A2B10G10R10_UNORM_PACK32),
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
GL_FORMAT_INFO(GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, RGBA),
|
||||
GL_FORMAT(GL_RGBA),
|
||||
|
|
@ -580,6 +596,7 @@ static const struct pixel_format_info pixel_format_table[] = {
|
|||
#if __BYTE_ORDER__ == __LITTLE_ENDIAN
|
||||
GL_FORMAT(GL_RGBA16_EXT),
|
||||
GL_TYPE(GL_UNSIGNED_SHORT),
|
||||
VULKAN_FORMAT(VK_FORMAT_R16G16B16A16_UNORM),
|
||||
#endif
|
||||
},
|
||||
{
|
||||
|
|
@ -592,6 +609,7 @@ static const struct pixel_format_info pixel_format_table[] = {
|
|||
#if __BYTE_ORDER__ == __LITTLE_ENDIAN
|
||||
GL_FORMAT(GL_RGBA16_EXT),
|
||||
GL_TYPE(GL_UNSIGNED_SHORT),
|
||||
VULKAN_FORMAT(VK_FORMAT_R16G16B16A16_UNORM),
|
||||
#endif
|
||||
},
|
||||
{
|
||||
|
|
@ -618,6 +636,7 @@ static const struct pixel_format_info pixel_format_table[] = {
|
|||
#if __BYTE_ORDER__ == __LITTLE_ENDIAN
|
||||
GL_FORMAT(GL_RGBA16F),
|
||||
GL_TYPE(GL_HALF_FLOAT),
|
||||
VULKAN_FORMAT(VK_FORMAT_R16G16B16A16_SFLOAT),
|
||||
#endif
|
||||
},
|
||||
{
|
||||
|
|
@ -630,6 +649,7 @@ static const struct pixel_format_info pixel_format_table[] = {
|
|||
#if __BYTE_ORDER__ == __LITTLE_ENDIAN
|
||||
GL_FORMAT(GL_RGBA16F),
|
||||
GL_TYPE(GL_HALF_FLOAT),
|
||||
VULKAN_FORMAT(VK_FORMAT_R16G16B16A16_SFLOAT),
|
||||
#endif
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -107,6 +107,9 @@ struct pixel_format_info {
|
|||
/** GL data type, if data can be natively/directly uploaded. */
|
||||
int gl_type;
|
||||
|
||||
/** Vulkan format, if data can be natively/directly uploaded. */
|
||||
int vulkan_format;
|
||||
|
||||
/** Pixman data type, if it agrees exactly with the wl_shm format */
|
||||
pixman_format_code_t pixman_format;
|
||||
|
||||
|
|
|
|||
59
libweston/renderer-vulkan/meson.build
Normal file
59
libweston/renderer-vulkan/meson.build
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
if not get_option('renderer-vulkan')
|
||||
subdir_done()
|
||||
endif
|
||||
|
||||
config_h.set('ENABLE_VULKAN', '1')
|
||||
|
||||
srcs_shaders_renderer_vulkan = [
|
||||
'vulkan_vertex_shader_surface.vert',
|
||||
'vulkan_vertex_shader_texcoord.vert',
|
||||
'vulkan_fragment_shader.frag',
|
||||
]
|
||||
|
||||
shaders_renderer_vulkan = []
|
||||
foreach s : srcs_shaders_renderer_vulkan
|
||||
shaders_renderer_vulkan += custom_target(s + '.spv.h',
|
||||
command: [ prog_glslang, '@INPUT@', '--quiet', '--variable-name', '@BASENAME@', '-V', '-x', '-o', '@OUTPUT@' ],
|
||||
input: s,
|
||||
output: '@BASENAME@.spv.h',
|
||||
)
|
||||
endforeach
|
||||
|
||||
srcs_renderer_vulkan = [
|
||||
'vulkan-pipeline.c',
|
||||
'vulkan-pixel-format.c',
|
||||
'vulkan-renderer.c',
|
||||
shaders_renderer_vulkan,
|
||||
linux_dmabuf_unstable_v1_protocol_c,
|
||||
linux_dmabuf_unstable_v1_server_protocol_h,
|
||||
]
|
||||
|
||||
deps_renderer_vulkan = [
|
||||
dep_libdrm,
|
||||
|
||||
dep_gbm,
|
||||
dep_libm,
|
||||
dep_pixman,
|
||||
dep_libweston_private,
|
||||
dep_libdrm_headers,
|
||||
dep_vertex_clipping
|
||||
]
|
||||
|
||||
foreach name : [ 'vulkan' ]
|
||||
d = dependency(name, required: false)
|
||||
if not d.found()
|
||||
error('vulkan-renderer requires @0@ which was not found. Or, you can use \'-Drenderer-vulkan=false\'.'.format(name))
|
||||
endif
|
||||
deps_renderer_vulkan += d
|
||||
endforeach
|
||||
|
||||
plugin_vulkan = shared_library(
|
||||
'vulkan-renderer',
|
||||
srcs_renderer_vulkan,
|
||||
include_directories: common_inc,
|
||||
dependencies: deps_renderer_vulkan,
|
||||
name_prefix: '',
|
||||
install: true,
|
||||
install_dir: dir_module_libweston
|
||||
)
|
||||
env_modmap += 'vulkan-renderer.so=@0@;'.format(plugin_vulkan.full_path())
|
||||
399
libweston/renderer-vulkan/vulkan-pipeline.c
Normal file
399
libweston/renderer-vulkan/vulkan-pipeline.c
Normal file
|
|
@ -0,0 +1,399 @@
|
|||
/*
|
||||
* Copyright © 2025 Erico Nunes
|
||||
*
|
||||
* based on gl-shaders.c:
|
||||
* Copyright 2012 Intel Corporation
|
||||
* Copyright 2015,2019,2021 Collabora, Ltd.
|
||||
* Copyright 2016 NVIDIA Corporation
|
||||
* Copyright 2019 Harish Krupo
|
||||
* Copyright 2019 Intel Corporation
|
||||
* Copyright 2021 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial
|
||||
* portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "vulkan-renderer.h"
|
||||
#include "vulkan-renderer-internal.h"
|
||||
|
||||
/* const uint32_t vulkan_vertex_shader_surface[]; vulkan_vertex_shader_surface.vert */
|
||||
#include "vulkan_vertex_shader_surface.spv.h"
|
||||
|
||||
/* const uint32_t vulkan_vertex_shader_texcoord[]; vulkan_vertex_shader_texcoord.vert */
|
||||
#include "vulkan_vertex_shader_texcoord.spv.h"
|
||||
|
||||
/* const uint32_t vulkan_fragment_shader[]; vulkan_fragment_shader.frag */
|
||||
#include "vulkan_fragment_shader.spv.h"
|
||||
|
||||
struct vertex {
|
||||
float pos[2];
|
||||
};
|
||||
|
||||
struct vertex_tc {
|
||||
float pos[2];
|
||||
float texcoord[2];
|
||||
};
|
||||
|
||||
struct fs_specialization_consts {
|
||||
uint32_t c_variant;
|
||||
uint32_t c_input_is_premult;
|
||||
};
|
||||
|
||||
static void create_graphics_pipeline(struct vulkan_renderer *vr,
|
||||
const struct vulkan_pipeline_requirements *req,
|
||||
struct vulkan_pipeline *pipeline)
|
||||
{
|
||||
VkResult result;
|
||||
|
||||
VkShaderModule vs_module;
|
||||
VkShaderModuleCreateInfo vs_shader_module_create_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
||||
};
|
||||
|
||||
switch (req->texcoord_input) {
|
||||
case SHADER_TEXCOORD_INPUT_ATTRIB:
|
||||
vs_shader_module_create_info.codeSize = sizeof(vulkan_vertex_shader_texcoord),
|
||||
vs_shader_module_create_info.pCode = (uint32_t *)vulkan_vertex_shader_texcoord;
|
||||
break;
|
||||
case SHADER_TEXCOORD_INPUT_SURFACE:
|
||||
vs_shader_module_create_info.codeSize = sizeof(vulkan_vertex_shader_surface);
|
||||
vs_shader_module_create_info.pCode = (uint32_t *)vulkan_vertex_shader_surface;
|
||||
break;
|
||||
default:
|
||||
weston_log("Invalid req->texcoord_input\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
vkCreateShaderModule(vr->dev, &vs_shader_module_create_info, NULL, &vs_module);
|
||||
|
||||
const struct fs_specialization_consts fsc = {
|
||||
req->variant,
|
||||
req->input_is_premult
|
||||
};
|
||||
const VkSpecializationMapEntry fsc_entries[] = {
|
||||
{ 0, 0, sizeof(fsc.c_variant) },
|
||||
{ 1, 0, sizeof(fsc.c_input_is_premult) },
|
||||
};
|
||||
const VkSpecializationInfo fs_specialization = {
|
||||
.mapEntryCount = ARRAY_LENGTH(fsc_entries),
|
||||
.pMapEntries = fsc_entries,
|
||||
.dataSize = sizeof(fsc),
|
||||
.pData = &fsc,
|
||||
};
|
||||
VkShaderModule fs_module;
|
||||
const VkShaderModuleCreateInfo fs_shader_module_create_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
||||
.codeSize = sizeof(vulkan_fragment_shader),
|
||||
.pCode = (uint32_t *)vulkan_fragment_shader,
|
||||
};
|
||||
vkCreateShaderModule(vr->dev, &fs_shader_module_create_info, NULL, &fs_module);
|
||||
|
||||
const VkPipelineShaderStageCreateInfo vert_shader_stage_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
.module = vs_module,
|
||||
.pName = "main",
|
||||
};
|
||||
|
||||
const VkPipelineShaderStageCreateInfo frag_shader_stage_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
.module = fs_module,
|
||||
.pSpecializationInfo = &fs_specialization,
|
||||
.pName = "main",
|
||||
};
|
||||
|
||||
const VkPipelineShaderStageCreateInfo shader_stages[] = {vert_shader_stage_info, frag_shader_stage_info};
|
||||
|
||||
// SHADER_TEXCOORD_INPUT_ATTRIB
|
||||
const VkPipelineVertexInputStateCreateInfo pipeline_vertex_input_attrib = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.vertexBindingDescriptionCount = 1,
|
||||
.pVertexBindingDescriptions = (VkVertexInputBindingDescription[]) {
|
||||
{
|
||||
.binding = 0,
|
||||
.stride = sizeof(struct vertex_tc),
|
||||
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX
|
||||
},
|
||||
},
|
||||
.vertexAttributeDescriptionCount = 2,
|
||||
.pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[]) {
|
||||
{
|
||||
.binding = 0,
|
||||
.location = 0,
|
||||
.format = VK_FORMAT_R32G32_SFLOAT,
|
||||
.offset = offsetof(struct vertex_tc, pos),
|
||||
},
|
||||
{
|
||||
.binding = 0,
|
||||
.location = 1,
|
||||
.format = VK_FORMAT_R32G32_SFLOAT,
|
||||
.offset = offsetof(struct vertex_tc, texcoord),
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
// SHADER_TEXCOORD_INPUT_SURFACE
|
||||
const VkPipelineVertexInputStateCreateInfo pipeline_vertex_input_surface = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.vertexBindingDescriptionCount = 1,
|
||||
.pVertexBindingDescriptions = (VkVertexInputBindingDescription[]) {
|
||||
{
|
||||
.binding = 0,
|
||||
.stride = sizeof(struct vertex),
|
||||
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX
|
||||
},
|
||||
},
|
||||
.vertexAttributeDescriptionCount = 1,
|
||||
.pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[]) {
|
||||
{
|
||||
.binding = 0,
|
||||
.location = 0,
|
||||
.format = VK_FORMAT_R32G32_SFLOAT,
|
||||
.offset = offsetof(struct vertex, pos),
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
const VkPipelineVertexInputStateCreateInfo *pipeline_vertex_input_state_create_info;
|
||||
|
||||
switch (req->texcoord_input) {
|
||||
case SHADER_TEXCOORD_INPUT_ATTRIB:
|
||||
pipeline_vertex_input_state_create_info = &pipeline_vertex_input_attrib;
|
||||
break;
|
||||
case SHADER_TEXCOORD_INPUT_SURFACE:
|
||||
pipeline_vertex_input_state_create_info = &pipeline_vertex_input_surface;
|
||||
break;
|
||||
default:
|
||||
weston_log("Invalid req->texcoord_input\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,
|
||||
.primitiveRestartEnable = VK_FALSE,
|
||||
};
|
||||
|
||||
const VkPipelineViewportStateCreateInfo viewport_state = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
.viewportCount = 1,
|
||||
.scissorCount = 1,
|
||||
};
|
||||
|
||||
const VkPipelineRasterizationStateCreateInfo rasterizer = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
.depthClampEnable = VK_FALSE,
|
||||
.rasterizerDiscardEnable = VK_FALSE,
|
||||
.polygonMode = VK_POLYGON_MODE_FILL,
|
||||
.lineWidth = 1.0f,
|
||||
.cullMode = VK_CULL_MODE_NONE,
|
||||
.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
|
||||
.depthBiasEnable = VK_FALSE,
|
||||
};
|
||||
|
||||
const VkPipelineMultisampleStateCreateInfo multisampling = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||
.sampleShadingEnable = VK_FALSE,
|
||||
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
|
||||
};
|
||||
|
||||
VkPipelineColorBlendAttachmentState color_blend_attachment = {
|
||||
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
|
||||
.blendEnable = VK_FALSE,
|
||||
};
|
||||
|
||||
if (req->blend) {
|
||||
color_blend_attachment.blendEnable = VK_TRUE;
|
||||
color_blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||
color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
color_blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD;
|
||||
color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||
}
|
||||
|
||||
const VkPipelineColorBlendStateCreateInfo color_blending = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
||||
.logicOpEnable = VK_FALSE,
|
||||
.logicOp = VK_LOGIC_OP_COPY,
|
||||
.attachmentCount = 1,
|
||||
.pAttachments = &color_blend_attachment,
|
||||
};
|
||||
|
||||
const VkDynamicState dynamic_states[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
|
||||
const VkPipelineDynamicStateCreateInfo dynamic_state = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.dynamicStateCount = ARRAY_LENGTH(dynamic_states),
|
||||
.pDynamicStates = dynamic_states,
|
||||
};
|
||||
|
||||
const VkPipelineLayoutCreateInfo pipeline_layout_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
.setLayoutCount = 1,
|
||||
.pSetLayouts = &pipeline->descriptor_set_layout,
|
||||
};
|
||||
|
||||
result = vkCreatePipelineLayout(vr->dev, &pipeline_layout_info, NULL, &pipeline->pipeline_layout);
|
||||
check_vk_success(result, "vkCreatePipelineLayout");
|
||||
|
||||
const VkGraphicsPipelineCreateInfo pipeline_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.stageCount = 2,
|
||||
.pStages = shader_stages,
|
||||
.pVertexInputState = pipeline_vertex_input_state_create_info,
|
||||
.pInputAssemblyState = &input_assembly,
|
||||
.pViewportState = &viewport_state,
|
||||
.pRasterizationState = &rasterizer,
|
||||
.pMultisampleState = &multisampling,
|
||||
.pColorBlendState = &color_blending,
|
||||
.pDynamicState = &dynamic_state,
|
||||
.layout = pipeline->pipeline_layout,
|
||||
.renderPass = req->renderpass,
|
||||
.subpass = 0,
|
||||
.basePipelineHandle = VK_NULL_HANDLE,
|
||||
};
|
||||
|
||||
result = vkCreateGraphicsPipelines(vr->dev, VK_NULL_HANDLE, 1, &pipeline_info, NULL, &pipeline->pipeline);
|
||||
check_vk_success(result, "vkCreateGraphicsPipelines");
|
||||
|
||||
vkDestroyShaderModule(vr->dev, fs_module, NULL);
|
||||
vkDestroyShaderModule(vr->dev, vs_module, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
create_descriptor_set_layout(struct vulkan_renderer *vr, struct vulkan_pipeline *pipeline)
|
||||
{
|
||||
VkResult result;
|
||||
|
||||
const VkDescriptorSetLayoutBinding vs_ubo_layout_binding = {
|
||||
.binding = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
};
|
||||
|
||||
const VkDescriptorSetLayoutBinding fs_ubo_layout_binding = {
|
||||
.binding = 1,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
};
|
||||
|
||||
const VkDescriptorSetLayoutBinding fs_sampler_layout_binding = {
|
||||
.binding = 2,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
};
|
||||
|
||||
const VkDescriptorSetLayoutBinding bindings[] = {
|
||||
vs_ubo_layout_binding,
|
||||
fs_ubo_layout_binding,
|
||||
fs_sampler_layout_binding,
|
||||
};
|
||||
const VkDescriptorSetLayoutCreateInfo layout_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||
.bindingCount = ARRAY_LENGTH(bindings),
|
||||
.pBindings = bindings,
|
||||
};
|
||||
|
||||
result = vkCreateDescriptorSetLayout(vr->dev, &layout_info, NULL, &pipeline->descriptor_set_layout);
|
||||
check_vk_success(result, "vkCreateDescriptorSetLayout");
|
||||
}
|
||||
|
||||
static struct vulkan_pipeline *
|
||||
vulkan_pipeline_create(struct vulkan_renderer *vr,
|
||||
const struct vulkan_pipeline_requirements *reqs)
|
||||
{
|
||||
struct vulkan_pipeline *pipeline = NULL;
|
||||
|
||||
pipeline = zalloc(sizeof *pipeline);
|
||||
if (!pipeline) {
|
||||
weston_log("could not create pipeline\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
wl_list_init(&pipeline->link);
|
||||
pipeline->key = *reqs;
|
||||
|
||||
create_descriptor_set_layout(vr, pipeline);
|
||||
|
||||
create_graphics_pipeline(vr, reqs, pipeline);
|
||||
|
||||
wl_list_insert(&vr->pipeline_list, &pipeline->link);
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
void
|
||||
vulkan_pipeline_destroy(struct vulkan_renderer *vr, struct vulkan_pipeline *pipeline)
|
||||
{
|
||||
vkDestroyPipelineLayout(vr->dev, pipeline->pipeline_layout, NULL);
|
||||
vkDestroyPipeline(vr->dev, pipeline->pipeline, NULL);
|
||||
vkDestroyDescriptorSetLayout(vr->dev, pipeline->descriptor_set_layout, NULL);
|
||||
wl_list_remove(&pipeline->link);
|
||||
free(pipeline);
|
||||
}
|
||||
|
||||
void
|
||||
vulkan_renderer_pipeline_list_destroy(struct vulkan_renderer *vr)
|
||||
{
|
||||
struct vulkan_pipeline *pipeline, *next_pipeline;
|
||||
|
||||
wl_list_for_each_safe(pipeline, next_pipeline, &vr->pipeline_list, link)
|
||||
vulkan_pipeline_destroy(vr, pipeline);
|
||||
}
|
||||
|
||||
static int
|
||||
vulkan_pipeline_requirements_cmp(const struct vulkan_pipeline_requirements *a,
|
||||
const struct vulkan_pipeline_requirements *b)
|
||||
{
|
||||
return memcmp(a, b, sizeof(*a));
|
||||
}
|
||||
|
||||
struct vulkan_pipeline *
|
||||
vulkan_renderer_get_pipeline(struct vulkan_renderer *vr,
|
||||
const struct vulkan_pipeline_requirements *reqs)
|
||||
{
|
||||
struct vulkan_pipeline *pipeline;
|
||||
|
||||
wl_list_for_each(pipeline, &vr->pipeline_list, link) {
|
||||
if (vulkan_pipeline_requirements_cmp(reqs, &pipeline->key) == 0)
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
pipeline = vulkan_pipeline_create(vr, reqs);
|
||||
if (pipeline)
|
||||
return pipeline;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
237
libweston/renderer-vulkan/vulkan-pixel-format.c
Normal file
237
libweston/renderer-vulkan/vulkan-pixel-format.c
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
* Copyright © 2025 Erico Nunes
|
||||
*
|
||||
* Based on wlroots' vulkan pixel_format.c
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial
|
||||
* portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include "pixel-formats.h"
|
||||
#include "shared/xalloc.h"
|
||||
#include "vulkan-renderer-internal.h"
|
||||
|
||||
#include <xf86drm.h>
|
||||
#include <drm_fourcc.h>
|
||||
|
||||
static const VkImageUsageFlags image_tex_usage =
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
|
||||
static const VkFormatFeatureFlags format_tex_features =
|
||||
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
|
||||
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
|
||||
|
||||
static bool
|
||||
query_modifier_usage_support(struct vulkan_renderer *vr, VkFormat vk_format,
|
||||
VkImageUsageFlags usage, const VkDrmFormatModifierPropertiesEXT *m)
|
||||
{
|
||||
VkResult result;
|
||||
|
||||
VkPhysicalDeviceImageFormatInfo2 pdev_image_format_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
|
||||
.type = VK_IMAGE_TYPE_2D,
|
||||
.format = vk_format,
|
||||
.usage = usage,
|
||||
.flags = 0,
|
||||
.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT,
|
||||
};
|
||||
|
||||
VkPhysicalDeviceExternalImageFormatInfo pdev_ext_image_format_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
|
||||
.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
|
||||
};
|
||||
pnext(&pdev_image_format_info, &pdev_ext_image_format_info);
|
||||
|
||||
VkPhysicalDeviceImageDrmFormatModifierInfoEXT pdev_image_drm_format_mod_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT,
|
||||
.drmFormatModifier = m->drmFormatModifier,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
};
|
||||
pnext(&pdev_image_format_info, &pdev_image_drm_format_mod_info);
|
||||
|
||||
VkImageFormatListCreateInfoKHR image_format_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR,
|
||||
.pViewFormats = &vk_format,
|
||||
.viewFormatCount = 1,
|
||||
};
|
||||
pnext(&pdev_image_format_info, &image_format_info);
|
||||
|
||||
VkImageFormatProperties2 image_format_props = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
|
||||
};
|
||||
|
||||
VkExternalImageFormatProperties ext_image_format_props = {
|
||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES,
|
||||
};
|
||||
pnext(&image_format_props, &ext_image_format_props);
|
||||
|
||||
const VkExternalMemoryProperties *ext_mem_props = &ext_image_format_props.externalMemoryProperties;
|
||||
|
||||
result = vkGetPhysicalDeviceImageFormatProperties2(vr->phys_dev, &pdev_image_format_info, &image_format_props);
|
||||
if (result != VK_SUCCESS && result != VK_ERROR_FORMAT_NOT_SUPPORTED)
|
||||
return false;
|
||||
|
||||
if (!(ext_mem_props->externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
query_dmabuf_support(struct vulkan_renderer *vr, VkFormat vk_format,
|
||||
VkImageFormatProperties *out)
|
||||
{
|
||||
VkResult result;
|
||||
|
||||
VkPhysicalDeviceImageFormatInfo2 pdev_image_format_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
|
||||
.type = VK_IMAGE_TYPE_2D,
|
||||
.format = vk_format,
|
||||
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
||||
.usage = image_tex_usage,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
VkImageFormatListCreateInfoKHR image_format_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR,
|
||||
.pViewFormats = &vk_format,
|
||||
.viewFormatCount = 1,
|
||||
};
|
||||
pnext(&pdev_image_format_info, &image_format_info);
|
||||
|
||||
VkImageFormatProperties2 image_format_props = {
|
||||
image_format_props.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
|
||||
};
|
||||
|
||||
result = vkGetPhysicalDeviceImageFormatProperties2(vr->phys_dev, &pdev_image_format_info, &image_format_props);
|
||||
if (result != VK_SUCCESS) {
|
||||
if (result == VK_ERROR_FORMAT_NOT_SUPPORTED) {
|
||||
weston_log("unsupported format\n");
|
||||
} else {
|
||||
weston_log("failed to get format properties\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = image_format_props.imageFormatProperties;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
query_dmabuf_modifier_support(struct vulkan_renderer *vr, const struct pixel_format_info *format,
|
||||
struct weston_drm_format *fmt)
|
||||
{
|
||||
if (!vr->has_image_drm_format_modifier) {
|
||||
uint64_t modifier = DRM_FORMAT_MOD_INVALID;
|
||||
|
||||
int ret = weston_drm_format_add_modifier(fmt, modifier);
|
||||
assert(ret == 0);
|
||||
|
||||
char *modifier_name = drmGetFormatModifierName(modifier);
|
||||
weston_log("DRM dmabuf format %s (0x%08x) modifier %s (0x%016lx)\n",
|
||||
format->drm_format_name ? format->drm_format_name : "<unknown>",
|
||||
format->format,
|
||||
modifier_name ? modifier_name : "<unknown>",
|
||||
modifier);
|
||||
free(modifier_name);
|
||||
return;
|
||||
}
|
||||
|
||||
VkDrmFormatModifierPropertiesListEXT drm_format_mod_props = {
|
||||
drm_format_mod_props.sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT,
|
||||
};
|
||||
VkFormatProperties2 format_props = {
|
||||
.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
|
||||
};
|
||||
pnext(&format_props, &drm_format_mod_props);
|
||||
vkGetPhysicalDeviceFormatProperties2(vr->phys_dev, format->vulkan_format, &format_props);
|
||||
|
||||
size_t modifier_count = drm_format_mod_props.drmFormatModifierCount;
|
||||
|
||||
drm_format_mod_props.drmFormatModifierCount = modifier_count;
|
||||
drm_format_mod_props.pDrmFormatModifierProperties =
|
||||
xzalloc(modifier_count * sizeof(*drm_format_mod_props.pDrmFormatModifierProperties));
|
||||
|
||||
vkGetPhysicalDeviceFormatProperties2(vr->phys_dev, format->vulkan_format, &format_props);
|
||||
|
||||
for (uint32_t i = 0; i < drm_format_mod_props.drmFormatModifierCount; ++i) {
|
||||
VkDrmFormatModifierPropertiesEXT m = drm_format_mod_props.pDrmFormatModifierProperties[i];
|
||||
|
||||
// check that specific modifier for texture usage
|
||||
if ((m.drmFormatModifierTilingFeatures & format_tex_features) != format_tex_features)
|
||||
continue;
|
||||
|
||||
if (!query_modifier_usage_support(vr, format->vulkan_format, image_tex_usage, &m))
|
||||
continue;
|
||||
|
||||
int ret = weston_drm_format_add_modifier(fmt, m.drmFormatModifier);
|
||||
assert(ret == 0);
|
||||
|
||||
char *modifier_name = drmGetFormatModifierName(m.drmFormatModifier);
|
||||
weston_log("DRM dmabuf format %s (0x%08x) modifier %s (0x%016lx) %d planes\n",
|
||||
format->drm_format_name ? format->drm_format_name : "<unknown>",
|
||||
format->format,
|
||||
modifier_name ? modifier_name : "<unknown>",
|
||||
m.drmFormatModifier,
|
||||
m.drmFormatModifierPlaneCount);
|
||||
free(modifier_name);
|
||||
|
||||
}
|
||||
|
||||
free(drm_format_mod_props.pDrmFormatModifierProperties);
|
||||
}
|
||||
|
||||
bool
|
||||
vulkan_renderer_query_dmabuf_format(struct vulkan_renderer *vr, const struct pixel_format_info *format)
|
||||
{
|
||||
VkFormatProperties2 format_props = {
|
||||
.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
|
||||
};
|
||||
|
||||
vkGetPhysicalDeviceFormatProperties2(vr->phys_dev, format->vulkan_format, &format_props);
|
||||
|
||||
struct weston_drm_format *fmt = NULL;
|
||||
|
||||
// dmabuf texture properties
|
||||
if ((format_props.formatProperties.optimalTilingFeatures & format_tex_features) != format_tex_features)
|
||||
return false;
|
||||
|
||||
VkImageFormatProperties iformat_props;
|
||||
if (!query_dmabuf_support(vr, format->vulkan_format, &iformat_props))
|
||||
return false;
|
||||
|
||||
fmt = weston_drm_format_array_add_format(&vr->supported_formats, format->format);
|
||||
assert(fmt);
|
||||
|
||||
weston_log("DRM dmabuf format %s (0x%08x)\n",
|
||||
format->drm_format_name ? format->drm_format_name : "<unknown>",
|
||||
format->format);
|
||||
|
||||
query_dmabuf_modifier_support(vr, format, fmt);
|
||||
|
||||
return true;
|
||||
}
|
||||
203
libweston/renderer-vulkan/vulkan-renderer-internal.h
Normal file
203
libweston/renderer-vulkan/vulkan-renderer-internal.h
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* Copyright © 2025 Erico Nunes
|
||||
*
|
||||
* based on gl-renderer-internal.h:
|
||||
* Copyright © 2019 Collabora, Ltd.
|
||||
* Copyright © 2019 Harish Krupo
|
||||
* Copyright © 2019 Intel Corporation
|
||||
* Copyright 2021 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial
|
||||
* portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef VULKAN_RENDERER_INTERNAL_H
|
||||
#define VULKAN_RENDERER_INTERNAL_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <wayland-util.h>
|
||||
#include <vulkan/vulkan.h>
|
||||
#include "shared/helpers.h"
|
||||
#include "libweston/libweston.h"
|
||||
#include "libweston/libweston-internal.h"
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
#define VK_USE_PLATFORM_XCB_KHR
|
||||
#define VK_USE_PLATFORM_WAYLAND_KHR
|
||||
#include <vulkan/vulkan_wayland.h>
|
||||
#include <vulkan/vulkan_xcb.h>
|
||||
|
||||
#define MAX_NUM_IMAGES 5
|
||||
#define MAX_CONCURRENT_FRAMES 2
|
||||
|
||||
enum vulkan_pipeline_texture_variant {
|
||||
PIPELINE_VARIANT_NONE = 0,
|
||||
/* Keep the following in sync with Vulkan shader.frag. */
|
||||
PIPELINE_VARIANT_RGBA = 1,
|
||||
PIPELINE_VARIANT_RGBX = 2,
|
||||
PIPELINE_VARIANT_SOLID = 3,
|
||||
PIPELINE_VARIANT_EXTERNAL = 4,
|
||||
};
|
||||
|
||||
struct vulkan_pipeline_requirements
|
||||
{
|
||||
unsigned texcoord_input:1; /* enum vulkan_shader_texcoord_input */
|
||||
unsigned variant:4; /* enum vulkan_pipeline_texture_variant */
|
||||
bool input_is_premult:1;
|
||||
bool blend:1;
|
||||
VkRenderPass renderpass;
|
||||
};
|
||||
|
||||
struct vulkan_pipeline_config {
|
||||
struct vulkan_pipeline_requirements req;
|
||||
|
||||
struct weston_matrix projection;
|
||||
struct weston_matrix surface_to_buffer;
|
||||
float view_alpha;
|
||||
float unicolor[4];
|
||||
};
|
||||
|
||||
|
||||
/* Keep the following in sync with vertex.glsl. */
|
||||
enum vulkan_shader_texcoord_input {
|
||||
SHADER_TEXCOORD_INPUT_ATTRIB = 0,
|
||||
SHADER_TEXCOORD_INPUT_SURFACE,
|
||||
};
|
||||
|
||||
struct vulkan_pipeline {
|
||||
struct vulkan_pipeline_requirements key;
|
||||
|
||||
struct wl_list link; /* vulkan_renderer::pipeline_list */
|
||||
struct timespec last_used;
|
||||
|
||||
VkDescriptorSetLayout descriptor_set_layout;
|
||||
|
||||
VkPipeline pipeline;
|
||||
VkPipelineLayout pipeline_layout;
|
||||
};
|
||||
|
||||
struct vulkan_renderer_texture_image {
|
||||
VkImage image;
|
||||
VkDeviceMemory memory;
|
||||
VkImageView image_view;
|
||||
|
||||
VkBuffer staging_buffer;
|
||||
VkDeviceMemory staging_memory;
|
||||
void *staging_map;
|
||||
|
||||
VkCommandBuffer upload_cmd;
|
||||
VkFence upload_fence;
|
||||
};
|
||||
|
||||
struct vulkan_renderer {
|
||||
struct weston_renderer base;
|
||||
struct weston_compositor *compositor;
|
||||
|
||||
bool has_wayland_surface;
|
||||
bool has_xcb_surface;
|
||||
VkInstance inst;
|
||||
|
||||
VkPhysicalDevice phys_dev;
|
||||
VkQueue queue;
|
||||
uint32_t queue_family;
|
||||
|
||||
bool has_incremental_present;
|
||||
bool has_image_drm_format_modifier;
|
||||
bool has_external_semaphore_fd;
|
||||
bool has_physical_device_drm;
|
||||
bool has_external_memory_dma_buf;
|
||||
bool has_queue_family_foreign;
|
||||
bool semaphore_import_export;
|
||||
VkDevice dev;
|
||||
|
||||
VkCommandPool cmd_pool;
|
||||
|
||||
int drm_fd; /* drm device fd */
|
||||
struct weston_drm_format_array supported_formats;
|
||||
struct wl_list dmabuf_images;
|
||||
struct wl_list dmabuf_formats;
|
||||
|
||||
struct wl_signal destroy_signal;
|
||||
struct wl_list pipeline_list;
|
||||
struct dmabuf_allocator *allocator;
|
||||
|
||||
PFN_vkCreateWaylandSurfaceKHR create_wayland_surface;
|
||||
PFN_vkCreateXcbSurfaceKHR create_xcb_surface;
|
||||
PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR get_wayland_presentation_support;
|
||||
PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR get_xcb_presentation_support;
|
||||
|
||||
PFN_vkGetImageMemoryRequirements2KHR get_image_memory_requirements2;
|
||||
PFN_vkGetMemoryFdPropertiesKHR get_memory_fd_properties;
|
||||
PFN_vkGetSemaphoreFdKHR get_semaphore_fd;
|
||||
PFN_vkImportSemaphoreFdKHR import_semaphore_fd;
|
||||
|
||||
/* This can be removed if a different shader is defined
|
||||
* to avoid requiring a valid sampler descriptor to run
|
||||
* for solids */
|
||||
struct {
|
||||
struct vulkan_renderer_texture_image image;
|
||||
VkSampler sampler;
|
||||
} dummy;
|
||||
};
|
||||
|
||||
static inline struct vulkan_renderer *
|
||||
get_renderer(struct weston_compositor *ec)
|
||||
{
|
||||
return (struct vulkan_renderer *)ec->renderer;
|
||||
}
|
||||
|
||||
static inline void pnext(void *base, void *next)
|
||||
{
|
||||
VkBaseOutStructure *b = base;
|
||||
VkBaseOutStructure *n = next;
|
||||
n->pNext = b->pNext;
|
||||
b->pNext = n;
|
||||
}
|
||||
|
||||
static inline void _check_vk_success(const char *file, int line, const char *func,
|
||||
VkResult result, const char *vk_func)
|
||||
{
|
||||
if (result == VK_SUCCESS)
|
||||
return;
|
||||
|
||||
weston_log("%s %d %s Error: %s failed with VkResult %d\n", file, line, func, vk_func, result);
|
||||
abort();
|
||||
}
|
||||
#define check_vk_success(result, vk_func) \
|
||||
_check_vk_success(__FILE__, __LINE__, __func__, (result), (vk_func))
|
||||
|
||||
void
|
||||
vulkan_pipeline_destroy(struct vulkan_renderer *vr, struct vulkan_pipeline *pipeline);
|
||||
|
||||
void
|
||||
vulkan_renderer_pipeline_list_destroy(struct vulkan_renderer *vr);
|
||||
|
||||
struct vulkan_pipeline *
|
||||
vulkan_renderer_get_pipeline(struct vulkan_renderer *vr,
|
||||
const struct vulkan_pipeline_requirements *reqs);
|
||||
|
||||
bool
|
||||
vulkan_renderer_query_dmabuf_format(struct vulkan_renderer *vr,
|
||||
const struct pixel_format_info *format);
|
||||
|
||||
#endif /* VULKAN_RENDERER_INTERNAL_H */
|
||||
4195
libweston/renderer-vulkan/vulkan-renderer.c
Normal file
4195
libweston/renderer-vulkan/vulkan-renderer.c
Normal file
File diff suppressed because it is too large
Load diff
97
libweston/renderer-vulkan/vulkan-renderer.h
Normal file
97
libweston/renderer-vulkan/vulkan-renderer.h
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright © 2025 Erico Nunes
|
||||
*
|
||||
* based on gl-renderer:
|
||||
* Copyright © 2012 John Kåre Alsaker
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial
|
||||
* portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <vulkan/vulkan_wayland.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libweston/libweston.h>
|
||||
#include "backend.h"
|
||||
#include "libweston-internal.h"
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
/**
|
||||
* Options passed to the \c display_create method of the vulkan renderer interface.
|
||||
*
|
||||
* \see struct vulkan_renderer_interface
|
||||
*/
|
||||
struct vulkan_renderer_display_options {
|
||||
struct weston_renderer_options base;
|
||||
VkInstance instance;
|
||||
void *gbm_device;
|
||||
const struct pixel_format_info **formats;
|
||||
unsigned formats_count;
|
||||
};
|
||||
|
||||
#define NUM_GBM_BOS 2
|
||||
|
||||
struct vulkan_renderer_output_options {
|
||||
struct gbm_bo *gbm_bos[NUM_GBM_BOS];
|
||||
unsigned int num_gbm_bos;
|
||||
struct weston_size fb_size;
|
||||
struct weston_geometry area;
|
||||
const struct pixel_format_info **formats;
|
||||
unsigned formats_count;
|
||||
|
||||
// xcb backend options
|
||||
void *xcb_connection;
|
||||
xcb_visualid_t xcb_visualid;
|
||||
xcb_window_t xcb_window;
|
||||
|
||||
// wayland backend options
|
||||
void *wayland_display;
|
||||
void *wayland_surface;
|
||||
};
|
||||
|
||||
struct vulkan_renderer_fbo_options {
|
||||
/** Size of the framebuffer in pixels, including borders */
|
||||
struct weston_size fb_size;
|
||||
/** Area inside the framebuffer in pixels for composited content */
|
||||
struct weston_geometry area;
|
||||
};
|
||||
|
||||
struct vulkan_renderer_interface {
|
||||
int (*display_create)(struct weston_compositor *ec,
|
||||
const struct vulkan_renderer_display_options *options);
|
||||
|
||||
int (*output_window_create)(struct weston_output *output,
|
||||
const struct vulkan_renderer_output_options *options);
|
||||
|
||||
int (*output_fbo_create)(struct weston_output *output,
|
||||
const struct vulkan_renderer_fbo_options *options);
|
||||
|
||||
void (*output_destroy)(struct weston_output *output);
|
||||
|
||||
int (*create_fence_fd)(struct weston_output *output);
|
||||
};
|
||||
57
libweston/renderer-vulkan/vulkan_fragment_shader.frag
Normal file
57
libweston/renderer-vulkan/vulkan_fragment_shader.frag
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#version 450
|
||||
|
||||
layout(binding = 1) uniform _ubo {
|
||||
uniform vec4 unicolor;
|
||||
uniform float view_alpha;
|
||||
} ubo;
|
||||
layout(binding = 2) uniform sampler2D tex;
|
||||
|
||||
layout(location = 1) in vec2 v_texcoord;
|
||||
|
||||
layout(location = 0) out vec4 fragcolor;
|
||||
|
||||
layout(constant_id = 0) const int c_variant = 0;
|
||||
layout(constant_id = 1) const bool c_input_is_premult = false;
|
||||
|
||||
#define PIPELINE_VARIANT_RGBA 1
|
||||
#define PIPELINE_VARIANT_RGBX 2
|
||||
#define PIPELINE_VARIANT_SOLID 3
|
||||
#define PIPELINE_VARIANT_EXTERNAL 4
|
||||
|
||||
vec4
|
||||
sample_input_texture()
|
||||
{
|
||||
if (c_variant == PIPELINE_VARIANT_SOLID)
|
||||
return ubo.unicolor;
|
||||
|
||||
if (c_variant == PIPELINE_VARIANT_EXTERNAL ||
|
||||
c_variant == PIPELINE_VARIANT_RGBA ||
|
||||
c_variant == PIPELINE_VARIANT_RGBX) {
|
||||
vec4 color;
|
||||
|
||||
color = texture(tex, v_texcoord);
|
||||
|
||||
if (c_variant == PIPELINE_VARIANT_RGBX)
|
||||
color.a = 1.0;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
/* Never reached, bad variant value. */
|
||||
return vec4(1.0, 0.3, 1.0, 1.0);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 color;
|
||||
|
||||
/* Electrical (non-linear) RGBA values, may be premult or not */
|
||||
color = sample_input_texture();
|
||||
|
||||
/* Ensure pre-multiplied for blending */
|
||||
if (!c_input_is_premult)
|
||||
color.rgb *= color.a;
|
||||
|
||||
color *= ubo.view_alpha;
|
||||
|
||||
fragcolor = color;
|
||||
}
|
||||
16
libweston/renderer-vulkan/vulkan_vertex_shader_surface.vert
Normal file
16
libweston/renderer-vulkan/vulkan_vertex_shader_surface.vert
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#version 450
|
||||
|
||||
layout(binding = 0) uniform _ubo {
|
||||
uniform mat4 proj;
|
||||
uniform mat4 surface_to_buffer;
|
||||
} ubo;
|
||||
|
||||
layout(location = 0) in vec2 position;
|
||||
/* layout(location = 1) in vec2 texcoord; // unused here */
|
||||
|
||||
layout(location = 1) out vec2 v_texcoord;
|
||||
|
||||
void main() {
|
||||
gl_Position = ubo.proj * vec4(position, 0.0, 1.0);
|
||||
v_texcoord = vec2(ubo.surface_to_buffer * vec4(position, 0.0, 1.0));
|
||||
}
|
||||
16
libweston/renderer-vulkan/vulkan_vertex_shader_texcoord.vert
Normal file
16
libweston/renderer-vulkan/vulkan_vertex_shader_texcoord.vert
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#version 450
|
||||
|
||||
layout(binding = 0) uniform _ubo {
|
||||
uniform mat4 proj;
|
||||
uniform mat4 surface_to_buffer;
|
||||
} ubo;
|
||||
|
||||
layout(location = 0) in vec2 position;
|
||||
layout(location = 1) in vec2 texcoord;
|
||||
|
||||
layout(location = 1) out vec2 v_texcoord;
|
||||
|
||||
void main() {
|
||||
gl_Position = ubo.proj * vec4(position, 0.0, 1.0);
|
||||
v_texcoord = texcoord;
|
||||
}
|
||||
|
|
@ -18,11 +18,11 @@ runs without any underlying windowing system. The backend uses the
|
|||
Linux KMS API to detect connected monitors. Monitor hot-plugging is
|
||||
supported. Input devices are found automatically by
|
||||
.BR udev (7).
|
||||
Compositing happens mainly in GL\ ES\ 2, initialized through EGL. It
|
||||
Compositing happens mainly in GL\ ES\ 2, initialized through EGL, or Vulkan. It
|
||||
is also possible to take advantage of hardware cursors and overlays,
|
||||
when they exist and are functional. Full-screen surfaces will be
|
||||
scanned out directly without compositing, when possible.
|
||||
Hardware accelerated clients are supported via EGL.
|
||||
Hardware accelerated clients are supported via EGL or Vulkan.
|
||||
|
||||
The backend chooses the DRM graphics device first based on seat id.
|
||||
If seat identifiers are not set, it looks for the graphics device
|
||||
|
|
@ -57,7 +57,7 @@ The actually supported pixel formats depend on the DRM driver and hardware,
|
|||
and the renderer used. Using Pixman-renderer, DRM-backend supports
|
||||
.BR xrgb8888 ", " xrgb2101010 ", " rgb565
|
||||
and some of their permutations.
|
||||
The formats supported with GL-renderer depend on the EGL and OpenGL ES 2 or 3
|
||||
The formats supported with GL-renderer or vulkan-renderer depend on the driver
|
||||
implementations. The names are case-insensitive. This setting applies only to
|
||||
.RB "outputs in SDR mode, see " eotf-mode " in " weston.ini (5).
|
||||
If the hardware platform supports hardware planes placed under the DRM primary plane
|
||||
|
|
|
|||
19
meson.build
19
meson.build
|
|
@ -123,6 +123,10 @@ config_h.set('EGL_NO_X11', '1')
|
|||
config_h.set('MESA_EGL_NO_X11_HEADERS', '1')
|
||||
config_h.set('EGL_NO_PLATFORM_SPECIFIC_TYPES', '1')
|
||||
|
||||
config_h.set('VULKAN_NO_X11', '1')
|
||||
config_h.set('MESA_VULKAN_NO_X11_HEADERS', '1')
|
||||
config_h.set('VULKAN_NO_PLATFORM_SPECIFIC_TYPES', '1')
|
||||
|
||||
config_h.set_quoted('PACKAGE_STRING', 'weston @0@'.format(version_weston))
|
||||
config_h.set_quoted('PACKAGE_VERSION', version_weston)
|
||||
config_h.set_quoted('VERSION', version_weston)
|
||||
|
|
@ -201,6 +205,21 @@ else
|
|||
dep_egl = dependency('', required: false)
|
||||
endif
|
||||
|
||||
if get_option('renderer-vulkan')
|
||||
dep_vulkan = dependency('vulkan', required: false)
|
||||
if not dep_vulkan.found()
|
||||
error('libweston + vulkan-renderer requires vulkan which was not found. Or, you can use \'-Drenderer-vulkan=false\'.')
|
||||
endif
|
||||
|
||||
prog_glslang = find_program('glslangValidator', required : false)
|
||||
if not prog_glslang.found()
|
||||
error('libweston + vulkan-renderer requires glslangValidator which was not found. Or, you can use \'-Drenderer-vulkan=false\'.')
|
||||
endif
|
||||
else
|
||||
dep_vulkan = dependency('', required: false)
|
||||
prog_glslang = find_program('', required : false)
|
||||
endif
|
||||
|
||||
|
||||
subdir('include')
|
||||
subdir('protocol')
|
||||
|
|
|
|||
|
|
@ -71,6 +71,13 @@ option(
|
|||
description: 'Weston renderer: EGL / OpenGL ES 2.x'
|
||||
)
|
||||
|
||||
option(
|
||||
'renderer-vulkan',
|
||||
type: 'boolean',
|
||||
value: true,
|
||||
description: 'Weston renderer: Vulkan'
|
||||
)
|
||||
|
||||
option(
|
||||
'xwayland',
|
||||
type: 'boolean',
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ srcs_libshared = [
|
|||
'process-util.c',
|
||||
'hash.c',
|
||||
]
|
||||
deps_libshared = [dep_wayland_client, dep_pixman, deps_for_libweston_users, dep_egl]
|
||||
deps_libshared = [dep_wayland_client, dep_pixman, deps_for_libweston_users, dep_egl, dep_vulkan]
|
||||
|
||||
lib_libshared = static_library(
|
||||
'shared',
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue