iris: Add fence support using drm_syncobj

This commit is contained in:
Chris Wilson 2018-11-07 11:50:02 +00:00 committed by Kenneth Graunke
parent db199d9d07
commit f459c56be6
5 changed files with 258 additions and 36 deletions

View File

@ -34,23 +34,6 @@
#include "iris_screen.h"
#include "common/gen_sample_positions.h"
static void
iris_flush(struct pipe_context *ctx,
struct pipe_fence_handle **fence,
unsigned flags)
{
struct iris_context *ice = (struct iris_context *)ctx;
iris_batch_flush(&ice->render_batch);
if (ice->compute_batch.contains_draw)
iris_batch_flush(&ice->compute_batch);
// XXX: bogus!!!
if (fence)
*fence = NULL;
}
/**
* For debugging purposes, this returns a time in seconds.
*/
@ -182,12 +165,12 @@ iris_create_context(struct pipe_screen *pscreen, void *priv, unsigned flags)
ctx->const_uploader = ctx->stream_uploader;
ctx->destroy = iris_destroy_context;
ctx->flush = iris_flush;
ctx->set_debug_callback = iris_set_debug_callback;
ctx->get_sample_position = iris_get_sample_position;
ice->shaders.urb_size = devinfo->urb.size;
iris_init_context_fence_functions(ctx);
iris_init_blit_functions(ctx);
iris_init_clear_functions(ctx);
iris_init_program_functions(ctx);

View File

@ -31,6 +31,7 @@
#include "intel/compiler/brw_compiler.h"
#include "iris_batch.h"
#include "iris_binder.h"
#include "iris_fence.h"
#include "iris_resource.h"
#include "iris_screen.h"

View File

@ -30,6 +30,7 @@
#include "iris_batch.h"
#include "iris_bufmgr.h"
#include "iris_context.h"
#include "iris_fence.h"
#include "iris_screen.h"
@ -105,3 +106,254 @@ iris_batch_add_syncpt(struct iris_batch *batch,
*store = NULL;
iris_syncpt_reference(batch->screen, store, syncpt);
}
/* ------------------------------------------------------------------- */
struct pipe_fence_handle {
struct pipe_reference ref;
struct iris_syncpt *syncpt[IRIS_BATCH_COUNT];
unsigned count;
};
static void
iris_fence_destroy(struct pipe_screen *p_screen,
struct pipe_fence_handle *fence)
{
struct iris_screen *screen = (struct iris_screen *)p_screen;
for (unsigned i = 0; i < fence->count; i++)
iris_syncpt_reference(screen, &fence->syncpt[i], NULL);
free(fence);
}
static void
iris_fence_reference(struct pipe_screen *p_screen,
struct pipe_fence_handle **dst,
struct pipe_fence_handle *src)
{
if (pipe_reference(&(*dst)->ref, &src->ref))
iris_fence_destroy(p_screen, *dst);
*dst = src;
}
static bool
check_syncpt(struct pipe_screen *p_screen,
struct iris_syncpt *syncpt)
{
if (!syncpt)
return false;
struct iris_screen *screen = (struct iris_screen *)p_screen;
struct drm_syncobj_wait args = {
.handles = (uintptr_t)&syncpt->handle,
.count_handles = 1,
};
return drm_ioctl(screen->fd, DRM_IOCTL_SYNCOBJ_WAIT, &args);
}
static void
iris_fence_flush(struct pipe_context *ctx,
struct pipe_fence_handle **out_fence,
unsigned flags)
{
struct iris_screen *screen = (void *) ctx->screen;
struct iris_context *ice = (struct iris_context *)ctx;
struct iris_batch *batch[IRIS_BATCH_COUNT] = {
&ice->compute_batch,
&ice->render_batch
};
/* XXX PIPE_FLUSH_DEFERRED */
for (unsigned i = 0; i < ARRAY_SIZE(batch); i++)
iris_batch_flush(batch[i]);
if (!out_fence)
return;
struct pipe_fence_handle *fence = calloc(1, sizeof(*fence));
if (!fence)
return;
pipe_reference_init(&fence->ref, 1);
for (unsigned b = 0; b < ARRAY_SIZE(batch); b++) {
if (!check_syncpt(ctx->screen, batch[b]->last_syncpt))
continue;
iris_syncpt_reference(screen, &fence->syncpt[fence->count++],
batch[b]->last_syncpt);
}
*out_fence = fence;
}
static void
iris_fence_await(struct pipe_context *ctx,
struct pipe_fence_handle *fence)
{
struct iris_context *ice = (struct iris_context *)ctx;
struct iris_batch *batch[IRIS_BATCH_COUNT] = {
&ice->compute_batch,
&ice->render_batch
};
for (unsigned b = 0; b < ARRAY_SIZE(batch); b++) {
for (unsigned i = 0; i < fence->count; i++) {
iris_batch_add_syncpt(batch[b], fence->syncpt[i],
I915_EXEC_FENCE_WAIT);
}
}
}
#define NSEC_PER_SEC (1000 * USEC_PER_SEC)
#define USEC_PER_SEC (1000 * MSEC_PER_SEC)
#define MSEC_PER_SEC (1000)
static uint64_t
rel2abs(uint64_t timeout)
{
struct timespec ts;
uint64_t now;
if (!timeout)
return 0;
if (timeout == PIPE_TIMEOUT_INFINITE)
return INT64_MAX;
clock_gettime(CLOCK_MONOTONIC, &ts);
now = ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec;
if (now > INT64_MAX - timeout)
return INT64_MAX;
return now + timeout;
}
static boolean
iris_fence_finish(struct pipe_screen *p_screen,
struct pipe_context *ctx,
struct pipe_fence_handle *fence,
uint64_t timeout)
{
struct iris_screen *screen = (struct iris_screen *)p_screen;
if (!fence->count)
return true;
uint32_t handles[ARRAY_SIZE(fence->syncpt)];
for (unsigned i = 0; i < fence->count; i++)
handles[i] = fence->syncpt[i]->handle;
struct drm_syncobj_wait args = {
.handles = (uintptr_t)handles,
.count_handles = fence->count,
.timeout_nsec = rel2abs(timeout), /* XXX */
.flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL
};
return drm_ioctl(screen->fd, DRM_IOCTL_SYNCOBJ_WAIT, &args) == 0;
}
#ifndef SYNC_IOC_MAGIC
/* duplicated from linux/sync_file.h to avoid build-time dependency
* on new (v4.7) kernel headers. Once distro's are mostly using
* something newer than v4.7 drop this and #include <linux/sync_file.h>
* instead.
*/
struct sync_merge_data {
char name[32];
__s32 fd2;
__s32 fence;
__u32 flags;
__u32 pad;
};
#define SYNC_IOC_MAGIC '>'
#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data)
#endif
static int
sync_merge_fd(int sync_fd, int new_fd)
{
if (sync_fd == -1)
return new_fd;
if (new_fd == -1)
return sync_fd;
struct sync_merge_data args = {
.name = "iris fence",
.fd2 = new_fd,
.fence = -1,
};
drm_ioctl(sync_fd, SYNC_IOC_MERGE, &args);
close(new_fd);
close(sync_fd);
return args.fence;
}
static int
iris_fence_get_fd(struct pipe_screen *p_screen,
struct pipe_fence_handle *fence)
{
struct iris_screen *screen = (struct iris_screen *)p_screen;
int fd = -1;
for (unsigned i = 0; i < fence->count; i++) {
struct drm_syncobj_handle args = {
.handle = fence->syncpt[i]->handle,
.flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE,
.fd = -1,
};
drm_ioctl(screen->fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
fd = sync_merge_fd(fd, args.fd);
}
return fd;
}
static void
iris_fence_create_fd(struct pipe_context *ctx,
struct pipe_fence_handle **out,
int fd,
enum pipe_fd_type type)
{
assert(type == PIPE_FD_TYPE_NATIVE_SYNC);
struct iris_screen *screen = (struct iris_screen *)ctx->screen;
struct drm_syncobj_handle args = {
.flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE,
.fd = fd,
};
drm_ioctl(screen->fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args);
struct iris_syncpt *syncpt = malloc(sizeof(*syncpt));
syncpt->handle = args.handle;
pipe_reference_init(&syncpt->ref, 1);
struct pipe_fence_handle *fence = malloc(sizeof(*fence));
pipe_reference_init(&fence->ref, 1);
fence->syncpt[0] = syncpt;
fence->count = 1;
*out = fence;
}
void
iris_init_screen_fence_functions(struct pipe_screen *screen)
{
screen->fence_reference = iris_fence_reference;
screen->fence_finish = iris_fence_finish;
screen->fence_get_fd = iris_fence_get_fd;
}
void
iris_init_context_fence_functions(struct pipe_context *ctx)
{
ctx->flush = iris_fence_flush;
ctx->create_fence_fd = iris_fence_create_fd;
ctx->fence_server_sync = iris_fence_await;
}

View File

@ -33,6 +33,9 @@ struct iris_syncpt {
uint32_t handle;
};
void iris_init_context_fence_functions(struct pipe_context *ctx);
void iris_init_screen_fence_functions(struct pipe_screen *screen);
struct iris_syncpt *iris_create_syncpt(struct iris_screen *screen);
void iris_syncpt_destroy(struct iris_screen *, struct iris_syncpt *);
void iris_batch_add_syncpt(struct iris_batch *batch,

View File

@ -459,22 +459,6 @@ iris_destroy_screen(struct pipe_screen *pscreen)
ralloc_free(screen);
}
static void
iris_fence_reference(struct pipe_screen *screen,
struct pipe_fence_handle **ptr,
struct pipe_fence_handle *fence)
{
}
static boolean
iris_fence_finish(struct pipe_screen *screen,
struct pipe_context *ctx,
struct pipe_fence_handle *fence,
uint64_t timeout)
{
return true;
}
static void
iris_query_memory_info(struct pipe_screen *pscreen,
struct pipe_memory_info *info)
@ -596,6 +580,7 @@ iris_screen_create(int fd)
struct pipe_screen *pscreen = &screen->base;
iris_init_screen_fence_functions(pscreen);
iris_init_screen_resource_functions(pscreen);
pscreen->destroy = iris_destroy_screen;
@ -611,8 +596,6 @@ iris_screen_create(int fd)
pscreen->context_create = iris_create_context;
pscreen->flush_frontbuffer = iris_flush_frontbuffer;
pscreen->get_timestamp = iris_get_timestamp;
pscreen->fence_reference = iris_fence_reference;
pscreen->fence_finish = iris_fence_finish;
pscreen->query_memory_info = iris_query_memory_info;
return pscreen;