1220 lines
31 KiB
C
1220 lines
31 KiB
C
/*
|
|
* Copyright (c) 2019, Fuzhou Rockchip Electronics Co., Ltd
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#ifdef HAVE_DIX_CONFIG_H
|
|
#include "dix-config.h"
|
|
#endif
|
|
|
|
#include "exa.h"
|
|
#include "xf86.h"
|
|
#include "driver.h"
|
|
#include "dumb_bo.h"
|
|
#include "fbpict.h"
|
|
|
|
#include <unistd.h>
|
|
|
|
#ifdef MODESETTING_WITH_RGA
|
|
#include <rga/rga.h>
|
|
#include <rga/RgaApi.h>
|
|
|
|
#define RGA_MIN_LINEWIDTH 2
|
|
|
|
/* See rga_get_pixmap_format */
|
|
#define PIXMAP_IS_YUV(pix) ((pix)->drawable.bitsPerPixel == 12)
|
|
#endif
|
|
|
|
#define ABS(n) ((n) < 0 ? -(n) : (n))
|
|
#define ANGLE(n) ((n) < 0 ? (n) + 360 : (n))
|
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
|
|
|
typedef struct {
|
|
struct dumb_bo *bo;
|
|
int fd;
|
|
int pitch;
|
|
Bool owned;
|
|
} ms_exa_pixmap_priv;
|
|
|
|
typedef struct {
|
|
struct {
|
|
int alu;
|
|
Pixel planemask;
|
|
Pixel fg;
|
|
} solid;
|
|
struct {
|
|
PixmapPtr pSrcPixmap;
|
|
int alu;
|
|
Pixel planemask;
|
|
} copy;
|
|
struct {
|
|
int op;
|
|
PicturePtr pSrcPicture;
|
|
PicturePtr pMaskPicture;
|
|
PicturePtr pDstPicture;
|
|
PixmapPtr pSrc;
|
|
PixmapPtr pMask;
|
|
PixmapPtr pDst;
|
|
|
|
int rotate;
|
|
Bool reflect_y;
|
|
} composite;
|
|
} ms_exa_prepare_args;
|
|
|
|
typedef struct {
|
|
ms_exa_pixmap_priv *scratch_pixmap;
|
|
ms_exa_prepare_args prepare_args;
|
|
} ms_exa_ctx;
|
|
|
|
#ifdef MODESETTING_WITH_RGA
|
|
|
|
static inline RgaSURF_FORMAT
|
|
rga_get_pixmap_format(PixmapPtr pPix)
|
|
{
|
|
switch (pPix->drawable.bitsPerPixel) {
|
|
case 32:
|
|
if (pPix->drawable.depth == 32)
|
|
return RK_FORMAT_BGRA_8888;
|
|
return RK_FORMAT_BGRX_8888;
|
|
case 12:
|
|
switch (pPix->drawable.depth) {
|
|
case 12:
|
|
return RK_FORMAT_YCbCr_420_SP;
|
|
/* HACK: Special depth for NV12_10 and NV16*/
|
|
case 10:
|
|
return RK_FORMAT_YCbCr_420_SP_10B;
|
|
default:
|
|
return RK_FORMAT_YCbCr_422_SP;
|
|
}
|
|
default:
|
|
return RK_FORMAT_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
static Bool
|
|
rga_prepare_info(PixmapPtr pPixmap, rga_info_t *info,
|
|
int x, int y, int w, int h)
|
|
{
|
|
ms_exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap);
|
|
RgaSURF_FORMAT format;
|
|
int pitch, wstride, hstride;
|
|
|
|
memset(info, 0, sizeof(rga_info_t));
|
|
|
|
info->fd = -1;
|
|
info->mmuFlag = 1;
|
|
|
|
if (priv && priv->fd) {
|
|
info->fd = priv->fd;
|
|
pitch = priv->pitch;
|
|
} else {
|
|
info->virAddr = pPixmap->devPrivate.ptr;
|
|
pitch = pPixmap->devKind;
|
|
}
|
|
|
|
format = rga_get_pixmap_format(pPixmap);
|
|
|
|
/* rga requires yuv image rect align to 2 */
|
|
if (PIXMAP_IS_YUV(pPixmap)) {
|
|
x = (x + 1) & ~1;
|
|
y = (y + 1) & ~1;
|
|
w = w & ~1;
|
|
h = h & ~1;
|
|
}
|
|
|
|
/* rga requires image width/height larger than 2 */
|
|
if (w <= RGA_MIN_LINEWIDTH || h <= RGA_MIN_LINEWIDTH)
|
|
return FALSE;
|
|
|
|
wstride = pitch * 8 / pPixmap->drawable.bitsPerPixel;
|
|
hstride = pPixmap->drawable.height;
|
|
if (x < 0 || y < 0 || x + w > wstride || y + h > hstride)
|
|
return FALSE;
|
|
|
|
rga_set_rect(&info->rect, x, y, w, h, wstride, hstride, format);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static Bool
|
|
rga_check_pixmap(PixmapPtr pPixmap)
|
|
{
|
|
ms_exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap);
|
|
RgaSURF_FORMAT format;
|
|
|
|
/* rga requires image width/height larger than 2 */
|
|
if (pPixmap->drawable.width <= RGA_MIN_LINEWIDTH &&
|
|
pPixmap->drawable.height <= RGA_MIN_LINEWIDTH)
|
|
return FALSE;
|
|
|
|
format = rga_get_pixmap_format(pPixmap);
|
|
if (format == RK_FORMAT_UNKNOWN)
|
|
return FALSE;
|
|
|
|
if (pPixmap->devKind && pPixmap->devPrivate.ptr)
|
|
return TRUE;
|
|
|
|
return priv && priv->fd;
|
|
}
|
|
|
|
#endif
|
|
|
|
static void ms_exa_done(PixmapPtr pPixmap) {}
|
|
|
|
Bool
|
|
ms_exa_prepare_access(PixmapPtr pPix, int index)
|
|
{
|
|
ScreenPtr screen = pPix->drawable.pScreen;
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
ms_exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPix);
|
|
|
|
if (pPix->devPrivate.ptr)
|
|
return TRUE;
|
|
|
|
if (!priv)
|
|
return FALSE;
|
|
|
|
dumb_bo_map(ms->drmmode.fd, priv->bo);
|
|
|
|
pPix->devPrivate.ptr = priv->bo->ptr;
|
|
|
|
return pPix->devPrivate.ptr != NULL;
|
|
}
|
|
|
|
void
|
|
ms_exa_finish_access(PixmapPtr pPix, int index)
|
|
{
|
|
ms_exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPix);
|
|
|
|
if (priv && priv->bo)
|
|
pPix->devPrivate.ptr = NULL;
|
|
}
|
|
|
|
static Bool
|
|
ms_exa_prepare_solid(PixmapPtr pPixmap,
|
|
int alu, Pixel planemask, Pixel fg)
|
|
{
|
|
ScreenPtr screen = pPixmap->drawable.pScreen;
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
ms_exa_ctx *ctx = ms->drmmode.exa->priv;
|
|
|
|
#ifdef MODESETTING_WITH_RGA
|
|
//int rop;
|
|
|
|
if (planemask != ~0U)
|
|
return FALSE;
|
|
|
|
if (!rga_check_pixmap(pPixmap))
|
|
return FALSE;
|
|
|
|
/* TODO: Support rop */
|
|
switch (alu) {
|
|
case GXcopy:
|
|
break;
|
|
case GXclear:
|
|
case GXset:
|
|
case GXcopyInverted:
|
|
default:
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
ctx->prepare_args.solid.alu = alu;
|
|
ctx->prepare_args.solid.planemask = planemask;
|
|
ctx->prepare_args.solid.fg = fg;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
ms_exa_solid_bail(PixmapPtr pPixmap, int x1, int y1, int x2, int y2)
|
|
{
|
|
ScreenPtr screen = pPixmap->drawable.pScreen;
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
ms_exa_ctx *ctx = ms->drmmode.exa->priv;
|
|
|
|
ChangeGCVal val[3];
|
|
GCPtr gc;
|
|
|
|
gc = GetScratchGC(pPixmap->drawable.depth, screen);
|
|
|
|
val[0].val = ctx->prepare_args.solid.alu;
|
|
val[1].val = ctx->prepare_args.solid.planemask;
|
|
val[2].val = ctx->prepare_args.solid.fg;
|
|
ChangeGC(NullClient, gc, GCFunction | GCPlaneMask | GCForeground, val);
|
|
ValidateGC(&pPixmap->drawable, gc);
|
|
|
|
ms_exa_prepare_access(pPixmap, 0);
|
|
fbFill(&pPixmap->drawable, gc, x1, y1, x2 - x1, y2 - y1);
|
|
ms_exa_finish_access(pPixmap, 0);
|
|
|
|
FreeScratchGC(gc);
|
|
}
|
|
|
|
static void
|
|
ms_exa_solid(PixmapPtr pPixmap, int x1, int y1, int x2, int y2)
|
|
{
|
|
#ifdef MODESETTING_WITH_RGA
|
|
ScreenPtr screen = pPixmap->drawable.pScreen;
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
ms_exa_ctx *ctx = ms->drmmode.exa->priv;
|
|
|
|
rga_info_t dst_info = {0};
|
|
int width = x2 - x1;
|
|
int height = y2 - y1;
|
|
|
|
/* skip small images */
|
|
if (width * height <= 4096)
|
|
goto bail;
|
|
|
|
if (!rga_prepare_info(pPixmap, &dst_info, x1, y1, x2 - x1, y2 - y1))
|
|
goto bail;
|
|
|
|
dst_info.color = ctx->prepare_args.solid.fg;
|
|
|
|
/* rga only support RGBA8888 for color fill */
|
|
if (pPixmap->drawable.bitsPerPixel != 32)
|
|
goto bail;
|
|
|
|
if (pPixmap->drawable.depth == 24)
|
|
dst_info.color |= 0xFF << 24;
|
|
|
|
dst_info.rect.format = RK_FORMAT_RGBA_8888;
|
|
|
|
if (c_RkRgaColorFill(&dst_info) < 0)
|
|
goto bail;
|
|
|
|
return;
|
|
|
|
bail:
|
|
#endif
|
|
|
|
ms_exa_solid_bail(pPixmap, x1, y1, x2, y2);
|
|
}
|
|
|
|
static Bool
|
|
ms_exa_prepare_copy(PixmapPtr pSrcPixmap,
|
|
PixmapPtr pDstPixmap,
|
|
int dx, int dy, int alu, Pixel planemask)
|
|
{
|
|
ScreenPtr screen = pSrcPixmap->drawable.pScreen;
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
ms_exa_ctx *ctx = ms->drmmode.exa->priv;
|
|
|
|
#ifdef MODESETTING_WITH_RGA
|
|
//int rop;
|
|
|
|
if (planemask != ~0U)
|
|
return FALSE;
|
|
|
|
if (!rga_check_pixmap(pSrcPixmap))
|
|
return FALSE;
|
|
|
|
if (!rga_check_pixmap(pDstPixmap))
|
|
return FALSE;
|
|
|
|
/* TODO: Support rop */
|
|
switch (alu) {
|
|
case GXcopy:
|
|
break;
|
|
case GXclear:
|
|
case GXset:
|
|
case GXcopyInverted:
|
|
default:
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
ctx->prepare_args.copy.pSrcPixmap = pSrcPixmap;
|
|
ctx->prepare_args.copy.alu = alu;
|
|
ctx->prepare_args.copy.planemask = planemask;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
ms_exa_copy_bail(PixmapPtr pDstPixmap, int srcX, int srcY,
|
|
int dstX, int dstY, int width, int height)
|
|
{
|
|
ScreenPtr screen = pDstPixmap->drawable.pScreen;
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
ms_exa_ctx *ctx = ms->drmmode.exa->priv;
|
|
|
|
PixmapPtr pSrcPixmap = ctx->prepare_args.copy.pSrcPixmap;
|
|
ChangeGCVal val[2];
|
|
GCPtr gc;
|
|
|
|
gc = GetScratchGC(pDstPixmap->drawable.depth, screen);
|
|
|
|
val[0].val = ctx->prepare_args.copy.alu;
|
|
val[1].val = ctx->prepare_args.copy.planemask;
|
|
ChangeGC(NullClient, gc, GCFunction | GCPlaneMask, val);
|
|
ValidateGC(&pDstPixmap->drawable, gc);
|
|
|
|
ms_exa_prepare_access(pSrcPixmap, 0);
|
|
ms_exa_prepare_access(pDstPixmap, 0);
|
|
fbCopyArea(&pSrcPixmap->drawable, &pDstPixmap->drawable, gc,
|
|
srcX, srcY, width, height, dstX, dstY);
|
|
ms_exa_finish_access(pDstPixmap, 0);
|
|
ms_exa_finish_access(pSrcPixmap, 0);
|
|
|
|
FreeScratchGC(gc);
|
|
}
|
|
|
|
static void
|
|
ms_exa_copy(PixmapPtr pDstPixmap, int srcX, int srcY,
|
|
int dstX, int dstY, int width, int height)
|
|
{
|
|
#ifdef MODESETTING_WITH_RGA
|
|
ScreenPtr screen = pDstPixmap->drawable.pScreen;
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
ms_exa_ctx *ctx = ms->drmmode.exa->priv;
|
|
|
|
PixmapPtr pSrcPixmap = ctx->prepare_args.copy.pSrcPixmap;
|
|
rga_info_t src_info = {0};
|
|
rga_info_t dst_info = {0};
|
|
rga_info_t tmp_info = {0};
|
|
|
|
/* skip small images */
|
|
if (width * height <= 4096)
|
|
goto bail;
|
|
|
|
if (!rga_prepare_info(pSrcPixmap, &src_info, srcX, srcY, width, height))
|
|
goto bail;
|
|
|
|
if (!rga_prepare_info(pDstPixmap, &dst_info, dstX, dstY, width, height))
|
|
goto bail;
|
|
|
|
/* need an extra buffer for overlap copy */
|
|
if (pSrcPixmap == pDstPixmap &&
|
|
(ABS(dstX - srcX) < width || ABS(dstY - srcX) < height)) {
|
|
tmp_info.fd = ctx->scratch_pixmap->fd;
|
|
tmp_info.mmuFlag = 1;
|
|
|
|
rga_set_rect(&tmp_info.rect, 0, 0, width, height,
|
|
width, height, rga_get_pixmap_format(pDstPixmap));
|
|
|
|
if (c_RkRgaBlit(&src_info, &tmp_info, NULL) < 0)
|
|
goto bail;
|
|
|
|
src_info = tmp_info;
|
|
}
|
|
|
|
if (c_RkRgaBlit(&src_info, &dst_info, NULL) < 0)
|
|
goto bail;
|
|
|
|
return;
|
|
|
|
bail:
|
|
#endif
|
|
|
|
ms_exa_copy_bail(pDstPixmap, srcX, srcY, dstX, dstY, width, height);
|
|
}
|
|
|
|
static Bool
|
|
ms_exa_check_composite(int op,
|
|
PicturePtr pSrcPicture,
|
|
PicturePtr pMaskPicture, PicturePtr pDstPicture)
|
|
{
|
|
#ifdef MODESETTING_WITH_RGA
|
|
/* TODO: Support other op */
|
|
if (op != PictOpSrc && op != PictOpOver)
|
|
return FALSE;
|
|
|
|
/* TODO: Support mask */
|
|
if (pMaskPicture)
|
|
return FALSE;
|
|
|
|
/* TODO: Multiply transform from src and dst */
|
|
if (pDstPicture->transform)
|
|
return FALSE;
|
|
#endif
|
|
|
|
if (!pSrcPicture->pDrawable)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static Bool
|
|
ms_exa_parse_transform(PictTransformPtr t, int *rotate, Bool *reflect_y)
|
|
{
|
|
PictVector v;
|
|
double x, y, dx, dy;
|
|
int r1, r2;
|
|
|
|
if (!t) {
|
|
*rotate = 0;
|
|
*reflect_y = FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
/* Only support affine matrix */
|
|
if (t->matrix[2][0] || t->matrix[2][1] || !t->matrix[2][2])
|
|
return FALSE;
|
|
|
|
dx = t->matrix[0][2] / (double) t->matrix[2][2];
|
|
dy = t->matrix[1][2] / (double) t->matrix[2][2];
|
|
|
|
v.vector[0] = IntToxFixed(1);
|
|
v.vector[1] = IntToxFixed(0);
|
|
v.vector[2] = xFixed1;
|
|
PictureTransformPoint(t, &v);
|
|
x = pixman_fixed_to_double(v.vector[0]) - dx;
|
|
y = pixman_fixed_to_double(v.vector[1]) - dy;
|
|
r1 = (int) ANGLE(atan2(y, x) * 180 / M_PI);
|
|
|
|
/* Only support 0/90/180/270 rotations */
|
|
if (r1 % 90)
|
|
return FALSE;
|
|
|
|
v.vector[0] = IntToxFixed(0);
|
|
v.vector[1] = IntToxFixed(1);
|
|
v.vector[2] = xFixed1;
|
|
PictureTransformPoint(t, &v);
|
|
x = pixman_fixed_to_double(v.vector[0]) - dx;
|
|
y = pixman_fixed_to_double(v.vector[1]) - dy;
|
|
r2 = (int) ANGLE(atan2(y, x) * 180 / M_PI - 90);
|
|
|
|
*rotate = (360 - r1) % 360;
|
|
*reflect_y = r1 != r2;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static Bool
|
|
ms_exa_prepare_composite(int op,
|
|
PicturePtr pSrcPicture,
|
|
PicturePtr pMaskPicture,
|
|
PicturePtr pDstPicture,
|
|
PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst)
|
|
{
|
|
ScreenPtr screen = pSrc->drawable.pScreen;
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
ms_exa_ctx *ctx = ms->drmmode.exa->priv;
|
|
|
|
#ifdef MODESETTING_WITH_RGA
|
|
PictTransformPtr t = pSrcPicture->transform;
|
|
|
|
if (!rga_check_pixmap(pSrc))
|
|
return FALSE;
|
|
|
|
if (!rga_check_pixmap(pDst))
|
|
return FALSE;
|
|
|
|
if (pDst == pSrc)
|
|
return FALSE;
|
|
|
|
/* TODO: Support repeat */
|
|
if (pSrcPicture->repeat)
|
|
return FALSE;
|
|
|
|
/* TODO: Handle pSrcPicture->filter */
|
|
|
|
if (!ms_exa_parse_transform(t, &ctx->prepare_args.composite.rotate,
|
|
&ctx->prepare_args.composite.reflect_y))
|
|
return FALSE;
|
|
#endif
|
|
ctx->prepare_args.composite.op = op;
|
|
ctx->prepare_args.composite.pSrcPicture = pSrcPicture;
|
|
ctx->prepare_args.composite.pMaskPicture = pMaskPicture;
|
|
ctx->prepare_args.composite.pDstPicture = pDstPicture;
|
|
ctx->prepare_args.composite.pSrc = pSrc;
|
|
ctx->prepare_args.composite.pMask = pMask;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static inline void
|
|
ms_exa_composite_fix_offsets(DrawablePtr pDrawable, PixmapPtr pPix,
|
|
int *xoff, int *yoff)
|
|
{
|
|
// Base on fb/fb.h#fbGetDrawablePixmap
|
|
if (pDrawable->type != DRAWABLE_PIXMAP) {
|
|
ScreenPtr pScreen = pDrawable->pScreen;
|
|
pPix = pScreen->GetWindowPixmap((WindowPtr) pDrawable);
|
|
|
|
#ifdef COMPOSITE
|
|
*xoff -= pPix->drawable.x - pPix->screen_x;
|
|
*yoff -= pPix->drawable.y - pPix->screen_y;
|
|
#else
|
|
*xoff -= pPix->drawable.x;
|
|
*yoff -= pPix->drawable.y;
|
|
#endif
|
|
} else {
|
|
*xoff -= pDrawable->x;
|
|
*yoff -= pDrawable->y;
|
|
}
|
|
|
|
// Based on fb/fbpict.c#create_bits_picture
|
|
*xoff -= pDrawable->x;
|
|
*yoff -= pDrawable->y;
|
|
}
|
|
|
|
static void
|
|
ms_exa_composite_bail(PixmapPtr pDst, int srcX, int srcY,
|
|
int maskX, int maskY, int dstX, int dstY,
|
|
int width, int height)
|
|
{
|
|
ScreenPtr screen = pDst->drawable.pScreen;
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
ms_exa_ctx *ctx = ms->drmmode.exa->priv;
|
|
|
|
PicturePtr pSrcPicture = ctx->prepare_args.composite.pSrcPicture;
|
|
PicturePtr pMaskPicture = ctx->prepare_args.composite.pMaskPicture;
|
|
PicturePtr pDstPicture = ctx->prepare_args.composite.pDstPicture;
|
|
PixmapPtr pSrc = ctx->prepare_args.composite.pSrc;
|
|
PixmapPtr pMask = ctx->prepare_args.composite.pMask;
|
|
int op = ctx->prepare_args.composite.op;
|
|
|
|
if (pMask)
|
|
ms_exa_prepare_access(pMask, 0);
|
|
|
|
ms_exa_prepare_access(pSrc, 0);
|
|
ms_exa_prepare_access(pDst, 0);
|
|
|
|
ms_exa_composite_fix_offsets(pSrcPicture->pDrawable, pSrc, &srcX, &srcY);
|
|
ms_exa_composite_fix_offsets(pDstPicture->pDrawable, pDst, &dstX, &dstY);
|
|
if (pMaskPicture && pMask)
|
|
ms_exa_composite_fix_offsets(pMaskPicture->pDrawable,
|
|
pMask, &maskX, &maskY);
|
|
|
|
fbComposite(op, pSrcPicture, pMaskPicture, pDstPicture,
|
|
srcX, srcY, maskX, maskY,
|
|
dstX, dstY, width, height);
|
|
|
|
ms_exa_finish_access(pDst, 0);
|
|
ms_exa_finish_access(pSrc, 0);
|
|
|
|
if (pMask)
|
|
ms_exa_finish_access(pMask, 0);
|
|
}
|
|
|
|
static void
|
|
ms_exa_composite(PixmapPtr pDst, int srcX, int srcY,
|
|
int maskX, int maskY, int dstX, int dstY,
|
|
int width, int height)
|
|
{
|
|
#ifdef MODESETTING_WITH_RGA
|
|
ScreenPtr screen = pDst->drawable.pScreen;
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
ms_exa_ctx *ctx = ms->drmmode.exa->priv;
|
|
|
|
PictTransformPtr t = ctx->prepare_args.composite.pSrcPicture->transform;
|
|
PixmapPtr pSrc = ctx->prepare_args.composite.pSrc;
|
|
BoxRec box = {
|
|
.x1 = srcX,
|
|
.y1 = srcY,
|
|
.x2 = srcX + width,
|
|
.y2 = srcY + height,
|
|
};
|
|
rga_info_t src_info = {0};
|
|
rga_info_t dst_info = {0};
|
|
rga_info_t tmp_info = {0};
|
|
Bool reflect_y = ctx->prepare_args.composite.reflect_y;
|
|
int rotate = ctx->prepare_args.composite.rotate;
|
|
int op = ctx->prepare_args.composite.op;
|
|
int sw, sh, blend = 0;
|
|
|
|
/* skip small images */
|
|
if (width * height <= 4096)
|
|
goto bail;
|
|
|
|
if (t)
|
|
pixman_transform_bounds(t, &box);
|
|
|
|
sw = box.x2 - box.x1;
|
|
sh = box.y2 - box.y1;
|
|
|
|
/* rga has scale limits */
|
|
if ((double)sw / width > 16 || (double)width / sw > 16 ||
|
|
(double)sh / height > 16 || (double)height / sh > 16)
|
|
goto bail;
|
|
|
|
if (!rga_prepare_info(pSrc, &src_info, box.x1, box.y1, sw, sh))
|
|
goto bail;
|
|
|
|
if (!rga_prepare_info(pDst, &dst_info, dstX, dstY, width, height))
|
|
goto bail;
|
|
|
|
/* dst = src + (1 - src.a) * dst */
|
|
if (op == PictOpOver)
|
|
blend = 0xFF0405;
|
|
|
|
if (rotate == 90)
|
|
src_info.rotation = HAL_TRANSFORM_ROT_90;
|
|
else if (rotate == 180)
|
|
src_info.rotation = HAL_TRANSFORM_ROT_180;
|
|
else if (rotate == 270)
|
|
src_info.rotation = HAL_TRANSFORM_ROT_270;
|
|
|
|
/* need an extra buffer for reflect + rotate composite */
|
|
if (reflect_y && rotate) {
|
|
tmp_info.fd = ctx->scratch_pixmap->fd;
|
|
tmp_info.mmuFlag = 1;
|
|
|
|
rga_set_rect(&tmp_info.rect, 0, 0, width, height,
|
|
width, height, rga_get_pixmap_format(pDst));
|
|
|
|
src_info.blend = blend;
|
|
if (c_RkRgaBlit(&src_info, &tmp_info, NULL) < 0)
|
|
goto bail;
|
|
|
|
src_info = tmp_info;
|
|
}
|
|
|
|
if (reflect_y)
|
|
src_info.rotation = HAL_TRANSFORM_FLIP_V;
|
|
|
|
src_info.blend = blend;
|
|
if (c_RkRgaBlit(&src_info, &dst_info, NULL) < 0)
|
|
goto bail;
|
|
|
|
return;
|
|
|
|
bail:
|
|
#endif
|
|
|
|
ms_exa_composite_bail(pDst, srcX, srcY, maskX, maskY,
|
|
dstX, dstY, width, height);
|
|
}
|
|
|
|
static Bool
|
|
ms_exa_upload_to_screen(PixmapPtr pDst, int x, int y, int w, int h,
|
|
char *src, int src_pitch)
|
|
{
|
|
#ifndef MODESETTING_WITH_RGA
|
|
return FALSE;
|
|
#else
|
|
ScreenPtr screen = pDst->drawable.pScreen;
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
ms_exa_ctx *ctx = ms->drmmode.exa->priv;
|
|
|
|
PixmapPtr pixmap;
|
|
Bool ret = FALSE;
|
|
|
|
/* rga requires image width/height larger than 2 */
|
|
if (w <= RGA_MIN_LINEWIDTH || h <= RGA_MIN_LINEWIDTH)
|
|
return FALSE;
|
|
|
|
/* skip small images */
|
|
if (w * h <= 4096)
|
|
return FALSE;
|
|
|
|
if (!rga_check_pixmap(pDst))
|
|
return FALSE;
|
|
|
|
/* copy the h-1 lines */
|
|
h -= 1;
|
|
pixmap = drmmode_create_pixmap_header(screen, w, h,
|
|
pDst->drawable.depth,
|
|
pDst->drawable.bitsPerPixel,
|
|
src_pitch, NULL);
|
|
if (!pixmap)
|
|
goto out;
|
|
|
|
pixmap->devKind = src_pitch;
|
|
pixmap->devPrivate.ptr = src;
|
|
ctx->prepare_args.copy.pSrcPixmap = pixmap;
|
|
ms_exa_copy(pDst, 0, 0, x, y, w, h);
|
|
|
|
screen->DestroyPixmap(pixmap);
|
|
|
|
/* copy the last line separately */
|
|
pixmap = drmmode_create_pixmap_header(screen, w, 1,
|
|
pDst->drawable.depth,
|
|
pDst->drawable.bitsPerPixel,
|
|
src_pitch, NULL);
|
|
if (!pixmap)
|
|
goto out;
|
|
|
|
pixmap->devKind = w * pDst->drawable.bitsPerPixel / 8;
|
|
pixmap->devPrivate.ptr = src + src_pitch * h;
|
|
ctx->prepare_args.copy.pSrcPixmap = pixmap;
|
|
ms_exa_copy(pDst, 0, 0, x, y + h, w, 1);
|
|
|
|
ret = TRUE;
|
|
|
|
out:
|
|
if (pixmap)
|
|
screen->DestroyPixmap(pixmap);
|
|
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
static Bool
|
|
ms_exa_download_from_screen(PixmapPtr pSrc, int x, int y, int w, int h,
|
|
char *dst, int dst_pitch)
|
|
{
|
|
#ifndef MODESETTING_WITH_RGA
|
|
return FALSE;
|
|
#else
|
|
ScreenPtr screen = pSrc->drawable.pScreen;
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
ms_exa_ctx *ctx = ms->drmmode.exa->priv;
|
|
|
|
PixmapPtr pixmap;
|
|
Bool ret = FALSE;
|
|
|
|
/* rga requires image width/height larger than 2 */
|
|
if (w <= RGA_MIN_LINEWIDTH || h <= RGA_MIN_LINEWIDTH)
|
|
return FALSE;
|
|
|
|
/* skip small images */
|
|
if (w * h <= 4096)
|
|
return FALSE;
|
|
|
|
if (!rga_check_pixmap(pSrc))
|
|
return FALSE;
|
|
|
|
ctx->prepare_args.copy.pSrcPixmap = pSrc;
|
|
|
|
/* copy the h-1 lines */
|
|
h -= 1;
|
|
pixmap = drmmode_create_pixmap_header(screen, w, h,
|
|
pSrc->drawable.depth,
|
|
pSrc->drawable.bitsPerPixel,
|
|
dst_pitch, NULL);
|
|
if (!pixmap)
|
|
goto out;
|
|
|
|
pixmap->devKind = dst_pitch;
|
|
pixmap->devPrivate.ptr = dst;
|
|
ms_exa_copy(pixmap, x, y, 0, 0, w, h);
|
|
|
|
screen->DestroyPixmap(pixmap);
|
|
|
|
/* copy the last line separately */
|
|
pixmap = drmmode_create_pixmap_header(screen, w, 1,
|
|
pSrc->drawable.depth,
|
|
pSrc->drawable.bitsPerPixel,
|
|
dst_pitch, NULL);
|
|
if (!pixmap)
|
|
goto out;
|
|
|
|
pixmap->devKind = w * pSrc->drawable.bitsPerPixel / 8;
|
|
pixmap->devPrivate.ptr = dst + dst_pitch * h;
|
|
ms_exa_copy(pixmap, x, y + h, 0, 0, w, 1);
|
|
|
|
ret = TRUE;
|
|
|
|
out:
|
|
if (pixmap)
|
|
screen->DestroyPixmap(pixmap);
|
|
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
ms_exa_wait_marker(ScreenPtr pScreen, int marker)
|
|
{
|
|
// TODO: Use async rga, and sync for specified request here.
|
|
}
|
|
|
|
static int
|
|
ms_exa_mark_sync(ScreenPtr pScreen)
|
|
{
|
|
// TODO: return latest request(marker).
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
ms_exa_destroy_pixmap(ScreenPtr pScreen, void *driverPriv)
|
|
{
|
|
ScrnInfoPtr scrn = xf86Screens[pScreen->myNum];
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
ms_exa_pixmap_priv *priv = driverPriv;
|
|
|
|
if (priv->fd > 0)
|
|
close(priv->fd);
|
|
|
|
if (priv->owned && priv->bo)
|
|
dumb_bo_destroy(ms->drmmode.fd, priv->bo);
|
|
|
|
free(priv);
|
|
}
|
|
|
|
static void *
|
|
ms_exa_create_pixmap2(ScreenPtr pScreen, int width, int height,
|
|
int depth, int usage_hint, int bitsPerPixel,
|
|
int *new_fb_pitch)
|
|
{
|
|
ScrnInfoPtr scrn = xf86Screens[pScreen->myNum];
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
ms_exa_pixmap_priv *priv;
|
|
|
|
priv = calloc(1, sizeof(ms_exa_pixmap_priv));
|
|
if (!priv)
|
|
return NULL;
|
|
|
|
if (!width && !height)
|
|
return priv;
|
|
|
|
priv->bo = dumb_bo_create(ms->drmmode.fd, width, height, bitsPerPixel);
|
|
if (!priv->bo)
|
|
goto fail;
|
|
|
|
priv->owned = TRUE;
|
|
|
|
priv->fd = dumb_bo_get_fd(ms->drmmode.fd, priv->bo, 0);
|
|
priv->pitch = priv->bo->pitch;
|
|
|
|
if (new_fb_pitch)
|
|
*new_fb_pitch = priv->pitch;
|
|
|
|
return priv;
|
|
|
|
fail:
|
|
free(priv);
|
|
return NULL;
|
|
}
|
|
|
|
static Bool
|
|
ms_exa_pixmap_is_offscreen(PixmapPtr pPixmap)
|
|
{
|
|
ms_exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap);
|
|
|
|
return priv && priv->bo;
|
|
}
|
|
|
|
Bool
|
|
ms_exa_set_pixmap_bo(ScrnInfoPtr scrn, PixmapPtr pPixmap,
|
|
struct dumb_bo *bo, Bool owned)
|
|
{
|
|
ms_exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap);
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
|
|
if (!ms->drmmode.exa || !priv)
|
|
return FALSE;
|
|
|
|
if (priv->fd > 0)
|
|
close(priv->fd);
|
|
|
|
if (priv->owned && priv->bo)
|
|
dumb_bo_destroy(ms->drmmode.fd, priv->bo);
|
|
|
|
priv->bo = bo;
|
|
priv->fd = dumb_bo_get_fd(ms->drmmode.fd, priv->bo, 0);
|
|
priv->pitch = priv->bo->pitch;
|
|
|
|
priv->owned = owned;
|
|
|
|
pPixmap->devPrivate.ptr = NULL;
|
|
pPixmap->devKind = priv->pitch;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
struct dumb_bo *
|
|
ms_exa_bo_from_pixmap(ScreenPtr screen, PixmapPtr pixmap)
|
|
{
|
|
ms_exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pixmap);
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
|
|
if (!ms->drmmode.exa || !priv)
|
|
return NULL;
|
|
|
|
return priv->bo;
|
|
}
|
|
|
|
void
|
|
ms_exa_exchange_buffers(PixmapPtr front, PixmapPtr back)
|
|
{
|
|
ms_exa_pixmap_priv *front_priv = exaGetPixmapDriverPrivate(front);
|
|
ms_exa_pixmap_priv *back_priv = exaGetPixmapDriverPrivate(back);
|
|
ms_exa_pixmap_priv tmp_priv;
|
|
|
|
tmp_priv = *front_priv;
|
|
*front_priv = *back_priv;
|
|
*back_priv = tmp_priv;
|
|
}
|
|
|
|
Bool
|
|
ms_exa_back_pixmap_from_fd(PixmapPtr pixmap,
|
|
int fd,
|
|
CARD16 width,
|
|
CARD16 height,
|
|
CARD16 stride, CARD8 depth, CARD8 bpp)
|
|
{
|
|
ScreenPtr screen = pixmap->drawable.pScreen;
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
struct dumb_bo *bo;
|
|
Bool ret;
|
|
|
|
bo = dumb_get_bo_from_fd(ms->drmmode.fd, fd,
|
|
stride, stride * height);
|
|
if (!bo)
|
|
return FALSE;
|
|
|
|
screen->ModifyPixmapHeader(pixmap, width, height,
|
|
depth, bpp, stride, NULL);
|
|
|
|
ret = ms_exa_set_pixmap_bo(scrn, pixmap, bo, TRUE);
|
|
if (!ret)
|
|
dumb_bo_destroy(ms->drmmode.fd, bo);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
ms_exa_shareable_fd_from_pixmap(ScreenPtr screen,
|
|
PixmapPtr pixmap,
|
|
CARD16 *stride,
|
|
CARD32 *size)
|
|
{
|
|
ms_exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pixmap);
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
|
|
if (!ms->drmmode.exa || !priv || !priv->fd)
|
|
return -1;
|
|
|
|
return priv->fd;
|
|
}
|
|
|
|
Bool
|
|
ms_exa_copy_area(PixmapPtr pSrc, PixmapPtr pDst,
|
|
pixman_f_transform_t *transform, RegionPtr clip)
|
|
{
|
|
#ifdef MODESETTING_WITH_RGA
|
|
ScreenPtr screen = pSrc->drawable.pScreen;
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
rga_info_t src_info = {0};
|
|
rga_info_t dst_info = {0};
|
|
RegionPtr region = NULL;
|
|
BoxPtr box;
|
|
int n;
|
|
|
|
if (!ms->drmmode.exa)
|
|
goto bail;
|
|
|
|
if (!rga_check_pixmap(pSrc))
|
|
goto bail;
|
|
|
|
if (!rga_check_pixmap(pDst))
|
|
goto bail;
|
|
|
|
/* Fallback to compositor for rotate / reflect */
|
|
if (transform) {
|
|
pixman_transform_t t;
|
|
Bool reflect_y = FALSE;
|
|
int rotate = 0;
|
|
|
|
pixman_transform_from_pixman_f_transform(&t, transform);
|
|
if (!ms_exa_parse_transform(&t, &rotate, &reflect_y))
|
|
goto bail;
|
|
|
|
if (rotate || reflect_y)
|
|
goto bail;
|
|
}
|
|
|
|
region = RegionDuplicate(clip);
|
|
n = REGION_NUM_RECTS(region);
|
|
|
|
while(n--) {
|
|
int sx, sy, sw, sh, dx, dy, dw, dh;
|
|
box = REGION_RECTS(region) + n;
|
|
|
|
box->x1 = max(box->x1, 0);
|
|
box->y1 = max(box->y1, 0);
|
|
box->x2 = min(box->x2, pDst->drawable.width);
|
|
box->y2 = min(box->y2, pDst->drawable.height);
|
|
|
|
dx = box->x1;
|
|
dy = box->y1;
|
|
dw = box->x2 - box->x1;
|
|
dh = box->y2 - box->y1;
|
|
|
|
if (transform)
|
|
pixman_f_transform_bounds(transform, box);
|
|
|
|
sx = max(box->x1, 0);
|
|
sy = max(box->y1, 0);
|
|
sw = min(box->x2, pSrc->drawable.width) - sx;
|
|
sh = min(box->y2, pSrc->drawable.height) - sy;
|
|
|
|
/* rga has scale limits */
|
|
if ((double)sw / dw > 16 || (double)dw / sw > 16 ||
|
|
(double)sh / dh > 16 || (double)dh / sh > 16)
|
|
goto err;
|
|
|
|
if (!rga_prepare_info(pSrc, &src_info, sx, sy, sw, sh))
|
|
goto err;
|
|
|
|
if (!rga_prepare_info(pDst, &dst_info, dx, dy, dw, dh))
|
|
goto err;
|
|
|
|
if (!c_RkRgaBlit(&src_info, &dst_info, NULL))
|
|
continue;
|
|
err:
|
|
/* HACK: Ignoring errors for YUV, since xserver cannot handle it */
|
|
if (!PIXMAP_IS_YUV(pSrc) && !PIXMAP_IS_YUV(pDst))
|
|
goto bail;
|
|
}
|
|
|
|
RegionDestroy(region);
|
|
return TRUE;
|
|
|
|
bail:
|
|
if (region)
|
|
RegionDestroy(region);
|
|
#endif
|
|
|
|
return ms_copy_area(pSrc, pDst, transform, clip);
|
|
}
|
|
|
|
static inline void
|
|
ms_setup_exa(ExaDriverPtr exa)
|
|
{
|
|
exa->exa_major = EXA_VERSION_MAJOR;
|
|
exa->exa_minor = EXA_VERSION_MINOR;
|
|
|
|
exa->pixmapPitchAlign = 8;
|
|
exa->flags = EXA_OFFSCREEN_PIXMAPS;
|
|
exa->maxX = 4096;
|
|
exa->maxY = 4096;
|
|
|
|
exa->PrepareSolid = ms_exa_prepare_solid;
|
|
exa->Solid = ms_exa_solid;
|
|
exa->DoneSolid = ms_exa_done;
|
|
|
|
exa->PrepareCopy = ms_exa_prepare_copy;
|
|
exa->Copy = ms_exa_copy;
|
|
exa->DoneCopy = ms_exa_done;
|
|
|
|
exa->CheckComposite = ms_exa_check_composite;
|
|
exa->PrepareComposite = ms_exa_prepare_composite;
|
|
exa->Composite = ms_exa_composite;
|
|
exa->DoneComposite = ms_exa_done;
|
|
|
|
/* Disable upload/download, until rga2 crash issue fixed */
|
|
exa->UploadToScreen = ms_exa_upload_to_screen;
|
|
exa->DownloadFromScreen = ms_exa_download_from_screen;
|
|
|
|
exa->WaitMarker = ms_exa_wait_marker;
|
|
exa->MarkSync = ms_exa_mark_sync;
|
|
|
|
// bo based pixmap ops
|
|
exa->flags |= EXA_HANDLES_PIXMAPS | EXA_SUPPORTS_PREPARE_AUX;
|
|
|
|
exa->DestroyPixmap = ms_exa_destroy_pixmap;
|
|
exa->CreatePixmap2 = ms_exa_create_pixmap2;
|
|
exa->PrepareAccess = ms_exa_prepare_access;
|
|
exa->FinishAccess = ms_exa_finish_access;
|
|
exa->PixmapIsOffscreen = ms_exa_pixmap_is_offscreen;
|
|
}
|
|
|
|
Bool
|
|
ms_init_exa(ScrnInfoPtr scrn)
|
|
{
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
ScreenPtr screen = scrn->pScreen;
|
|
drmmode_exa *exa;
|
|
ms_exa_ctx *ctx;
|
|
|
|
if (ms->drmmode.exa)
|
|
ms_deinit_exa(scrn);
|
|
|
|
#ifdef MODESETTING_WITH_RGA
|
|
if (c_RkRgaInit() < 0)
|
|
return FALSE;
|
|
|
|
xf86DrvMsg(scrn->scrnIndex, X_INFO, "Using RGA EXA\n");
|
|
#else
|
|
xf86DrvMsg(scrn->scrnIndex, X_INFO, "Using software EXA\n");
|
|
#endif
|
|
|
|
ms->drmmode.exa = calloc(1, sizeof(drmmode_exa));
|
|
if (!ms->drmmode.exa)
|
|
return FALSE;
|
|
|
|
exa = ms->drmmode.exa;
|
|
exa->driver = exaDriverAlloc();
|
|
if (!exa->driver)
|
|
goto bail;
|
|
|
|
ms_setup_exa(exa->driver);
|
|
|
|
if (!exaDriverInit(screen, exa->driver))
|
|
goto bail;
|
|
|
|
exa->priv = calloc(1, sizeof(ms_exa_ctx));
|
|
if (!exa->priv)
|
|
goto bail;
|
|
|
|
ctx = exa->priv;
|
|
ctx->scratch_pixmap = ms_exa_create_pixmap2(screen,
|
|
exa->driver->maxX, exa->driver->maxY,
|
|
scrn->depth, 0,
|
|
scrn->bitsPerPixel,
|
|
NULL);
|
|
if (!ctx->scratch_pixmap)
|
|
goto bail;
|
|
|
|
return TRUE;
|
|
|
|
bail:
|
|
ms_deinit_exa(scrn);
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
ms_deinit_exa(ScrnInfoPtr scrn)
|
|
{
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
ScreenPtr screen = scrn->pScreen;
|
|
drmmode_exa *exa;
|
|
ms_exa_ctx *ctx;
|
|
|
|
if (!ms->drmmode.exa)
|
|
return;
|
|
|
|
exa = ms->drmmode.exa;
|
|
ctx = exa->priv;
|
|
|
|
if (ctx) {
|
|
if (ctx->scratch_pixmap)
|
|
ms_exa_destroy_pixmap(screen, ctx->scratch_pixmap);
|
|
|
|
free(ctx);
|
|
}
|
|
|
|
if (exa->driver) {
|
|
exaDriverFini(screen);
|
|
free(exa->driver);
|
|
}
|
|
|
|
free(exa);
|
|
ms->drmmode.exa = NULL;
|
|
|
|
#ifdef MODESETTING_WITH_RGA
|
|
c_RkRgaDeInit();
|
|
#endif
|
|
}
|