diff mbox

[RFC] Updated DRM plane handling patches

Message ID 20110615102911.3fa27a7a@jbarnes-desktop
State New, archived
Headers show

Commit Message

Jesse Barnes June 15, 2011, 5:29 p.m. UTC
On Tue,  7 Jun 2011 13:07:38 -0700
Jesse Barnes <jbarnes@virtuousgeek.org> wrote:

> This patchset updates the previous one, incorporating the feedback I
> received:
>   1) uses the v4l fourcc codes to communicate pixel format
>   2) adds a new addfb ioctl that takes a format
>   3) adds working SNB support for the new code
> 
> Comments welcome.  I'll be pushing intel-gpu-tools testdisplay support
> for this shortly if people want to play around with it.  Next step is to
> incorporate it into X and Wayland to see if the API is rich enough for
> our needs.

And here's a very early & hackish DDX patch for this code in case other
people want to test things out.  I still have to update it with the
scaling stuff we talked about and support various things (disabling
planes, controlling attributes, etc) but it's enough to get bits on the
screen at least.

Jesse
diff mbox

Patch

diff --git a/src/Makefile.am b/src/Makefile.am
index a7f219c..2aec5a8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -69,6 +69,7 @@  intel_drv_la_SOURCES = \
 	 i965_reg.h \
 	 i965_video.c \
 	 i965_render.c \
+	 intel_sprite.c \
 	 $(NULL)
 
 if DRI
diff --git a/src/intel.h b/src/intel.h
index 2b114c3..11d911a 100644
--- a/src/intel.h
+++ b/src/intel.h
@@ -334,6 +334,7 @@  typedef struct intel_screen_private {
 
 	int colorKey;
 	XF86VideoAdaptorPtr adaptor;
+	XF86VideoAdaptorPtr sprite_adaptor;
 	ScreenBlockHandlerProcPtr BlockHandler;
 	Bool overlayOn;
 
@@ -461,6 +462,7 @@  extern void intel_mode_fini(intel_screen_private *intel);
 
 extern int intel_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, xf86CrtcPtr crtc);
 extern int intel_crtc_id(xf86CrtcPtr crtc);
+extern int intel_crtc_to_sprite(xf86CrtcPtr crtc);
 extern int intel_output_dpms_status(xf86OutputPtr output);
 
 enum DRI2FrameEventType {
@@ -518,6 +520,7 @@  extern void I915EmitInvarientState(ScrnInfoPtr scrn);
 extern void I830EmitFlush(ScrnInfoPtr scrn);
 
 extern void I830InitVideo(ScreenPtr pScreen);
+extern XF86VideoAdaptorPtr intel_setup_sprite(ScreenPtr screen);
 extern xf86CrtcPtr intel_covering_crtc(ScrnInfoPtr scrn, BoxPtr box,
 				      xf86CrtcPtr desired, BoxPtr crtc_box_ret);
 
diff --git a/src/intel_display.c b/src/intel_display.c
index b55b110..4b032af 100644
--- a/src/intel_display.c
+++ b/src/intel_display.c
@@ -75,6 +75,7 @@  struct intel_crtc {
 	dri_bo *rotate_bo;
 	uint32_t rotate_pitch;
 	uint32_t rotate_fb_id;
+	uint32_t sprite_id;
 	xf86CrtcPtr crtc;
 	struct list link;
 };
@@ -1564,9 +1565,50 @@  drm_wakeup_handler(pointer data, int err, pointer p)
 		drmHandleEvent(mode->fd, &mode->event_context);
 }
 
+static void intel_crtc_find_plane(ScrnInfoPtr scrn, xf86CrtcPtr crtc)
+{
+	intel_screen_private *intel = intel_get_screen_private(scrn);
+	struct intel_crtc *intel_crtc = crtc->driver_private;
+	drmModePlaneRes *plane_resources;
+	drmModePlane *ovr;
+	uint32_t id = 0;
+	int i;
+
+	plane_resources = drmModeGetPlaneResources(intel->drmSubFD);
+	if (!plane_resources) {
+		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+			   "failed to get plane resources: %s\n",
+			   strerror(errno));
+		goto out;
+	}
+
+	for (i = 0; i < plane_resources->count_planes; i++) {
+		ovr = drmModeGetPlane(intel->drmSubFD,
+				      plane_resources->planes[i]);
+		if (!ovr) {
+			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+				   "failed to get plane info: %s\n",
+				   strerror(errno));
+			continue;
+		}
+
+		if (ovr->possible_crtcs & (1 << intel_crtc_to_pipe(crtc))) {
+			id = ovr->plane_id;
+			drmModeFreePlane(ovr);
+			break;
+		}
+		drmModeFreePlane(ovr);
+	}
+
+	free(plane_resources);
+out:
+	intel_crtc->sprite_id = id;
+}
+
 Bool intel_mode_pre_init(ScrnInfoPtr scrn, int fd, int cpp)
 {
 	intel_screen_private *intel = intel_get_screen_private(scrn);
+	struct intel_crtc *intel_crtc;
 	struct drm_i915_getparam gp;
 	struct intel_mode *mode;
 	unsigned int i;
@@ -1597,6 +1639,9 @@  Bool intel_mode_pre_init(ScrnInfoPtr scrn, int fd, int cpp)
 	for (i = 0; i < mode->mode_res->count_crtcs; i++)
 		intel_crtc_init(scrn, mode, i);
 
+	list_for_each_entry(intel_crtc, &mode->crtcs, link)
+		intel_crtc_find_plane(scrn, intel_crtc->crtc);
+
 	for (i = 0; i < mode->mode_res->count_connectors; i++)
 		intel_output_init(scrn, mode, i);
 
@@ -1618,6 +1663,8 @@  Bool intel_mode_pre_init(ScrnInfoPtr scrn, int fd, int cpp)
 	}
 
 	intel->modes = mode;
+
+
 	return TRUE;
 }
 
@@ -1687,3 +1734,9 @@  int intel_crtc_to_pipe(xf86CrtcPtr crtc)
 	struct intel_crtc *intel_crtc = crtc->driver_private;
 	return intel_crtc->pipe;
 }
+
+int intel_crtc_to_sprite(xf86CrtcPtr crtc)
+{
+	struct intel_crtc *intel_crtc = crtc->driver_private;
+	return intel_crtc->sprite_id;
+}
diff --git a/src/intel_sprite.c b/src/intel_sprite.c
new file mode 100644
index 0000000..618a526
--- /dev/null
+++ b/src/intel_sprite.c
@@ -0,0 +1,291 @@ 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <inttypes.h>
+#include <math.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <xf86drmMode.h>
+
+#include "xf86.h"
+#include "xf86_OSproc.h"
+#include "compiler.h"
+#include "xf86PciInfo.h"
+#include "xf86Pci.h"
+#include "xf86fbman.h"
+#include "regionstr.h"
+#include "randrstr.h"
+#include "windowstr.h"
+#include "damage.h"
+#include "intel.h"
+#include "intel_video.h"
+#include "i830_reg.h"
+#include "xf86xv.h"
+#include <X11/extensions/Xv.h>
+#include "dixstruct.h"
+#include "fourcc.h"
+
+#define IMAGE_MAX_WIDTH		2048
+#define IMAGE_MAX_HEIGHT	2048
+
+static XF86VideoFormatRec xv_formats[] = {
+	{15, TrueColor}, {16, TrueColor}, {24, TrueColor}
+};
+
+static XF86ImageRec xv_images[] = {
+	XVIMAGE_YUY2,
+	XVIMAGE_UYVY,
+};
+
+static const XF86VideoEncodingRec xv_dummy_encoding[] = {
+	{
+	 0,
+	 "XV_IMAGE",
+	 IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT,
+	 {1, 1}
+	 }
+};
+
+static void intel_sprite_stop(ScrnInfoPtr scrn, pointer data, Bool shutdown)
+{
+}
+
+static int intel_sprite_set_attr(ScrnInfoPtr scrn, Atom attribute, INT32 value,
+				 pointer data)
+{
+	return Success;
+}
+
+static int intel_sprite_get_attr(ScrnInfoPtr scrn, Atom attribute, INT32 *value,
+				 pointer data)
+{
+	return Success;
+}
+
+static void intel_sprite_best_size(ScrnInfoPtr scrn, Bool motion, short vid_w,
+				   short vid_h, short drw_w, short drw_h,
+				   unsigned int *p_w, unsigned int *p_h,
+				   pointer data)
+{
+	*p_w = vid_w;
+	*p_h = vid_h;
+}
+
+static int intel_sprite_put(ScrnInfoPtr scrn, short src_x, short src_y,
+			    short drw_x, short drw_y, short src_w, short src_h,
+			    short drw_w, short drw_h, int id,
+			    unsigned char *buf, short width, short height,
+			    Bool sync, RegionPtr clipBoxes, pointer data,
+			    DrawablePtr drawable)
+{
+	intel_screen_private *intel = intel_get_screen_private(scrn);
+	intel_adaptor_private *adaptor_priv = intel_get_sprite_adaptor_private(intel);
+	dri_bo *new_frame;
+	unsigned char *src, *dst, *dst_base;
+	int pitch, i;
+	xf86CrtcPtr crtc;
+	BoxRec dst_box;
+	int ret, top, left, lines, pixel_width;
+	int plane_id;
+	uint32_t fb_id;
+	unsigned long alloc_pitch;
+
+	ret = intel_clip_video_helper(scrn, adaptor_priv, &crtc, &dst_box,
+				      src_x, src_y, drw_x, drw_y,
+				      src_w, src_h, drw_w, drw_h,
+				      id, &top, &left, &pixel_width, &lines,
+				      clipBoxes, width, height);
+	if (!ret)
+		return Success;
+
+	plane_id = intel_crtc_to_sprite(crtc);
+	if (!plane_id) {
+		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+			   "no planes available for crtc\n");
+		return Success;
+	}
+
+	new_frame = adaptor_priv->buf;
+	pitch = ALIGN(pixel_width, 64);
+
+	if (!new_frame) {
+		uint32_t tiling_mode = I915_TILING_X;
+
+		new_frame = drm_intel_bo_alloc_tiled(intel->bufmgr,
+						     "sprite buffer",
+						     pixel_width, lines,
+						     drawable->bitsPerPixel / 8,
+						     &tiling_mode, &alloc_pitch,
+						     BO_ALLOC_FOR_RENDER);
+		if (!new_frame) {
+			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+				   "failed to create bo for video data: %s\n",
+				   strerror(errno));
+			return BadAlloc;
+		}
+		adaptor_priv->reusable = TRUE;
+		adaptor_priv->buf = new_frame;
+	}
+
+	if (drm_intel_gem_bo_map_gtt(new_frame))
+		return BadAlloc;
+
+	dst_base = new_frame->virtual;
+	dst = dst_base + adaptor_priv->YBufOffset;
+
+	src = buf + (top * (width * 2)) + (left << 1);
+
+	for (i = 0; i < height; i++) {
+		memcpy(dst, src, width * 2);
+		src += width * 2;
+		dst += pitch;
+	}
+
+	drm_intel_gem_bo_unmap_gtt(new_frame);
+
+	ret = drmModeAddFB2(intel->drmSubFD, pixel_width, lines,
+			    V4L2_PIX_FMT_RGB32, drawable->depth,
+			    drawable->bitsPerPixel, alloc_pitch,
+			    new_frame->handle, &fb_id);
+	if (ret) {
+		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+			   "failed to add fb for video data: %s\n",
+			   strerror(errno));
+		return BadAlloc;
+	}
+
+	ret = drmModeSetPlane(intel->drmSubFD, plane_id, intel_crtc_id(crtc),
+			      fb_id, left, top, 0, 0);
+	if (ret) {
+		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+			   "failed to enable plane for video data: %s\n",
+			   strerror(errno));
+		return BadAlloc;
+	}
+
+	return Success;
+}
+
+static int intel_sprite_query_attrs(ScrnInfoPtr scrn, int id, unsigned short *w,
+				    unsigned short *h, int *pitches,
+				    int *offsets)
+{
+	int size;
+
+	if (*w > IMAGE_MAX_WIDTH)
+		*w = IMAGE_MAX_WIDTH;
+	if (*h > IMAGE_MAX_HEIGHT)
+		*h = IMAGE_MAX_HEIGHT;
+
+	*w = (*w + 1) & ~1;
+	if (offsets)
+		offsets[0] = 0;
+
+	switch (id) {
+	case FOURCC_YUY2:
+	default:
+		size = *w << 1;
+		if (pitches)
+			pitches[0] = size;
+		size *= *h;
+		break;
+	}
+
+	return size;
+}
+
+XF86VideoAdaptorPtr intel_setup_sprite(ScreenPtr screen)
+{
+	ScrnInfoPtr scrn = xf86Screens[screen->myNum];
+	intel_screen_private *intel = intel_get_screen_private(scrn);
+	XF86VideoAdaptorPtr adapt;
+	intel_adaptor_private *adaptor_priv;
+	drmModePlaneRes *plane_resources;
+	drmModePlane *planes;
+
+	adapt = calloc(1, sizeof(XF86VideoAdaptorRec) +
+		       sizeof(intel_adaptor_private) + sizeof(DevUnion));
+	if (!adapt)
+		goto err;
+
+	plane_resources = drmModeGetPlaneResources(intel->drmSubFD);
+	if (!plane_resources) {
+		xf86DrvMsg(scrn->scrnIndex, X_INFO, "No sprite support\n");
+		goto err_free_adaptor;
+	}
+
+	planes = calloc(plane_resources->count_planes, sizeof(*planes));
+	if (!planes) {
+		xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Out of memory in %s\n",
+			   __func__);
+		goto err_free_res;
+	}
+
+	adapt->type = XvWindowMask | XvInputMask | XvImageMask;
+	adapt->flags = VIDEO_OVERLAID_IMAGES /*| VIDEO_CLIP_TO_VIEWPORT */ ;
+	adapt->name = "Intel(R) Video Sprite";
+	adapt->nEncodings = ARRAY_SIZE(xv_dummy_encoding);
+	adapt->pEncodings = xnfalloc(sizeof(xv_dummy_encoding));
+	memcpy(adapt->pEncodings, xv_dummy_encoding, sizeof(xv_dummy_encoding));
+	adapt->nFormats = ARRAY_SIZE(xv_formats);
+	adapt->pFormats = xv_formats;
+	adapt->nPorts = 1;
+	adapt->pPortPrivates = (DevUnion *) (&adapt[1]);
+
+	adaptor_priv = (intel_adaptor_private *)&adapt->pPortPrivates[1];
+	adapt->pPortPrivates[0].ptr = (pointer) (adaptor_priv);
+
+	adapt->nAttributes = 0;
+	adapt->pAttributes = NULL;
+
+	adapt->nImages = ARRAY_SIZE(xv_images);
+	adapt->pImages = xv_images;
+
+	adapt->PutVideo = NULL;
+	adapt->PutStill = NULL;
+	adapt->GetVideo = NULL;
+	adapt->GetStill = NULL;
+	adapt->StopVideo = intel_sprite_stop;
+	adapt->SetPortAttribute = intel_sprite_set_attr;
+	adapt->GetPortAttribute = intel_sprite_get_attr;
+	adapt->QueryBestSize = intel_sprite_best_size;
+	adapt->PutImage = intel_sprite_put;
+	adapt->QueryImageAttributes = intel_sprite_query_attrs;
+
+	adaptor_priv->textured = FALSE;
+	adaptor_priv->colorKey = intel->colorKey & ((1 << scrn->depth) - 1);
+	adaptor_priv->brightness = -19;	/* (255/219) * -16 */
+	adaptor_priv->contrast = 75;	/* 255/219 * 64 */
+	adaptor_priv->saturation = 146;	/* 128/112 * 128 */
+	adaptor_priv->desired_crtc = NULL;
+	adaptor_priv->buf = NULL;
+	adaptor_priv->old_buf[0] = NULL;
+	adaptor_priv->old_buf[1] = NULL;
+	adaptor_priv->gamma5 = 0xc0c0c0;
+	adaptor_priv->gamma4 = 0x808080;
+	adaptor_priv->gamma3 = 0x404040;
+	adaptor_priv->gamma2 = 0x202020;
+	adaptor_priv->gamma1 = 0x101010;
+	adaptor_priv->gamma0 = 0x080808;
+	adaptor_priv->planes = planes;
+
+	adaptor_priv->rotation = RR_Rotate_0;
+
+	/* gotta uninit this someplace */
+	REGION_NULL(screen, &adaptor_priv->clip);
+
+	intel->sprite_adaptor = adapt;
+
+	free(plane_resources);
+
+	return adapt;
+
+err_free_res:
+	free(plane_resources);
+err_free_adaptor:
+	free(adapt);
+err:
+	return NULL;
+}
diff --git a/src/intel_video.c b/src/intel_video.c
index 021ca5f..c873d34 100644
--- a/src/intel_video.c
+++ b/src/intel_video.c
@@ -337,7 +337,8 @@  void I830InitVideo(ScreenPtr screen)
 	ScrnInfoPtr scrn = xf86Screens[screen->myNum];
 	intel_screen_private *intel = intel_get_screen_private(scrn);
 	XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
-	XF86VideoAdaptorPtr overlayAdaptor = NULL, texturedAdaptor = NULL;
+	XF86VideoAdaptorPtr overlayAdaptor = NULL, texturedAdaptor = NULL,
+		spriteAdaptor = NULL;
 	int num_adaptors;
 
 	num_adaptors = xf86XVListGenericAdaptors(scrn, &adaptors);
@@ -345,7 +346,7 @@  void I830InitVideo(ScreenPtr screen)
 	 * adaptors.
 	 */
 	newAdaptors =
-	    malloc((num_adaptors + 2) * sizeof(XF86VideoAdaptorPtr *));
+	    malloc((num_adaptors + 3) * sizeof(XF86VideoAdaptorPtr *));
 	if (newAdaptors == NULL)
 		return;
 
@@ -388,6 +389,13 @@  void I830InitVideo(ScreenPtr screen)
 		}
 	}
 
+
+	spriteAdaptor = intel_setup_sprite(screen);
+	if (spriteAdaptor) {
+		xf86DrvMsg(scrn->scrnIndex, X_INFO, "Set up video sprite\n");
+		adaptors[num_adaptors++] = spriteAdaptor;
+	}
+
 	if (overlayAdaptor && intel->XvPreferOverlay)
 		adaptors[num_adaptors++] = overlayAdaptor;
 
@@ -405,10 +413,9 @@  void I830InitVideo(ScreenPtr screen)
 		intel->XvEnabled = FALSE;
 	}
 
-#ifdef INTEL_XVMC
 	if (texturedAdaptor)
 		intel_xvmc_adaptor_init(screen);
-#endif
+
 	free(adaptors);
 }
 
@@ -1226,7 +1233,7 @@  intel_display_overlay(ScrnInfoPtr scrn, xf86CrtcPtr crtc,
 					 src_w, src_h, drw_w, drw_h);
 }
 
-static Bool
+Bool
 intel_clip_video_helper(ScrnInfoPtr scrn,
 			intel_adaptor_private *adaptor_priv,
 			xf86CrtcPtr * crtc_ret,
diff --git a/src/intel_video.h b/src/intel_video.h
index f405d40..6dd7f88 100644
--- a/src/intel_video.h
+++ b/src/intel_video.h
@@ -55,6 +55,8 @@  typedef struct {
 	drm_intel_bo *buf, *old_buf[2];
 	Bool reusable;
 
+	struct _drmModePlane *planes;
+
 	Bool textured;
 	Rotation rotation;	/* should remove intel->rotation later */
 
@@ -67,6 +69,12 @@  intel_get_adaptor_private(intel_screen_private *intel)
 	return intel->adaptor->pPortPrivates[0].ptr;
 }
 
+static inline intel_adaptor_private *
+intel_get_sprite_adaptor_private(intel_screen_private *intel)
+{
+	return intel->sprite_adaptor->pPortPrivates[0].ptr;
+}
+
 void I915DisplayVideoTextured(ScrnInfoPtr scrn,
 			      intel_adaptor_private *adaptor_priv,
 			      int id, RegionPtr dstRegion, short width,
@@ -93,3 +101,16 @@  void i965_free_video(ScrnInfoPtr scrn);
 int is_planar_fourcc(int id);
 
 void intel_video_block_handler(intel_screen_private *intel);
+
+extern Bool intel_clip_video_helper(ScrnInfoPtr scrn,
+				    intel_adaptor_private *adaptor_priv,
+				    xf86CrtcPtr * crtc_ret,
+				    BoxPtr dst,
+				    short src_x, short src_y,
+				    short drw_x, short drw_y,
+				    short src_w, short src_h,
+				    short drw_w, short drw_h,
+				    int id,
+				    int *top, int* left, int* npixels,
+				    int *nlines,
+				    RegionPtr reg, INT32 width, INT32 height);