diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2014-05-08 16:25:32 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2014-06-02 08:32:11 +0100 |
commit | d8eb87f84f88ad2df42c6fed1d93df76589a14e3 (patch) | |
tree | e24b21ab5aa0fcdda05428595844c232cbfac778 | |
parent | 0fbe8995d51b4643f1cf06c07da8b4b5ac5ae7c3 (diff) |
sna: Add support for DRI3
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | src/sna/Makefile.am | 8 | ||||
-rw-r--r-- | src/sna/kgem.c | 54 | ||||
-rw-r--r-- | src/sna/kgem.h | 8 | ||||
-rw-r--r-- | src/sna/sna.h | 31 | ||||
-rw-r--r-- | src/sna/sna_accel.c | 64 | ||||
-rw-r--r-- | src/sna/sna_display.c | 4 | ||||
-rw-r--r-- | src/sna/sna_dri2.c | 38 | ||||
-rw-r--r-- | src/sna/sna_dri3.c | 383 | ||||
-rw-r--r-- | src/sna/sna_driver.c | 83 |
9 files changed, 618 insertions, 55 deletions
diff --git a/src/sna/Makefile.am b/src/sna/Makefile.am index a3349825..aa3f6a58 100644 --- a/src/sna/Makefile.am +++ b/src/sna/Makefile.am @@ -109,11 +109,17 @@ libsna_la_SOURCES = \ $(NULL) if DRI2 -AM_CFLAGS += @DRI2_CFLAGS@ +AM_CFLAGS += $(DRI2_CFLAGS) libsna_la_SOURCES += sna_dri2.c libsna_la_LIBADD += $(DRI2_LIBS) @CLOCK_GETTIME_LIBS@ endif +if DRI3 +AM_CFLAGS += $(DRI3_CFLAGS) +libsna_la_SOURCES += sna_dri3.c +libsna_la_LIBADD += $(DRI3_LIBS) +endif + if XVMC libsna_la_SOURCES += \ sna_video_hwmc.h \ diff --git a/src/sna/kgem.c b/src/sna/kgem.c index 17b5b1ac..3eb63d8f 100644 --- a/src/sna/kgem.c +++ b/src/sna/kgem.c @@ -1619,6 +1619,9 @@ static uint32_t kgem_surface_size(struct kgem *kgem, *pitch = ALIGN(width * bpp / 8, tile_width); height = ALIGN(height, tile_height); + DBG(("%s: tile_width=%d, tile_height=%d => aligned pitch=%d, height=%d\n", + __FUNCTION__, tile_width, tile_height, *pitch, height)); + if (kgem->gen >= 040) return PAGE_ALIGN(*pitch * height); @@ -1649,6 +1652,47 @@ static uint32_t kgem_surface_size(struct kgem *kgem, return tile_width; } +bool kgem_check_surface_size(struct kgem *kgem, + uint32_t width, + uint32_t height, + uint32_t bpp, + uint32_t tiling, + uint32_t pitch, + uint32_t size) +{ + uint32_t min_size, min_pitch; + int tile_width, tile_height, tile_size; + + DBG(("%s(width=%d, height=%d, bpp=%d, tiling=%d, pitch=%d, size=%d)\n", + __FUNCTION__, width, height, bpp, tiling, pitch, size)); + + if (pitch & 3) + return false; + + min_size = kgem_surface_size(kgem, kgem->has_relaxed_fencing, 0, + width, height, bpp, tiling, + &min_pitch); + + DBG(("%s: min_pitch=%d, min_size=%d\n", __FUNCTION__, min_pitch, min_size)); + + if (size < min_size) + return false; + + if (pitch < min_pitch) + return false; + + kgem_get_tile_size(kgem, tiling, min_pitch, + &tile_width, &tile_height, &tile_size); + + DBG(("%s: tile_width=%d, tile_size=%d\n", __FUNCTION__, tile_width, tile_size)); + if (pitch & (tile_width - 1)) + return false; + if (size & (tile_size - 1)) + return false; + + return true; +} + static uint32_t kgem_aligned_height(struct kgem *kgem, uint32_t height, uint32_t tiling) { @@ -3848,8 +3892,16 @@ struct kgem_bo *kgem_create_for_prime(struct kgem *kgem, int name, uint32_t size /* Query actual size, overriding specified if available */ seek = lseek(args.fd, 0, SEEK_END); - if (seek != -1) + DBG(("%s: estimated size=%ld, actual=%lld\n", + __FUNCTION__, (long)size, (long long)seek)); + if (seek != -1) { + if (size > seek) { + DBG(("%s(name=%d) estimated required size [%d] is larger than actual [%ld]\n", __FUNCTION__, name, size, (long)seek)); + gem_close(kgem->fd, args.handle); + return NULL; + } size = seek; + } DBG(("%s: new handle=%d, tiling=%d\n", __FUNCTION__, args.handle, tiling.tiling_mode)); diff --git a/src/sna/kgem.h b/src/sna/kgem.h index a9fb9394..6e61909e 100644 --- a/src/sna/kgem.h +++ b/src/sna/kgem.h @@ -268,6 +268,14 @@ unsigned kgem_can_create_2d(struct kgem *kgem, int width, int height, int depth) #define KGEM_CAN_CREATE_LARGE 0x4 #define KGEM_CAN_CREATE_GTT 0x8 +bool kgem_check_surface_size(struct kgem *kgem, + uint32_t width, + uint32_t height, + uint32_t bpp, + uint32_t tiling, + uint32_t pitch, + uint32_t size); + struct kgem_bo * kgem_replace_bo(struct kgem *kgem, struct kgem_bo *src, diff --git a/src/sna/sna.h b/src/sna/sna.h index d40ccf42..5114927d 100644 --- a/src/sna/sna.h +++ b/src/sna/sna.h @@ -61,10 +61,14 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include <drm.h> #include <i915_drm.h> -#ifdef HAVE_DRI2_H +#if HAVE_DRI2 #include <dri2.h> #endif +#if HAVE_DRI3 +#include <misync.h> +#endif + #if HAVE_UDEV #include <libudev.h> #endif @@ -161,6 +165,9 @@ struct sna_pixmap { uint8_t cpu :1; }; +#define IS_STATIC_PTR(ptr) ((uintptr_t)(ptr) & 1) +#define MAKE_STATIC_PTR(ptr) ((void*)((uintptr_t)(ptr) | 1)) + struct sna_glyph { PicturePtr atlas; struct sna_coordinate coordinate; @@ -324,6 +331,15 @@ struct sna { #endif } dri2; + struct sna_dri3 { + bool available; + bool open; +#if HAVE_DRI3 + SyncScreenCreateFenceFunc create_fence; + struct list pixmaps; +#endif + } dri3; + struct sna_xv { XvAdaptorPtr adaptors; int num_adaptors; @@ -496,7 +512,7 @@ static inline uint64_t ust64(int tv_sec, int tv_usec) return (uint64_t)tv_sec * 1000000 + tv_usec; } -#if HAVE_DRI2_H +#if HAVE_DRI2 bool sna_dri2_open(struct sna *sna, ScreenPtr pScreen); void sna_dri2_page_flip_handler(struct sna *sna, struct drm_event_vblank *event); void sna_dri2_vblank_handler(struct sna *sna, struct drm_event_vblank *event); @@ -514,6 +530,14 @@ static inline void sna_dri2_reset_scanout(struct sna *sna) { } static inline void sna_dri2_close(struct sna *sna, ScreenPtr pScreen) { } #endif +#if HAVE_DRI3 +bool sna_dri3_open(struct sna *sna, ScreenPtr pScreen); +void sna_dri3_close(struct sna *sna, ScreenPtr pScreen); +#else +static inline bool sna_dri3_open(struct sna *sna, ScreenPtr pScreen) { return false; } +static inline void sna_dri3_close(struct sna *sna, ScreenPtr pScreen) { } +#endif + extern bool sna_crtc_set_sprite_rotation(xf86CrtcPtr crtc, uint32_t rotation); extern int sna_crtc_to_pipe(xf86CrtcPtr crtc); extern uint32_t sna_crtc_to_sprite(xf86CrtcPtr crtc); @@ -569,7 +593,7 @@ get_drawable_dy(DrawablePtr drawable) return 0; } -bool sna_pixmap_attach_to_bo(PixmapPtr pixmap, struct kgem_bo *bo); +struct sna_pixmap *sna_pixmap_attach_to_bo(PixmapPtr pixmap, struct kgem_bo *bo); static inline bool sna_pixmap_is_scanout(struct sna *sna, PixmapPtr pixmap) { return (pixmap == sna->front && @@ -929,6 +953,7 @@ void sna_accel_create(struct sna *sna); void sna_accel_block_handler(struct sna *sna, struct timeval **tv); void sna_accel_wakeup_handler(struct sna *sna); void sna_accel_watch_flush(struct sna *sna, int enable); +void sna_accel_flush(struct sna *sna); void sna_accel_close(struct sna *sna); void sna_accel_free(struct sna *sna); diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c index 869427df..a02c5eb2 100644 --- a/src/sna/sna_accel.c +++ b/src/sna/sna_accel.c @@ -108,9 +108,6 @@ #define NO_TILE_8x8 0 #define NO_STIPPLE_8x8 0 -#define IS_STATIC_PTR(ptr) ((uintptr_t)(ptr) & 1) -#define MAKE_STATIC_PTR(ptr) ((void*)((uintptr_t)(ptr) | 1)) - #define IS_COW_OWNER(ptr) ((uintptr_t)(ptr) & 1) #define MAKE_COW_OWNER(ptr) ((void*)((uintptr_t)(ptr) | 1)) #define COW(ptr) (void *)((uintptr_t)(ptr) & ~1) @@ -562,8 +559,8 @@ static void __sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv) sna->debug_memory.cpu_bo_allocs--; sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo); #endif - if (!priv->cpu_bo->reusable) { - assert(priv->cpu_bo->flush == true); + if (priv->cpu_bo->flush) { + assert(!priv->cpu_bo->reusable); kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); sna_accel_watch_flush(sna, -1); } @@ -712,6 +709,7 @@ static struct sna_pixmap * _sna_pixmap_init(struct sna_pixmap *priv, PixmapPtr pixmap) { list_init(&priv->flush_list); + list_init(&priv->cow_list); priv->source_count = SOURCE_BIAS; priv->pixmap = pixmap; @@ -747,26 +745,37 @@ static struct sna_pixmap *sna_pixmap_attach(PixmapPtr pixmap) return _sna_pixmap_init(priv, pixmap); } -bool sna_pixmap_attach_to_bo(PixmapPtr pixmap, struct kgem_bo *bo) +struct sna_pixmap *sna_pixmap_attach_to_bo(PixmapPtr pixmap, struct kgem_bo *bo) { struct sna_pixmap *priv; assert(bo); + assert(bo->proxy == NULL); + assert(bo->unique_id); priv = sna_pixmap_attach(pixmap); if (!priv) - return false; + return NULL; + + DBG(("%s: attaching %s handle=%d to pixmap=%ld\n", + __FUNCTION__, bo->snoop ? "CPU" : "GPU", bo->handle, pixmap->drawable.serialNumber)); assert(!priv->mapped); assert(!priv->move_to_gpu); - priv->gpu_bo = kgem_bo_reference(bo); - assert(priv->gpu_bo->proxy == NULL); - sna_damage_all(&priv->gpu_damage, - pixmap->drawable.width, - pixmap->drawable.height); + if (bo->snoop) { + priv->cpu_bo = bo; + sna_damage_all(&priv->cpu_damage, + pixmap->drawable.width, + pixmap->drawable.height); + } else { + priv->gpu_bo = bo; + sna_damage_all(&priv->gpu_damage, + pixmap->drawable.width, + pixmap->drawable.height); + } - return true; + return priv; } static int bits_per_pixel(int depth) @@ -1402,6 +1411,7 @@ static void __sna_free_pixmap(struct sna *sna, PixmapPtr pixmap, struct sna_pixmap *priv) { + DBG(("%s(pixmap=%ld)\n", __FUNCTION__, pixmap->drawable.serialNumber)); list_del(&priv->flush_list); assert(priv->gpu_damage == NULL); @@ -1455,11 +1465,11 @@ static Bool sna_destroy_pixmap(PixmapPtr pixmap) DBG(("%s: pixmap=%ld discarding cow, refcnt=%d\n", __FUNCTION__, pixmap->drawable.serialNumber, cow->refcnt)); assert(cow->refcnt); - list_del(&priv->cow_list); if (!--cow->refcnt) free(cow); priv->cow = NULL; } + list_del(&priv->cow_list); if (priv->move_to_gpu) (void)priv->move_to_gpu(sna, priv, 0); @@ -1472,6 +1482,8 @@ static Bool sna_destroy_pixmap(PixmapPtr pixmap) } if (priv->shm && kgem_bo_is_busy(priv->cpu_bo)) { + DBG(("%s: deferring release of active SHM pixmap=%ld\n", + __FUNCTION__, pixmap->drawable.serialNumber)); sna_add_flush_pixmap(sna, priv, priv->cpu_bo); kgem_bo_submit(&sna->kgem, priv->cpu_bo); /* XXX ShmDetach */ } else @@ -1813,7 +1825,8 @@ sna_pixmap_undo_cow(struct sna *sna, struct sna_pixmap *priv, unsigned flags) assert(priv->gpu_bo == cow->bo); assert(cow->refcnt); - list_del(&priv->cow_list); + if (!IS_COW_OWNER(priv->cow)) + list_del(&priv->cow_list); if (!--cow->refcnt) { DBG(("%s: freeing cow\n", __FUNCTION__)); @@ -1960,7 +1973,6 @@ sna_pixmap_make_cow(struct sna *sna, cow->bo->handle)); src_priv->cow = MAKE_COW_OWNER(cow); - list_init(&src_priv->cow_list); } if (cow == COW(dst_priv->cow)) { @@ -16509,11 +16521,8 @@ static Bool sna_change_window_attributes(WindowPtr win, unsigned long mask) return ret; } -static void -sna_accel_flush_callback(CallbackListPtr *list, - pointer user_data, pointer call_data) +void sna_accel_flush(struct sna *sna) { - struct sna *sna = user_data; struct sna_pixmap *priv; /* XXX we should be able to reduce the frequency of flushes further @@ -16559,6 +16568,13 @@ sna_accel_flush_callback(CallbackListPtr *list, kgem_submit(&sna->kgem); } +static void +sna_accel_flush_callback(CallbackListPtr *list, + pointer user_data, pointer call_data) +{ + sna_accel_flush(user_data); +} + static struct sna_pixmap *sna_accel_scanout(struct sna *sna) { struct sna_pixmap *priv; @@ -16673,7 +16689,7 @@ static void timer_enable(struct sna *sna, int whom, int interval) DBG(("%s (time=%ld), starting timer %d\n", __FUNCTION__, (long)TIME, whom)); } -static bool sna_accel_do_flush(struct sna *sna) +static bool sna_scanout_do_flush(struct sna *sna) { struct sna_pixmap *priv; int interval; @@ -16862,7 +16878,7 @@ skip: #endif } -static void sna_accel_flush(struct sna *sna) +static void sna_scanout_flush(struct sna *sna) { struct sna_pixmap *priv = sna_accel_scanout(sna); bool busy; @@ -17355,8 +17371,8 @@ void sna_accel_block_handler(struct sna *sna, struct timeval **tv) } restart: - if (sna_accel_do_flush(sna)) - sna_accel_flush(sna); + if (sna_scanout_do_flush(sna)) + sna_scanout_flush(sna); assert(sna_accel_scanout(sna) == NULL || sna_accel_scanout(sna)->gpu_bo->exec == NULL || sna->timer_active & (1<<(FLUSH_TIMER))); diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c index 6803409e..2b7e4731 100644 --- a/src/sna/sna_display.c +++ b/src/sna/sna_display.c @@ -5356,8 +5356,10 @@ sna_crtc_redisplay__composite(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo bo->pitch, NULL)) goto free_pixmap; - if (!sna_pixmap_attach_to_bo(pixmap, bo)) + if (!sna_pixmap_attach_to_bo(pixmap, kgem_bo_reference(bo))) { + kgem_bo_destroy(&sna->kgem, bo); goto free_pixmap; + } src = CreatePicture(None, &sna->front->drawable, format, 0, NULL, serverClient, &error); diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c index 27840140..317f5985 100644 --- a/src/sna/sna_dri2.c +++ b/src/sna/sna_dri2.c @@ -309,8 +309,8 @@ static struct kgem_bo *sna_pixmap_set_dri(struct sna *sna, __FUNCTION__, pixmap->drawable.serialNumber)); priv = sna_pixmap(pixmap); - if (priv != NULL && priv->shm) { - DBG(("%s: SHM Pixmap, BadAlloc\n", __FUNCTION__)); + if (priv != NULL && IS_STATIC_PTR(priv->ptr) && priv->cpu_bo) { + DBG(("%s: SHM or unattached Pixmap, BadAlloc\n", __FUNCTION__)); return NULL; } @@ -669,7 +669,7 @@ static void set_bo(PixmapPtr pixmap, struct kgem_bo *bo) assert(bo->proxy == NULL); assert(bo->flush); assert(priv->pinned & PIN_DRI2); - assert((priv->pinned & PIN_PRIME) == 0); + assert((priv->pinned & (PIN_PRIME | PIN_DRI3)) == 0); assert(priv->flush); if (priv->cow && priv->gpu_bo != bo) @@ -2601,32 +2601,36 @@ namecmp(const char *s1, const char *s2) return c1 - c2; } -static bool is_bool(const char *str) +static bool is_level(const char **str) { - if (str == NULL) - return true; + const char *s = *str; + char *end; + unsigned val; - if (*str == '\0') + if (s == NULL || *s == '\0') return true; - if (namecmp(str, "1") == 0) - return true; - if (namecmp(str, "on") == 0) + if (namecmp(s, "on") == 0) return true; - if (namecmp(str, "true") == 0) + if (namecmp(s, "true") == 0) return true; - if (namecmp(str, "yes") == 0) + if (namecmp(s, "yes") == 0) return true; - if (namecmp(str, "0") == 0) + if (namecmp(s, "0") == 0) return true; - if (namecmp(str, "off") == 0) + if (namecmp(s, "off") == 0) return true; - if (namecmp(str, "false") == 0) + if (namecmp(s, "false") == 0) return true; - if (namecmp(str, "no") == 0) + if (namecmp(s, "no") == 0) return true; + val = strtoul(s, &end, 0); + if (val && *end == '\0') + return true; + if (val && *end == ':') + *str = end + 1; return false; } @@ -2634,7 +2638,7 @@ static const char *dri_driver_name(struct sna *sna) { const char *s = xf86GetOptValString(sna->Options, OPTION_DRI); - if (is_bool(s)) { + if (is_level(&s)) { if (sna->kgem.gen < 030) return has_i830_dri() ? "i830" : "i915"; else if (sna->kgem.gen < 040) diff --git a/src/sna/sna_dri3.c b/src/sna/sna_dri3.c new file mode 100644 index 00000000..0e58e790 --- /dev/null +++ b/src/sna/sna_dri3.c @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2014 Intel Corporation + * + * 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. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <xf86drm.h> + +#include "sna.h" + +#include <xf86.h> +#include <dri3.h> +#include <misyncshm.h> +#include <misyncstr.h> + +static DevPrivateKeyRec sna_sync_fence_private_key; +struct sna_sync_fence { + SyncFenceSetTriggeredFunc set_triggered; +}; + +static inline struct sna_sync_fence *sna_sync_fence(SyncFence *fence) +{ + return dixLookupPrivate(&fence->devPrivates, &sna_sync_fence_private_key); +} + +static void sna_sync_flush(struct sna *sna, struct sna_pixmap *priv) +{ + struct kgem_bo *bo = NULL; + + DBG(("%s(pixmap=%ld)\n", __FUNCTION__, priv->pixmap->drawable.serialNumber)); + assert(priv); + + if (priv->pinned & PIN_DRI3) { + assert(priv->gpu_bo); + assert(priv->pinned & PIN_DRI3); + DBG(("%s: flushing prime GPU bo, handle=%ld\n", __FUNCTION__, priv->gpu_bo->handle)); + if (sna_pixmap_move_to_gpu(priv->pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE)) { + sna_damage_all(&priv->gpu_damage, + priv->pixmap->drawable.width, + priv->pixmap->drawable.height); + bo = priv->gpu_bo; + } + } else { + assert(priv->cpu_bo); + assert(IS_STATIC_PTR(priv->ptr)); + DBG(("%s: flushing prime CPU bo, handle=%ld\n", __FUNCTION__, priv->cpu_bo->handle)); + if (sna_pixmap_move_to_cpu(priv->pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT)) + bo = priv->cpu_bo; + } + + if (bo != NULL) { + kgem_bo_submit(&sna->kgem, bo); + kgem_bo_unclean(&sna->kgem, bo); + } +} + +static void +sna_sync_fence_set_triggered(SyncFence *fence) +{ + struct sna *sna = to_sna_from_screen(fence->pScreen); + struct sna_sync_fence *sna_fence = sna_sync_fence(fence); + DrawablePtr draw = NULL; + + DBG(("%s()\n", __FUNCTION__)); + +#if 0 + draw = miSyncShmFenceGetDrawable(fence); +#endif + if (draw) { + DBG(("%s: associated pixmap=%ld\n", __FUNCTION__, get_drawable_pixmap(draw)->drawable.serialNumber)); + sna_sync_flush(sna, sna_pixmap(get_drawable_pixmap(draw))); + } else { /* SyncFence are currently per-screen, sigh */ + struct sna_pixmap *priv; + + DBG(("%s: flushing all DRI3 pixmaps\n", __FUNCTION__)); + list_for_each_entry(priv, &sna->dri3.pixmaps, cow_list) + sna_sync_flush(sna, priv); + + sna_accel_flush(sna); + } + + DBG(("%s: complete, chaining up\n", __FUNCTION__)); + fence->funcs.SetTriggered = sna_fence->set_triggered; + sna_fence->set_triggered(fence); + sna_fence->set_triggered = fence->funcs.SetTriggered; + fence->funcs.SetTriggered = sna_sync_fence_set_triggered; +} + +static void +sna_sync_create_fence(ScreenPtr screen, SyncFence *fence, Bool initially_triggered) +{ + struct sna *sna = to_sna_from_screen(screen); + SyncScreenFuncsPtr funcs = miSyncGetScreenFuncs(screen); + + DBG(("%s()\n", __FUNCTION__)); + + funcs->CreateFence = sna->dri3.create_fence; + sna->dri3.create_fence(screen, fence, initially_triggered); + sna->dri3.create_fence = funcs->CreateFence; + funcs->CreateFence = sna_sync_create_fence; + + sna_sync_fence(fence)->set_triggered = fence->funcs.SetTriggered; + fence->funcs.SetTriggered = sna_sync_fence_set_triggered; +} + +static bool +sna_sync_open(struct sna *sna, ScreenPtr screen) +{ + SyncScreenFuncsPtr funcs; + + DBG(("%s()\n", __FUNCTION__)); + + if (!miSyncShmScreenInit(screen)) + return false; + + if (!dixPrivateKeyRegistered(&sna_sync_fence_private_key)) { + if (!dixRegisterPrivateKey(&sna_sync_fence_private_key, + PRIVATE_SYNC_FENCE, + sizeof(struct sna_sync_fence))) + return false; + } + + funcs = miSyncGetScreenFuncs(screen); + sna->dri3.create_fence = funcs->CreateFence; + funcs->CreateFence = sna_sync_create_fence; + + return true; +} + +static int sna_dri3_open_device(ScreenPtr screen, + RRProviderPtr provider, + int *out) +{ + int fd; + + DBG(("%s()\n", __FUNCTION__)); + fd = intel_get_client_fd(xf86ScreenToScrn(screen)); + if (fd < 0) + return -fd; + + *out = fd; + return Success; +} + +static PixmapPtr sna_dri3_pixmap_from_fd(ScreenPtr screen, + int fd, + CARD16 width, + CARD16 height, + CARD16 stride, + CARD8 depth, + CARD8 bpp) +{ + struct sna *sna = to_sna_from_screen(screen); + PixmapPtr pixmap; + struct sna_pixmap *priv; + struct kgem_bo *bo; + + DBG(("%s(fd=%d, width=%d, height=%d, stride=%d, depth=%d, bpp=%d)\n", + __FUNCTION__, fd, width, height, stride, depth, bpp)); + if (width > INT16_MAX || height > INT16_MAX) + return NULL; + + if ((uint32_t)width * bpp > (uint32_t)stride * 8) + return NULL; + + if (depth < 8) + return NULL; + + switch (bpp) { + case 8: + case 16: + case 32: + break; + default: + return NULL; + } + + bo = kgem_create_for_prime(&sna->kgem, fd, (uint32_t)stride * height); + if (bo == NULL) + return NULL; + + /* Check for a duplicate */ + list_for_each_entry(priv, &sna->dri3.pixmaps, cow_list) { + int other_stride = 0; + if (bo->snoop) { + assert(priv->cpu_bo); + assert(IS_STATIC_PTR(priv->ptr)); + if (bo->handle == priv->cpu_bo->handle) + other_stride = priv->cpu_bo->pitch; + } else { + assert(priv->gpu_bo); + assert(priv->pinned & PIN_DRI3); + if (bo->handle == priv->gpu_bo->handle) + other_stride = priv->gpu_bo->pitch; + } + if (other_stride) { + pixmap = priv->pixmap; + DBG(("%s: imported fd matches existing DRI3 pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); + bo->handle = 0; /* fudge to prevent gem_close */ + kgem_bo_destroy(&sna->kgem, bo); + if (width != pixmap->drawable.width || + height != pixmap->drawable.height || + depth != pixmap->drawable.depth || + bpp != pixmap->drawable.bitsPerPixel || + stride != other_stride) { + DBG(("%s: imported fd mismatches existing DRI3 pixmap (width=%d, height=%d, depth=%d, bpp=%d, stride=%d)\n", __FUNCTION__, + pixmap->drawable.width, + pixmap->drawable.height, + pixmap->drawable.depth, + pixmap->drawable.bitsPerPixel, + other_stride)); + return NULL; + } + sna_sync_flush(sna, priv); + pixmap->refcnt++; + return pixmap; + } + } + + if (!kgem_check_surface_size(&sna->kgem, + width, height, bpp, + bo->tiling, stride, kgem_bo_size(bo))) { + DBG(("%s: client supplied pitch=%d, size=%d too small for %dx%d surface\n", + __FUNCTION__, stride, kgem_bo_size(bo), width, height)); + goto free_bo; + } + + pixmap = sna_pixmap_create_unattached(screen, 0, 0, depth); + if (pixmap == NullPixmap) + goto free_bo; + + if (!screen->ModifyPixmapHeader(pixmap, width, height, + depth, bpp, stride, NULL)) + goto free_pixmap; + + priv = sna_pixmap_attach_to_bo(pixmap, bo); + if (priv == NULL) + goto free_pixmap; + + bo->pitch = stride; + priv->stride = stride; + + if (bo->snoop) { + assert(priv->cpu_bo == bo); + pixmap->devPrivate.ptr = kgem_bo_map__cpu(&sna->kgem, priv->cpu_bo); + if (pixmap->devPrivate.ptr == NULL) + goto free_pixmap; + + pixmap->devKind = stride; + priv->ptr = MAKE_STATIC_PTR(pixmap->devPrivate.ptr); + } else { + assert(priv->gpu_bo == bo); + priv->pinned |= PIN_DRI3; + } + list_add(&priv->cow_list, &sna->dri3.pixmaps); + + return pixmap; + +free_pixmap: + screen->DestroyPixmap(pixmap); +free_bo: + kgem_bo_destroy(&sna->kgem, bo); + return NULL; +} + +static int sna_dri3_fd_from_pixmap(ScreenPtr screen, + PixmapPtr pixmap, + CARD16 *stride, + CARD32 *size) +{ + struct sna *sna = to_sna_from_screen(screen); + struct sna_pixmap *priv; + struct kgem_bo *bo = NULL; + int fd; + + DBG(("%s(pixmap=%ld, width=%d, height=%d)\n", __FUNCTION__, + pixmap->drawable.serialNumber, pixmap->drawable.width, pixmap->drawable.height)); + if (pixmap == sna->front && sna->flags & SNA_TEAR_FREE) { + DBG(("%s: DRI3 protocol cannot support TearFree frontbuffers\n", __FUNCTION__)); + return -1; + } + + priv = sna_pixmap(pixmap); + if (priv && IS_STATIC_PTR(priv->ptr) && priv->cpu_bo) { + if (sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT)) + bo = priv->cpu_bo; + } else { + priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE | __MOVE_DRI); + if (priv != NULL) { + sna_damage_all(&priv->gpu_damage, + pixmap->drawable.width, + pixmap->drawable.height); + bo = priv->gpu_bo; + } + } + if (bo == NULL) { + DBG(("%s: pixmap not supported by GPU\n", __FUNCTION__)); + return -1; + } + assert(priv != NULL); + + if (bo->pitch > UINT16_MAX) { + DBG(("%s: pixmap pitch (%d) too large for DRI3 protocol\n", + __FUNCTION__, bo->pitch)); + return -1; + } + + fd = kgem_bo_export_to_prime(&sna->kgem, bo); + if (fd == -1) { + DBG(("%s: exporting handle=%d to fd failed\n", __FUNCTION__, bo->handle)); + return -1; + } + + if (bo == priv->gpu_bo && (priv->pinned & PIN_DRI3) == 0) { + list_add(&priv->cow_list, &sna->dri3.pixmaps); + priv->pinned |= PIN_DRI3; + } + + *stride = (priv->pinned & PIN_DRI3) ? priv->gpu_bo->pitch : priv->cpu_bo->pitch; + *size = kgem_bo_size((priv->pinned & PIN_DRI3) ? priv->gpu_bo : priv->cpu_bo); + DBG(("%s: exporting %s pixmap=%ld, handle=%d, stride=%d, size=%d\n", + __FUNCTION__, + (priv->pinned & PIN_DRI3) ? "GPU" : "CPU", pixmap->drawable.serialNumber, + (priv->pinned & PIN_DRI3) ? priv->gpu_bo->handle : priv->cpu_bo->handle, + *stride, *size)); + return fd; +} + +static dri3_screen_info_rec sna_dri3_info = { + .version = DRI3_SCREEN_INFO_VERSION, + + .open = sna_dri3_open_device, + .pixmap_from_fd = sna_dri3_pixmap_from_fd, + .fd_from_pixmap = sna_dri3_fd_from_pixmap, +}; + +bool sna_dri3_open(struct sna *sna, ScreenPtr screen) +{ + DBG(("%s()\n", __FUNCTION__)); + + if (!sna_sync_open(sna, screen)) + return false; + + list_init(&sna->dri3.pixmaps); + return dri3_screen_init(screen, &sna_dri3_info); +} + +void sna_dri3_close(struct sna *sna, ScreenPtr screen) +{ + SyncScreenFuncsPtr funcs; + + DBG(("%s()\n", __FUNCTION__)); + + funcs = miSyncGetScreenFuncs(screen); + if (funcs) + funcs->CreateFence = sna->dri3.create_fence; +} diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c index 9d079cb8..97f27e27 100644 --- a/src/sna/sna_driver.c +++ b/src/sna/sna_driver.c @@ -379,6 +379,37 @@ static Bool sna_option_cast_to_bool(struct sna *sna, int id, Bool val) return val; } +static unsigned sna_option_cast_to_unsigned(struct sna *sna, int id, unsigned val) +{ + const char *str = xf86GetOptValString(sna->Options, id); + unsigned v; + + if (str == NULL || *str == '\0') + return val; + + if (namecmp(str, "on") == 0) + return val; + if (namecmp(str, "true") == 0) + return val; + if (namecmp(str, "yes") == 0) + return val; + + if (namecmp(str, "0") == 0) + return 0; + if (namecmp(str, "off") == 0) + return 0; + if (namecmp(str, "false") == 0) + return 0; + if (namecmp(str, "no") == 0) + return 0; + + v = atoi(str); + if (v) + return v; + + return val; +} + static Bool fb_supports_depth(int fd, int depth) { struct drm_i915_gem_create create; @@ -407,6 +438,24 @@ static Bool fb_supports_depth(int fd, int depth) return ret; } +static void setup_dri(struct sna *sna) +{ + unsigned level; + + sna->dri2.available = false; + sna->dri3.available = false; + + level = sna_option_cast_to_unsigned(sna, OPTION_DRI, ~0); +#if HAVE_DRI3 + if (level >= 3) + sna->dri3.available = !!xf86LoadSubModule(sna->scrn, "dri3"); +#endif +#if HAVE_DRI2 + if (level >= 2) + sna->dri2.available = !!xf86LoadSubModule(sna->scrn, "dri2"); +#endif +} + /** * This is called before ScreenInit to do any require probing of screen * configuration. @@ -595,9 +644,7 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int flags) xf86SetGamma(scrn, zeros); xf86SetDpi(scrn, 0, 0); - sna->dri2.available = false; - if (sna_option_cast_to_bool(sna, OPTION_DRI, TRUE)) - sna->dri2.available = !!xf86LoadSubModule(scrn, "dri2"); + setup_dri(sna); sna_acpi_init(sna); @@ -820,6 +867,11 @@ static Bool sna_early_close_screen(CLOSE_SCREEN_ARGS_DECL) sna_uevent_fini(scrn); sna_mode_close(sna); + if (sna->dri3.open) { + sna_dri3_close(sna, screen); + sna->dri3.open = false; + } + if (sna->dri2.open) { sna_dri2_close(sna, screen); sna->dri2.open = false; @@ -901,6 +953,25 @@ sna_register_all_privates(void) return TRUE; } +static void sna_dri_init(struct sna *sna, ScreenPtr screen) +{ + char str[128] = ""; + + if (sna->dri2.available) + sna->dri2.open = sna_dri2_open(sna, screen); + if (sna->dri2.open) + strcat(str, "DRI2 "); + + if (sna->dri3.available) + sna->dri3.open = sna_dri3_open(sna, screen); + if (sna->dri3.open) + strcat(str, "DRI3 "); + + if (*str) + xf86DrvMsg(sna->scrn->scrnIndex, X_INFO, + "direct rendering: %senabled\n", str); +} + static size_t agp_aperture_size(struct pci_device *dev, int gen) { @@ -1025,11 +1096,7 @@ sna_screen_init(SCREEN_INIT_ARGS_DECL) xf86DPMSInit(screen, xf86DPMSSet, 0); sna_video_init(sna, screen); - if (sna->dri2.available) - sna->dri2.open = sna_dri2_open(sna, screen); - if (sna->dri2.open) - xf86DrvMsg(scrn->scrnIndex, X_INFO, - "direct rendering: DRI2 Enabled\n"); + sna_dri_init(sna, screen); if (serverGeneration == 1) xf86ShowUnusedOptions(scrn->scrnIndex, scrn->options); |