sna: Add support for DRI3
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
parent
0fbe8995d5
commit
d8eb87f84f
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
const char *s = *str;
|
||||
char *end;
|
||||
unsigned val;
|
||||
|
||||
if (s == NULL || *s == '\0')
|
||||
return true;
|
||||
|
||||
if (*str == '\0')
|
||||
if (namecmp(s, "on") == 0)
|
||||
return true;
|
||||
if (namecmp(s, "true") == 0)
|
||||
return true;
|
||||
if (namecmp(s, "yes") == 0)
|
||||
return true;
|
||||
|
||||
if (namecmp(str, "1") == 0)
|
||||
if (namecmp(s, "0") == 0)
|
||||
return true;
|
||||
if (namecmp(str, "on") == 0)
|
||||
if (namecmp(s, "off") == 0)
|
||||
return true;
|
||||
if (namecmp(str, "true") == 0)
|
||||
if (namecmp(s, "false") == 0)
|
||||
return true;
|
||||
if (namecmp(str, "yes") == 0)
|
||||
if (namecmp(s, "no") == 0)
|
||||
return true;
|
||||
|
||||
if (namecmp(str, "0") == 0)
|
||||
val = strtoul(s, &end, 0);
|
||||
if (val && *end == '\0')
|
||||
return true;
|
||||
if (namecmp(str, "off") == 0)
|
||||
return true;
|
||||
if (namecmp(str, "false") == 0)
|
||||
return true;
|
||||
if (namecmp(str, "no") == 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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue