Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/egl/drivers/dri2/platform_x11_dri3.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@
#include "x11_dri3.h"
#include "loader_dri3_helper.h"

/* Keep the private EGL frontend tied to the DRI bridge structure ABI. */
const char hdmi_los_mesa_egl_bridge_abi[]
__attribute__((used, retain)) = LOADER_DRI3_SHM_BRIDGE_ABI;

static struct dri3_egl_surface *
loader_drawable_to_egl_surface(struct loader_dri3_drawable *draw)
{
Expand Down Expand Up @@ -101,12 +105,22 @@ egl_dri3_flush_drawable(struct loader_dri3_drawable *draw, unsigned flags)
dri2_flush_drawable_for_swapbuffers(disp, &dri3_surf->surf.base);
}

static int
egl_dri3_flush_drawable_with_fence_fd(struct loader_dri3_drawable *draw,
unsigned flags)
{
return loader_dri3_flush_with_fence_fd(
draw, __DRI2_FLUSH_DRAWABLE | __DRI2_FLUSH_INVALIDATE_ANCILLARY,
__DRI2_THROTTLE_SWAPBUFFER);
}

static const struct loader_dri3_vtable egl_dri3_vtable = {
.set_drawable_size = egl_dri3_set_drawable_size,
.in_current_context = egl_dri3_in_current_context,
.get_dri_context = egl_dri3_get_dri_context,
.get_dri_screen = egl_dri3_get_dri_screen,
.flush_drawable = egl_dri3_flush_drawable,
.flush_drawable_with_fence_fd = egl_dri3_flush_drawable_with_fence_fd,
};

static EGLBoolean
Expand Down
1 change: 0 additions & 1 deletion src/freedreno/drm/freedreno_bo.c
Original file line number Diff line number Diff line change
Expand Up @@ -844,4 +844,3 @@ fd_bo_state(struct fd_bo *bo)

return FD_BO_STATE_BUSY;
}

20 changes: 12 additions & 8 deletions src/freedreno/drm/freedreno_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,11 @@ fd_device_new(int fd)
* on the first capability query. When kgsl is forced (the whole kgsl stack
* exports FD_FORCE_KGSL=1), ignore the fd we were handed and open the kgsl
* GPU node directly for rendering. The fd we were handed is kept as the
* device control/identity fd (dev->control_fd, returned by fd_device_fd):
* device control/identity fd (dev->control_fd):
* it still identifies the screen for u_pipe_screen_lookup_or_create()'s
* fd-keyed cache (which compares file descriptions, so dev->fd MUST stay a
* dup of the cache key - a freshly opened kgsl fd is a different file
* description and would break cache eviction -> use-after-free) and is the
* fd handed to DRI3 clients. Only GPU submission uses the kgsl fd. */
* fd-keyed cache (which compares file descriptions, so the screen's
* get_screen_fd callback must return this control fd) and is the fd handed
* to DRI3 clients. */
if (debug_get_bool_option("FD_FORCE_KGSL", false)) {
int kgsl_fd = open("/dev/kgsl-3d0", O_RDWR | O_CLOEXEC);
if (kgsl_fd >= 0) {
Expand Down Expand Up @@ -296,9 +295,14 @@ fd_device_del(struct fd_device *dev)
int
fd_device_fd(struct fd_device *dev)
{
/* Return the control/identity fd, not the GPU submission fd. On the kgsl
* stack these differ: the screen cache and DRI3 must see the fd we were
* handed (a dup of the cache key), while GPU submission uses dev->fd. */
return dev->fd;
}

int
fd_device_control_fd(struct fd_device *dev)
{
/* The KGSL backend submits through dev->fd while the DRI/KMS winsys and
* fd-keyed screen cache must retain the DRM fd supplied by the loader. */
return dev->control_fd;
}

Expand Down
1 change: 1 addition & 0 deletions src/freedreno/drm/freedreno_drmif.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ struct fd_device *fd_device_ref(struct fd_device *dev);
void fd_device_purge(struct fd_device *dev);
void fd_device_del(struct fd_device *dev);
int fd_device_fd(struct fd_device *dev);
int fd_device_control_fd(struct fd_device *dev);

enum fd_version {
FD_VERSION_MADVISE = 1, /* kernel supports madvise */
Expand Down
3 changes: 1 addition & 2 deletions src/freedreno/drm/freedreno_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ submit_offset(struct fd_bo *bo, uint32_t offset)

struct fd_device {
int fd; /* GPU submission fd (kgsl GPU node on the kgsl stack) */
int control_fd; /* screen-cache / DRI3 identity fd; == fd unless redirected */
int control_fd; /* screen-cache / DRI/KMS fd; == fd unless redirected */
enum fd_version version;
int32_t refcnt;
uint32_t features;
Expand Down Expand Up @@ -424,7 +424,6 @@ struct fd_bo_funcs {
uint64_t (*iova)(struct fd_bo *bo);
void (*set_name)(struct fd_bo *bo, const char *fmt, va_list ap);
int (*dmabuf)(struct fd_bo *bo);

/**
* Optional hook that is called before ->destroy(). In the case of
* batch deletes (such as BO cache cleanup or cleaning up a submit)
Expand Down
15 changes: 12 additions & 3 deletions src/freedreno/drm/kgsl/kgsl_ringbuffer_sp.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,6 @@ flush_submit_list(struct list_head *submit_list)
DEBUG_MSG("merged %u submits", cmd_idx);
break;
}

list_del(&submit->node);
fd_submit_del(submit);
}

struct kgsl_cmd_syncpoint_fence sync_fence = {
Expand Down Expand Up @@ -109,6 +106,18 @@ flush_submit_list(struct list_head *submit_list)
close(fd_submit->in_fence_fd);

fail:
/* Keep merged submits alive until KGSL has consumed the command list and,
* on success, populated the shared kernel timestamp. Dropping them before
* IOCTL_KGSL_GPU_COMMAND can free BOs that the command stream still uses.
*/
foreach_submit_safe (submit, submit_list) {
if (submit == last_submit(submit_list))
break;

list_del(&submit->node);
fd_submit_del(submit);
}

return ret;
}

Expand Down
8 changes: 8 additions & 0 deletions src/gallium/drivers/freedreno/freedreno_batch.c
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,14 @@ batch_flush(struct fd_batch *batch, bool last_batch)
if (last_batch && !batch->fence)
batch->fence = fd_pipe_fence_create(batch);

/* flush_resource() can submit the drawable's writer before the frontend's
* context flush reaches fd_context_flush(). Mark that writer's fence for
* native-fd export here so the Present fence still comes from the rendering
* submission rather than a following empty submit.
*/
if (last_batch && batch->ctx->explicit_present_fence && batch->fence)
batch->fence->use_fence_fd = true;

if (batch->fence)
fd_pipe_fence_ref(&batch->ctx->last_fence, batch->fence);

Expand Down
19 changes: 19 additions & 0 deletions src/gallium/drivers/freedreno/freedreno_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ fd_context_flush(struct pipe_context *pctx, struct pipe_fence_handle **fencep,
fd_bc_dump(ctx, "need fence, last_fence=%p", ctx->last_fence);
batch = fd_context_batch(ctx);
} else if (!batch) {
ctx->explicit_present_fence = false;
return;
}

Expand Down Expand Up @@ -118,6 +119,8 @@ fd_context_flush(struct pipe_context *pctx, struct pipe_fence_handle **fencep,
fd_bc_dump(ctx, "%p: remaining:\n", ctx);

out:
ctx->explicit_present_fence = false;

if (fencep)
fd_pipe_fence_ref(fencep, fence);

Expand All @@ -134,6 +137,21 @@ fd_context_flush(struct pipe_context *pctx, struct pipe_fence_handle **fencep,
assert(pctx->get_device_reset_status(pctx) == PIPE_NO_RESET);
}

static void
fd_set_context_param(struct pipe_context *pctx, enum pipe_context_param param,
unsigned value)
{
struct fd_context *ctx = fd_context(pctx);

switch (param) {
case PIPE_CONTEXT_PARAM_EXPLICIT_PRESENT_FENCE:
ctx->explicit_present_fence = value;
break;
default:
break;
}
}

static void
fd_texture_barrier(struct pipe_context *pctx, unsigned flags) in_dt
{
Expand Down Expand Up @@ -699,6 +717,7 @@ fd_context_init(struct fd_context *ctx, struct pipe_screen *pscreen,
pctx->screen = pscreen;
pctx->priv = priv;
pctx->flush = fd_context_flush;
pctx->set_context_param = fd_set_context_param;
pctx->emit_string_marker = fd_emit_string_marker;
pctx->set_debug_callback = fd_set_debug_callback;
pctx->create_fence_fd = fd_create_pipe_fence_fd;
Expand Down
5 changes: 5 additions & 0 deletions src/gallium/drivers/freedreno/freedreno_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,11 @@ struct fd_context {
*/
struct pipe_fence_handle *last_fence dt;

/* The next context flush exports the render-completion fence directly to
* the window-system presentation path.
*/
bool explicit_present_fence;

/*
* Counter to keep track of batch's most recent update. Ie. the batch with
* the higher update count is the one that has been drawn/etc to the most
Expand Down
11 changes: 10 additions & 1 deletion src/gallium/drivers/freedreno/freedreno_resource.c
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,7 @@ fd_flush_resource(struct pipe_context *pctx, struct pipe_resource *prsc)
* to the kernel for the fence to be added to the backing GEM
* object.
*/
if (ctx->no_implicit_sync)
if (ctx->no_implicit_sync && !ctx->screen->is_kgsl)
return;

flush_resource(ctx, rsc, PIPE_MAP_READ);
Expand All @@ -703,6 +703,15 @@ fd_flush_resource(struct pipe_context *pctx, struct pipe_resource *prsc)
* way to the kernel:
*/
fd_resource_wait(ctx, rsc, FD_BO_PREP_FLUSH);

/* KGSL does not attach Mesa's tracked render fence to an exported dma-buf.
* If the window-system path is not carrying the next submission's native
* fence explicitly, wait here before handing the resource to an
* implicit-sync consumer. The explicit Present-fence path avoids this
* per-frame CPU stall.
*/
if (ctx->screen->is_kgsl && !ctx->explicit_present_fence)
fd_resource_wait(ctx, rsc, FD_BO_PREP_READ);
}

static void
Expand Down
76 changes: 75 additions & 1 deletion src/gallium/drivers/freedreno/freedreno_screen.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

#include "util/format/u_format.h"
#include "util/format/u_format_s3tc.h"
#include "util/libdrm.h"
#include "util/os_file.h"
#include "util/os_misc.h"
#include "util/u_debug.h"
#include "util/u_inlines.h"
Expand All @@ -25,6 +27,7 @@
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "drm-uapi/drm_fourcc.h"

#include "freedreno_fence.h"
Expand Down Expand Up @@ -86,6 +89,66 @@ static const struct debug_named_value fd_debug_options[] = {
};
/* clang-format on */

static void
fd_kgsl_renderonly_destroy(struct renderonly *ro)
{
if (ro->kms_fd >= 0)
close(ro->kms_fd);

util_sparse_array_finish(&ro->bo_map);
FREE(ro);
}

/*
* Android KGSL submits GPU work through /dev/kgsl-3d0 while scanout is owned
* by a separate DRM/KMS device. Model that split with Mesa's established
* renderonly contract instead of teaching the byte-oriented KGSL BO allocator
* how to manufacture display buffers. The fd supplied to this screen is the
* DRI3/KMS control fd; duplicating it preserves the GEM handle namespace used
* by the X server while render submissions continue through screen->dev->fd.
*/
static struct renderonly *
fd_kgsl_renderonly_create(int kms_fd)
{
struct renderonly *ro = CALLOC_STRUCT(renderonly);

if (!ro)
return NULL;

ro->kms_fd = os_dupfd_cloexec(kms_fd);
ro->gpu_fd = -1;
if (ro->kms_fd < 0) {
FREE(ro);
return NULL;
}

ro->create_for_resource =
renderonly_create_kms_dumb_buffer_for_resource;
ro->destroy = fd_kgsl_renderonly_destroy;
util_sparse_array_init(&ro->bo_map,
sizeof(struct renderonly_scanout), 64);
simple_mtx_init(&ro->bo_map_lock, mtx_plain);
return ro;
}

static bool
fd_kgsl_has_kms_control_fd(struct fd_device *dev)
{
drmVersionPtr version = drmGetVersion(fd_device_control_fd(dev));
/*
* Mainline names this DRM driver "msm". Qualcomm's downstream display
* stack, including the Sony pdx234 kernel, reports "msm_drm" instead.
* Both expose the KMS/dumb-buffer interface needed by renderonly.
*/
bool has_kms = version &&
(!strcmp(version->name, "msm") ||
!strcmp(version->name, "msm_drm"));

if (version)
drmFreeVersion(version);
return has_kms;
}

DEBUG_GET_ONCE_FLAGS_OPTION(fd_mesa_debug, "FD_MESA_DEBUG", fd_debug_options, 0)

int fd_mesa_debug = 0;
Expand Down Expand Up @@ -937,7 +1000,7 @@ static int
fd_screen_get_fd(struct pipe_screen *pscreen)
{
struct fd_screen *screen = fd_screen(pscreen);
return fd_device_fd(screen->dev);
return fd_device_control_fd(screen->dev);
}

static void
Expand Down Expand Up @@ -985,6 +1048,17 @@ fd_screen_create(int fd,
screen->dev = dev;
screen->is_kgsl = fd_get_features(dev) & FD_FEATURE_KGSL;
screen->kgsl_dmabuf = screen->is_kgsl && fd_kgsl_dmabuf_enabled();
if (!ro && screen->is_kgsl && fd_kgsl_has_kms_control_fd(dev) &&
debug_get_bool_option("FD_KGSL_RENDERONLY", false)) {
ro = fd_kgsl_renderonly_create(fd_device_control_fd(dev));
if (!ro) {
mesa_loge("freedreno/kgsl: failed to create KMS renderonly screen");
fd_device_del(dev);
FREE(screen);
return NULL;
}
mesa_logi("freedreno/kgsl: using Mesa renderonly for KMS scanout");
}
screen->ro = ro;

// maybe this should be in context?
Expand Down
2 changes: 1 addition & 1 deletion src/gallium/frontends/dri/dri2.c
Original file line number Diff line number Diff line change
Expand Up @@ -1548,7 +1548,7 @@ dri2_blit_image(struct dri_context *ctx, struct dri_image *dst, struct dri_image
{
struct pipe_context *pipe = ctx->st->pipe;
struct pipe_screen *screen;
struct pipe_fence_handle *fence;
struct pipe_fence_handle *fence = NULL;
struct pipe_blit_info blit;

if (!dst || !src)
Expand Down
Loading