sna: Port prime interfacing

Preliminary prime support.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
Chris Wilson 2012-09-03 20:43:48 +01:00
parent e3ad18036b
commit df68723baa
9 changed files with 290 additions and 28 deletions

View File

@ -28,15 +28,15 @@
#include "config.h"
#endif
#include <stdbool.h>
#include <pixman.h>
#include <xorg-server.h>
#include <servermd.h>
#include <gcstruct.h>
#include <colormap.h>
#include <windowstr.h>
#include <stdbool.h>
#include <pixman.h>
#if HAS_DEBUG_FULL
#define DBG(x) ErrorF x
#else
@ -288,13 +288,17 @@ typedef struct {
unsigned char bpp; /* current drawable bpp */
} FbGCPrivate, *FbGCPrivPtr;
extern DevPrivateKeyRec sna_gc_key;
extern DevPrivateKeyRec sna_window_key;
static inline FbGCPrivate *fb_gc(GCPtr gc)
{
return (FbGCPrivate *)gc->devPrivates;
return dixGetPrivateAddr(&gc->devPrivates, &sna_gc_key);
}
static inline PixmapPtr fbGetWindowPixmap(WindowPtr window)
{
return *(void **)window->devPrivates;
return *(PixmapPtr *)dixGetPrivateAddr(&window->devPrivates, &sna_window_key);
}
#ifdef ROOTLESS

View File

@ -2771,6 +2771,65 @@ struct kgem_bo *kgem_create_for_name(struct kgem *kgem, uint32_t name)
return bo;
}
struct kgem_bo *kgem_create_for_prime(struct kgem *kgem, int name, uint32_t size)
{
#ifdef DRM_IOCTL_PRIME_FD_TO_HANDLE
struct drm_prime_handle args;
struct drm_i915_gem_get_tiling tiling;
struct kgem_bo *bo;
DBG(("%s(name=%d)\n", __FUNCTION__, name));
VG_CLEAR(args);
args.fd = name;
args.flags = 0;
if (drmIoctl(kgem->fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args))
return NULL;
VG_CLEAR(tiling);
tiling.handle = args.handle;
if (drmIoctl(kgem->fd, DRM_IOCTL_I915_GEM_GET_TILING, &tiling)) {
gem_close(kgem->fd, args.handle);
return NULL;
}
DBG(("%s: new handle=%d, tiling=%d\n", __FUNCTION__,
args.handle, tiling.tiling_mode));
bo = __kgem_bo_alloc(args.handle, NUM_PAGES(size));
if (bo == NULL) {
gem_close(kgem->fd, args.handle);
return NULL;
}
bo->tiling = tiling.tiling_mode;
bo->reusable = false;
debug_alloc__bo(kgem, bo);
return bo;
#else
return NULL;
#endif
}
int kgem_bo_export_to_prime(struct kgem *kgem, struct kgem_bo *bo)
{
#ifdef DRM_IOCTL_PRIME_HANDLE_TO_PRIME
struct drm_prime_handle args;
VG_CLEAR(args);
args.handle = bo->handle;
args.flags = DRM_CLOEXEC;
if (drmIoctl(kgem->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args))
return -1;
bo->reusable = false;
return args.fd;
#else
return -1;
#endif
}
struct kgem_bo *kgem_create_linear(struct kgem *kgem, int size, unsigned flags)
{
struct kgem_bo *bo;

View File

@ -207,6 +207,8 @@ struct kgem_bo *kgem_create_map(struct kgem *kgem,
bool read_only);
struct kgem_bo *kgem_create_for_name(struct kgem *kgem, uint32_t name);
struct kgem_bo *kgem_create_for_prime(struct kgem *kgem, int name, uint32_t size);
int kgem_bo_export_to_prime(struct kgem *kgem, struct kgem_bo *bo);
struct kgem_bo *kgem_create_linear(struct kgem *kgem, int size, unsigned flags);
struct kgem_bo *kgem_create_proxy(struct kgem *kgem,

View File

@ -47,6 +47,10 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <xorg-server.h>
#include <xf86Crtc.h>
#if XF86_CRTC_VERSION >= 5
#define HAS_PIXMAP_SHARING 1
#endif
#include <xf86str.h>
#include <windowstr.h>
#include <glyphstr.h>
@ -149,9 +153,11 @@ static inline PixmapPtr get_drawable_pixmap(DrawablePtr drawable)
return get_window_pixmap((WindowPtr)drawable);
}
extern DevPrivateKeyRec sna_pixmap_key;
constant static inline struct sna_pixmap *sna_pixmap(PixmapPtr pixmap)
{
return ((void **)pixmap->devPrivates)[1];
return ((void **)dixGetPrivateAddr(&pixmap->devPrivates, &sna_pixmap_key))[1];
}
static inline struct sna_pixmap *sna_pixmap_from_drawable(DrawablePtr drawable)
@ -167,7 +173,7 @@ struct sna_gc {
static inline struct sna_gc *sna_gc(GCPtr gc)
{
return (struct sna_gc *)gc->devPrivates;
return dixGetPrivateAddr(&gc->devPrivates, &sna_gc_key);
}
enum {
@ -309,7 +315,7 @@ to_sna_from_screen(ScreenPtr screen)
constant static inline struct sna *
to_sna_from_pixmap(PixmapPtr pixmap)
{
return *(void **)pixmap->devPrivates;
return ((void **)dixGetPrivateAddr(&pixmap->devPrivates, &sna_pixmap_key))[0];
}
constant static inline struct sna *

View File

@ -601,11 +601,7 @@ struct kgem_bo *sna_pixmap_change_tiling(PixmapPtr pixmap, uint32_t tiling)
static inline void sna_set_pixmap(PixmapPtr pixmap, struct sna_pixmap *sna)
{
#if 0
dixSetPrivate(&pixmap->devPrivates, &sna_private_index, sna);
#else
((void **)pixmap->devPrivates)[1] = sna;
#endif
((void **)dixGetPrivateAddr(&pixmap->devPrivates, &sna_pixmap_key))[1] = sna;
assert(sna_pixmap(pixmap) == sna);
}
@ -709,7 +705,8 @@ create_pixmap(struct sna *sna, ScreenPtr screen,
if (!pixmap)
return NullPixmap;
((void **)pixmap->devPrivates)[0] = sna;
((void **)dixGetPrivateAddr(&pixmap->devPrivates, &sna_pixmap_key))[0] = sna;
assert(to_sna_from_pixmap(pixmap) == sna);
pixmap->drawable.type = DRAWABLE_PIXMAP;
pixmap->drawable.class = 0;
@ -924,6 +921,111 @@ sna_pixmap_create_scratch(ScreenPtr screen,
return pixmap;
}
#ifdef CREATE_PIXMAP_USAGE_SHARED
static Bool
sna_share_pixmap_backing(PixmapPtr pixmap, ScreenPtr slave, void **fd_handle)
{
struct sna *sna = to_sna_from_pixmap(pixmap);
struct sna_pixmap *priv;
int fd;
priv = sna_pixmap_move_to_gpu(pixmap,
MOVE_READ | MOVE_WRITE | __MOVE_DRI | __MOVE_FORCE);
if (priv == NULL)
return FALSE;
assert(priv->gpu_bo);
/* XXX */
if (priv->gpu_bo->tiling &&
!sna_pixmap_change_tiling(pixmap, I915_TILING_NONE))
return FALSE;
assert(priv->gpu_bo->tiling == I915_TILING_NONE);
/* And export the bo->pitch via pixmap->devKind */
pixmap->devPrivate.ptr =
kgem_bo_map(&sna->kgem, priv->gpu_bo);
if (pixmap->devPrivate.ptr == NULL)
return FALSE;
pixmap->devKind = priv->gpu_bo->pitch;
priv->mapped = true;
fd = kgem_bo_export_to_prime(&sna->kgem, priv->gpu_bo);
if (fd == -1)
return FALSE;
priv->pinned = true;
*fd_handle = (void *)(intptr_t)fd;
return TRUE;
}
static Bool
sna_set_shared_pixmap_backing(PixmapPtr pixmap, void *fd_handle)
{
struct sna *sna = to_sna_from_pixmap(pixmap);
struct sna_pixmap *priv;
struct kgem_bo *bo;
priv = sna_pixmap(pixmap);
if (priv == NULL)
return FALSE;
assert(!priv->pinned);
assert(priv->gpu_bo == NULL);
assert(priv->cpu_bo == NULL);
assert(priv->cpu_damage == NULL);
assert(priv->gpu_damage == NULL);
bo = kgem_bo_create_for_prime(&sna->kgem,
(intptr_t)fd_handle,
pixmap->devKind * pixmap->drawable.height);
if (bo == NULL)
return FALSE;
sna_damage_all(&priv->gpu_damage,
pixmap->drawable.width,
pixmap->drawable.height);
bo->pitch = pixmap->devKind;
priv->stride = pixmap->devKind;
priv->gpu_bo = bo;
priv->pinned = true;
close((intptr_t)fd_handle);
return TRUE;
}
static PixmapPtr
sna_create_pixmap_shared(struct sna *sna, ScreenPtr screen, int depth)
{
PixmapPtr pixmap;
struct sna_pixmap *priv;
/* Create a stub to be attached later */
pixmap = create_pixmap(sna, screen, 0, 0, depth, 0);
if (pixmap == NullPixmap)
return NullPixmap;
pixmap->drawable.width = 0;
pixmap->drawable.height = 0;
pixmap->devKind = 0;
pixmap->devPrivate.ptr = NULL;
priv = sna_pixmap_attach(pixmap);
if (priv == NULL) {
free(pixmap);
return NullPixmap;
}
priv->stride = 0;
priv->create = 0;
return pixmap;
}
#endif
static PixmapPtr sna_create_pixmap(ScreenPtr screen,
int width, int height, int depth,
unsigned int usage)
@ -936,6 +1038,13 @@ static PixmapPtr sna_create_pixmap(ScreenPtr screen,
DBG(("%s(%d, %d, %d, usage=%x)\n", __FUNCTION__,
width, height, depth, usage));
#ifdef CREATE_PIXMAP_USAGE_SHARED
if (usage == CREATE_PIXMAP_USAGE_SHARED) {
assert((width|height) == 0);
return sna_create_pixmap_shared(sna, screen, depth);
}
#endif
if ((width|height) == 0) {
usage = -1;
goto fallback;
@ -13675,6 +13784,31 @@ static int32_t sna_timeout(struct sna *sna)
return next;
}
static void sna_accel_post_damage(struct sna *sna)
{
#if HAS_PIXMAP_SHARING
ScreenPtr screen = sna->scrn->pScreen;
PixmapDirtyUpdatePtr dirty;
xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
RegionRec pixregion;
if (!RegionNotEmpty(DamageRegion(dirty->damage)))
continue;
PixmapRegionInit(&pixregion,
dirty->slave_dst->master_pixmap);
PixmapSyncDirtyHelper(dirty, &pixregion);
DamageRegionAppend(&dirty->slave_dst->drawable,
&pixregion);
RegionUninit(&pixregion);
DamageEmpty(dirty->damage);
}
#endif
}
static void sna_accel_flush(struct sna *sna)
{
struct sna_pixmap *priv = sna_accel_scanout(sna);
@ -13699,6 +13833,7 @@ static void sna_accel_flush(struct sna *sna)
}
sna_mode_redisplay(sna);
sna_accel_post_damage(sna);
}
static void sna_accel_throttle(struct sna *sna)
@ -13859,7 +13994,7 @@ sna_get_window_pixmap(WindowPtr window)
static void
sna_set_window_pixmap(WindowPtr window, PixmapPtr pixmap)
{
*(PixmapPtr *)window->devPrivates = pixmap;
*(PixmapPtr *)dixGetPrivateAddr(&window->devPrivates, &sna_window_key) = pixmap;
}
static Bool
@ -13988,6 +14123,10 @@ bool sna_accel_init(ScreenPtr screen, struct sna *sna)
screen->CreatePixmap = sna_create_pixmap;
assert(screen->DestroyPixmap == NULL);
screen->DestroyPixmap = sna_destroy_pixmap;
#ifdef CREATE_PIXMAP_USAGE_SHARED
screen->SharePixmapBacking = sna_share_pixmap_backing;
screen->SetSharedPixmapBacking = sna_set_shared_pixmap_backing;
#endif
screen->RealizeFont = sna_realize_font;
screen->UnrealizeFont = sna_unrealize_font;
assert(screen->CreateGC == NULL);
@ -14002,6 +14141,11 @@ bool sna_accel_init(ScreenPtr screen, struct sna *sna)
screen->StoreColors = sna_store_colors;
screen->BitmapToRegion = fbBitmapToRegion;
#if HAS_PIXMAP_SHARING
screen->StartPixmapTracking = PixmapStartDirtyTracking;
screen->StopPixmapTracking = PixmapStopDirtyTracking;
#endif
assert(screen->GetWindowPixmap == NULL);
screen->GetWindowPixmap = sna_get_window_pixmap;
assert(screen->SetWindowPixmap == NULL);

View File

@ -60,6 +60,7 @@
struct sna_crtc {
struct drm_mode_modeinfo kmode;
int dpms_mode;
PixmapPtr scanout_pixmap;
struct kgem_bo *bo;
uint32_t cursor;
bool shadow;
@ -960,6 +961,22 @@ static struct kgem_bo *sna_crtc_attach(xf86CrtcPtr crtc)
sna_crtc->transform = true;
return bo;
} else if (sna_crtc->scanout_pixmap) {
DBG(("%s: attaching to scanout pixmap\n", __FUNCTION__));
if (!sna_crtc_enable_shadow(sna, sna_crtc))
return NULL;
bo = sna_pixmap_pin(sna_crtc->scanout_pixmap);
if (bo == NULL)
return NULL;
if (!get_fb(sna, bo,
sna_crtc->scanout_pixmap->drawable.width,
sna_crtc->scanout_pixmap->drawable.height))
return NULL;
sna_crtc->transform = true;
return kgem_bo_reference(bo);
} else if (sna->flags & SNA_TEAR_FREE) {
DBG(("%s: tear-free updates requested\n", __FUNCTION__));
@ -1299,6 +1316,15 @@ sna_crtc_destroy(xf86CrtcPtr crtc)
crtc->driver_private = NULL;
}
#if HAS_PIXMAP_SHARING
static Bool
sna_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr pixmap)
{
to_sna_crtc(crtc)->scanout_pixmap = pixmap;
return TRUE;
}
#endif
static const xf86CrtcFuncsRec sna_crtc_funcs = {
.dpms = sna_crtc_dpms,
.set_mode_major = sna_crtc_set_mode_major,
@ -1309,6 +1335,9 @@ static const xf86CrtcFuncsRec sna_crtc_funcs = {
.load_cursor_argb = sna_crtc_load_cursor_argb,
.gamma_set = sna_crtc_gamma_set,
.destroy = sna_crtc_destroy,
#if HAS_PIXMAP_SHARING
.set_scanout_pixmap = sna_set_scanout_pixmap,
#endif
};
static uint32_t
@ -2412,6 +2441,9 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
for (i = 0; i < mode->kmode->count_connectors; i++)
sna_output_init(scrn, mode, i);
#if HAS_PIXMAP_SHARING
xf86ProviderSetup(scrn, NULL, "Intel");
#endif
xf86InitialConfiguration(scrn, TRUE);
return true;

View File

@ -195,12 +195,12 @@ static struct kgem_bo *sna_pixmap_set_dri(struct sna *sna,
constant static inline void *sna_pixmap_get_buffer(PixmapPtr pixmap)
{
return ((void **)pixmap->devPrivates)[2];
return ((void **)dixGetPrivateAddr(&pixmap->devPrivates, &sna_pixmap_key))[2];
}
static inline void sna_pixmap_set_buffer(PixmapPtr pixmap, void *ptr)
{
((void **)pixmap->devPrivates)[2] = ptr;
((void **)dixGetPrivateAddr(&pixmap->devPrivates, &sna_pixmap_key))[2] = ptr;
}
static DRI2Buffer2Ptr
@ -841,7 +841,7 @@ sna_dri_get_pipe(DrawablePtr pDraw)
static struct sna_dri_frame_event *
sna_dri_window_get_chain(WindowPtr win)
{
return ((void **)win->devPrivates)[1];
return ((void **)dixGetPrivateAddr(&win->devPrivates, &sna_window_key))[1];
}
static void
@ -850,7 +850,7 @@ sna_dri_window_set_chain(WindowPtr win,
{
DBG(("%s: head now %p\n", __FUNCTION__, chain));
assert(win->drawable.type == DRAWABLE_WINDOW);
((void **)win->devPrivates)[1] = chain;
((void **)dixGetPrivateAddr(&win->devPrivates, &sna_window_key))[1] = chain;
}
static void

View File

@ -75,10 +75,10 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "git_version.h"
#endif
static DevPrivateKeyRec sna_pixmap_key;
static DevPrivateKeyRec sna_gc_key;
static DevPrivateKeyRec sna_glyph_key;
static DevPrivateKeyRec sna_window_key;
DevPrivateKeyRec sna_pixmap_key;
DevPrivateKeyRec sna_gc_key;
DevPrivateKeyRec sna_window_key;
DevPrivateKeyRec sna_glyph_key;
static Bool sna_enter_vt(VT_FUNC_ARGS_DECL);
@ -343,6 +343,21 @@ static bool has_pageflipping(struct sna *sna)
return v > 0;
}
static void sna_setup_capabilities(ScrnInfoPtr scrn, int fd)
{
#if HAS_PIXMAP_SHARING && defined(DRM_CAP_PRIME)
uint64_t value;
scrn->capabilities = 0;
if (drmGetCap(fd, DRM_CAP_PRIME, &value) == 0) {
if (value & DRM_PRIME_CAP_EXPORT)
scrn->capabilities |= RR_Capability_SourceOutput | RR_Capability_SinkOffload;
if (value & DRM_PRIME_CAP_IMPORT)
scrn->capabilities |= RR_Capability_SinkOutput;
}
#endif
}
/**
* This is called before ScreenInit to do any require probing of screen
* configuration.
@ -442,6 +457,8 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int flags)
if (sna->Options == NULL)
return FALSE;
sna_setup_capabilities(scrn, fd);
intel_detect_chipset(scrn, sna->pEnt, sna->PciInfo);
kgem_init(&sna->kgem, fd, sna->PciInfo, sna->info->gen);
@ -777,22 +794,18 @@ sna_register_all_privates(void)
if (!dixRegisterPrivateKey(&sna_pixmap_key, PRIVATE_PIXMAP,
3*sizeof(void *)))
return FALSE;
assert(sna_pixmap_key.offset == 0);
if (!dixRegisterPrivateKey(&sna_gc_key, PRIVATE_GC,
sizeof(FbGCPrivate)))
return FALSE;
assert(sna_gc_key.offset == 0);
if (!dixRegisterPrivateKey(&sna_glyph_key, PRIVATE_GLYPH,
sizeof(struct sna_glyph)))
return FALSE;
assert(sna_glyph_key.offset == 0);
if (!dixRegisterPrivateKey(&sna_window_key, PRIVATE_WINDOW,
2*sizeof(void *)))
return FALSE;
assert(sna_window_key.offset == 0);
return TRUE;
}

View File

@ -104,9 +104,11 @@ static void _assert_pixmap_contains_box(PixmapPtr pixmap, BoxPtr box, const char
#define assert_pixmap_contains_box(p, b)
#endif
extern DevPrivateKeyRec sna_glyph_key;
static inline struct sna_glyph *sna_glyph(GlyphPtr glyph)
{
return (struct sna_glyph *)glyph->devPrivates;
return dixGetPrivateAddr(&glyph->devPrivates, &sna_glyph_key);
}
#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)