@@ -2,6 +2,8 @@ Entries are sorted chronologically from oldest to youngest within each release,
releases are sorted from youngest to oldest.
version <next>:
+- hwcontext_drm detiles non linear layouts, if possible
+- fbtile cpu based framebuffer tile/detile helpers
- kmsgrab GetFB2 format_modifier, if user doesnt specify
- AudioToolbox output device
- MacCaption demuxer
@@ -84,6 +84,7 @@ HEADERS = adler32.h \
xtea.h \
tea.h \
tx.h \
+ fbtile.h \
HEADERS-$(CONFIG_LZO) += lzo.h
@@ -169,6 +170,7 @@ OBJS = adler32.o \
tx_float.o \
tx_double.o \
tx_int32.o \
+ fbtile.o \
video_enc_params.o \
new file mode 100644
@@ -0,0 +1,434 @@
+/*
+ * CPU based Framebuffer Generic Tile DeTile logic
+ * Copyright (c) 2020 C Hanish Menon <HanishKVC>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "avutil.h"
+#include "common.h"
+#include "fbtile.h"
+#if CONFIG_LIBDRM
+#include <drm_fourcc.h>
+#endif
+
+
+SCOPEIN enum FBTileLayout fbtilelayoutid_from_drmformatmodifier(uint64_t formatModifier)
+{
+ enum FBTileLayout layout = FBTILE_UNKNOWN;
+
+#if CONFIG_LIBDRM
+ switch(formatModifier) {
+ case DRM_FORMAT_MOD_LINEAR:
+ layout = FBTILE_NONE;
+ break;
+ case I915_FORMAT_MOD_X_TILED:
+ layout = FBTILE_INTEL_XGEN9;
+ break;
+ case I915_FORMAT_MOD_Y_TILED:
+ layout = FBTILE_INTEL_YGEN9;
+ break;
+ case I915_FORMAT_MOD_Yf_TILED:
+ layout = FBTILE_INTEL_YF;
+ break;
+ default:
+ layout = FBTILE_UNKNOWN;
+ break;
+ }
+#endif
+#ifdef DEBUG_FBTILE_FORMATMODIFIER_MAPPING
+ av_log(NULL, AV_LOG_DEBUG, "fbtile:drmformatmodifier[%lx] mapped to layout[%d]\n", formatModifier, layout);
+#endif
+ return layout;
+}
+
+
+/**
+ * Supported pixel formats
+ * Currently only RGB based 32bit formats are specified
+ * TODO: Technically the logic is transparent to 16bit RGB formats also to a great extent
+ */
+SCOPEIN const enum AVPixelFormat fbtilePixFormats[] = {
+ AV_PIX_FMT_RGB0, AV_PIX_FMT_0RGB, AV_PIX_FMT_BGR0, AV_PIX_FMT_0BGR,
+ AV_PIX_FMT_RGBA, AV_PIX_FMT_ARGB, AV_PIX_FMT_BGRA, AV_PIX_FMT_ABGR,
+ AV_PIX_FMT_NONE};
+
+SCOPEIN int fbtile_checkpixformats(const enum AVPixelFormat srcPixFormat, const enum AVPixelFormat dstPixFormat)
+{
+ int errSrc = 1;
+ int errDst = 1;
+ for (int i = 0; fbtilePixFormats[i] != AV_PIX_FMT_NONE; i++) {
+ if (fbtilePixFormats[i] == srcPixFormat)
+ errSrc = 0;
+ if (fbtilePixFormats[i] == dstPixFormat)
+ errDst = 0;
+ }
+ return (errSrc | errDst);
+}
+
+
+/*
+ * Generic tile/detile logic
+ * The tile layout data is assumed to be tightly packed, with no gaps inbetween.
+ * However the logic does try to accomodate a src/dst linear layout memory,
+ * where there is possibly some additional bytes beyond the width in each line
+ * of pixel data.
+ */
+
+/**
+ * Settings for Intel Tile-Yf framebuffer layout.
+ * May need to swap the 4 pixel wide subtile, have to check doc bit more
+ */
+SCOPEIN struct FBTileWalk tyfTileWalk = {
+ .bytesPerPixel = 4,
+ .subTileWidth = 4, .subTileHeight = 8,
+ .tileWidth = 32, .tileHeight = 32,
+ .numDirChanges = 6,
+ .dirChanges = { {8, 4, 0}, {16, -4, 8}, {32, 4, -8}, {64, -12, 8}, {128, 4, -24}, {256, 4, -24} }
+ };
+
+/**
+ * Setting for Intel Tile-X framebuffer layout
+ */
+SCOPEIN struct FBTileWalk txTileWalk = {
+ .bytesPerPixel = 4,
+ .subTileWidth = 128, .subTileHeight = 8,
+ .tileWidth = 128, .tileHeight = 8,
+ .numDirChanges = 1,
+ .dirChanges = { {8, 128, 0} }
+ };
+
+/**
+ * Setting for Intel Tile-Y framebuffer layout
+ * Even thou a simple generic detiling logic doesnt require the
+ * dummy 256 posOffset entry. The pseudo parallel detiling based
+ * opti logic requires to know about the Tile boundry.
+ */
+SCOPEIN struct FBTileWalk tyTileWalk = {
+ .bytesPerPixel = 4,
+ .subTileWidth = 4, .subTileHeight = 32,
+ .tileWidth = 32, .tileHeight = 32,
+ .numDirChanges = 2,
+ .dirChanges = { {32, 4, 0}, {256, 4, 0} }
+ };
+
+
+/**
+ * _fbtile_generic_simple tile/detile layout
+ */
+static int _fbtile_generic_simple(enum FBTileOps op,
+ const int w, const int h,
+ uint8_t *dst, const int dstLineSize,
+ uint8_t *src, const int srcLineSize,
+ const int bytesPerPixel,
+ const int subTileWidth, const int subTileHeight,
+ const int tileWidth, const int tileHeight,
+ const int numDirChanges, const struct FBTWDirChange *dirChanges)
+{
+ int tO, lO;
+ int lX, lY;
+ int cSTL, nSTLines;
+ uint8_t *tld, *lin;
+ int tldLineSize, linLineSize;
+ const int subTileWidthBytes = subTileWidth*bytesPerPixel;
+
+ if (op == FBTILEOPS_TILE) {
+ lin = src;
+ linLineSize = srcLineSize;
+ tld = dst;
+ tldLineSize = dstLineSize;
+ } else {
+ tld = src;
+ tldLineSize = srcLineSize;
+ lin = dst;
+ linLineSize = dstLineSize;
+ }
+
+ // To keep things sane and simple tile layout is assumed to be tightly packed,
+ // so below check is a indirect logical assumption, even thou tldLineSize is not directly mappable at one level
+ if (w*bytesPerPixel != tldLineSize) {
+ av_log(NULL, AV_LOG_ERROR, "fbtile:genericsimp: w%dxh%d, dL%d, sL%d\n", w, h, tldLineSize, linLineSize);
+ av_log(NULL, AV_LOG_ERROR, "fbtile:genericsimp: dont support tldLineSize | Pitch going beyond width\n");
+ return FBT_ERR;
+ }
+ tO = 0;
+ lX = 0;
+ lY = 0;
+ nSTLines = (w*h)/subTileWidth; // numSubTileLines
+ cSTL = 0; // curSubTileLine
+ while (cSTL < nSTLines) {
+ lO = lY*linLineSize + lX*bytesPerPixel;
+#ifdef DEBUG_FBTILE
+ av_log(NULL, AV_LOG_DEBUG, "fbtile:genericsimp: lX%d lY%d; lO%d, tO%d; %d/%d\n", lX, lY, lO, tO, cSTL, nSTLines);
+#endif
+
+ for (int k = 0; k < subTileHeight; k++) {
+ if (op == FBTILEOPS_TILE) {
+ memcpy(tld+tO+k*subTileWidthBytes, lin+lO+k*linLineSize, subTileWidthBytes);
+ } else {
+ memcpy(lin+lO+k*linLineSize, tld+tO+k*subTileWidthBytes, subTileWidthBytes);
+ }
+ }
+ tO = tO + subTileHeight*subTileWidthBytes;
+
+ cSTL += subTileHeight;
+ for (int i=numDirChanges-1; i>=0; i--) {
+ if ((cSTL%dirChanges[i].posOffset) == 0) {
+ lX += dirChanges[i].xDelta;
+ lY += dirChanges[i].yDelta;
+ break;
+ }
+ }
+ if (lX >= w) {
+ lX = 0;
+ lY += tileHeight;
+ }
+ }
+ return FBT_OK;
+}
+
+
+SCOPEIN int fbtile_generic_simple(enum FBTileOps op,
+ const int w, const int h,
+ uint8_t *dst, const int dstLineSize,
+ uint8_t *src, const int srcLineSize,
+ const struct FBTileWalk *tw)
+{
+ return _fbtile_generic_simple(op, w, h,
+ dst, dstLineSize, src, srcLineSize,
+ tw->bytesPerPixel,
+ tw->subTileWidth, tw->subTileHeight,
+ tw->tileWidth, tw->tileHeight,
+ tw->numDirChanges, tw->dirChanges);
+}
+
+
+static int _fbtile_generic_opti(enum FBTileOps op,
+ const int w, const int h,
+ uint8_t *dst, const int dstLineSize,
+ uint8_t *src, const int srcLineSize,
+ const int bytesPerPixel,
+ const int subTileWidth, const int subTileHeight,
+ const int tileWidth, const int tileHeight,
+ const int numDirChanges, const struct FBTWDirChange *dirChanges)
+{
+ int tO, lO, tOPrev;
+ int lX, lY;
+ int cSTL, nSTLines;
+ int curTileInRow, nTilesInARow;
+ uint8_t *tld, *lin;
+ int tldLineSize, linLineSize;
+ const int subTileWidthBytes = subTileWidth*bytesPerPixel;
+ int parallel = 1;
+
+ if (op == FBTILEOPS_TILE) {
+ lin = src;
+ linLineSize = srcLineSize;
+ tld = dst;
+ tldLineSize = dstLineSize;
+ } else {
+ tld = src;
+ tldLineSize = srcLineSize;
+ lin = dst;
+ linLineSize = dstLineSize;
+ }
+
+ if (w*bytesPerPixel != tldLineSize) {
+ av_log(NULL, AV_LOG_ERROR, "fbtile:genericopti: w%dxh%d, dL%d, sL%d\n", w, h, linLineSize, tldLineSize);
+ av_log(NULL, AV_LOG_ERROR, "fbtile:genericopti: dont support tldLineSize | Pitch going beyond width\n");
+ return FBT_ERR;
+ }
+ if (w%tileWidth != 0) {
+ av_log(NULL, AV_LOG_ERROR, "fbtile:genericopti:NotSupported:Width being non-mult Of TileWidth: width%d, tileWidth%d\n", w, tileWidth);
+ return FBT_ERR;
+ }
+ tO = 0;
+ tOPrev = 0;
+ lX = 0;
+ lY = 0;
+ nTilesInARow = w/tileWidth;
+ for (parallel=8; parallel>0; parallel--) {
+ if (nTilesInARow%parallel == 0)
+ break;
+ }
+ nSTLines = (w*h)/subTileWidth; // numSubTileLines
+ cSTL = 0; // curSubTileLine
+ curTileInRow = 0;
+ while (cSTL < nSTLines) {
+ lO = lY*linLineSize + lX*bytesPerPixel;
+#ifdef DEBUG_FBTILE
+ av_log(NULL, AV_LOG_DEBUG, "fbtile:genericopti: lX%d lY%d; tO%d, lO%d; %d/%d\n", lX, lY, tO, lO, cSTL, nSTLines);
+#endif
+
+ // As most tiling layouts have a minimum subtile of 4x4, if I remember correctly,
+ // so this loop can be unrolled to be multiples of 4, and speed up a bit.
+ // However tiling involving 3x3 or 2x2 wont be handlable. In which one will have to use
+ // NON UnRolled version or fbtile_generic_simple for such tile layouts.
+ // (De)tile parallely to a limited extent. Gain some speed by allowing reuse of calcs and parallelism,
+ // but still avoid any cache set-associativity and or limited cache based thrashing. Keep it spatially
+ // and inturn temporaly small at one level.
+ if (op == FBTILEOPS_DETILE) {
+#ifdef FBTILER_OPTI_UNROLL
+ for (int k = 0; k < subTileHeight; k+=4) {
+#else
+ for (int k = 0; k < subTileHeight; k+=1) {
+#endif
+ for (int p = 0; p < parallel; p++) {
+ int pTldOffset = p*tileWidth*tileHeight*bytesPerPixel;
+ int pLinOffset = p*tileWidth*bytesPerPixel;
+ memcpy(lin+lO+(k+0)*linLineSize+pLinOffset, tld+tO+(k+0)*subTileWidthBytes+pTldOffset, subTileWidthBytes);
+#ifdef FBTILER_OPTI_UNROLL
+ memcpy(lin+lO+(k+1)*linLineSize+pLinOffset, tld+tO+(k+1)*subTileWidthBytes+pTldOffset, subTileWidthBytes);
+ memcpy(lin+lO+(k+2)*linLineSize+pLinOffset, tld+tO+(k+2)*subTileWidthBytes+pTldOffset, subTileWidthBytes);
+ memcpy(lin+lO+(k+3)*linLineSize+pLinOffset, tld+tO+(k+3)*subTileWidthBytes+pTldOffset, subTileWidthBytes);
+#endif
+ }
+ }
+ } else {
+#ifdef FBTILER_OPTI_UNROLL
+ for (int k = 0; k < subTileHeight; k+=4) {
+#else
+ for (int k = 0; k < subTileHeight; k+=1) {
+#endif
+ for (int p = 0; p < parallel; p++) {
+ int pTldOffset = p*tileWidth*tileHeight*bytesPerPixel;
+ int pLinOffset = p*tileWidth*bytesPerPixel;
+ memcpy(tld+tO+(k+0)*subTileWidthBytes+pTldOffset, lin+lO+(k+0)*linLineSize+pLinOffset, subTileWidthBytes);
+#ifdef FBTILER_OPTI_UNROLL
+ memcpy(tld+tO+(k+1)*subTileWidthBytes+pTldOffset, lin+lO+(k+1)*linLineSize+pLinOffset, subTileWidthBytes);
+ memcpy(tld+tO+(k+2)*subTileWidthBytes+pTldOffset, lin+lO+(k+2)*linLineSize+pLinOffset, subTileWidthBytes);
+ memcpy(tld+tO+(k+3)*subTileWidthBytes+pTldOffset, lin+lO+(k+3)*linLineSize+pLinOffset, subTileWidthBytes);
+#endif
+ }
+ }
+ }
+
+ tO = tO + subTileHeight*subTileWidthBytes;
+ cSTL += subTileHeight;
+
+ for (int i=numDirChanges-1; i>=0; i--) {
+ if ((cSTL%dirChanges[i].posOffset) == 0) {
+ if (i == numDirChanges-1) {
+ curTileInRow += parallel;
+ lX = curTileInRow*tileWidth;
+ tO = tOPrev + tileWidth*tileHeight*bytesPerPixel*(parallel);
+ tOPrev = tO;
+ } else {
+ lX += dirChanges[i].xDelta;
+ }
+ lY += dirChanges[i].yDelta;
+ break;
+ }
+ }
+ if (lX >= w) {
+ lX = 0;
+ curTileInRow = 0;
+ lY += tileHeight;
+ if (lY >= h) {
+ break;
+ }
+ }
+ }
+ return FBT_OK;
+}
+
+
+SCOPEIN int fbtile_generic_opti(enum FBTileOps op,
+ const int w, const int h,
+ uint8_t *dst, const int dstLineSize,
+ uint8_t *src, const int srcLineSize,
+ const struct FBTileWalk *tw)
+{
+ return _fbtile_generic_opti(op, w, h,
+ dst, dstLineSize, src, srcLineSize,
+ tw->bytesPerPixel,
+ tw->subTileWidth, tw->subTileHeight,
+ tw->tileWidth, tw->tileHeight,
+ tw->numDirChanges, tw->dirChanges);
+}
+
+
+SCOPEIN int fbtile_conv(enum FBTileOps op, enum FBTileLayout layout,
+ int w, int h,
+ uint8_t *dst, int dstLineSize,
+ uint8_t *src, int srcLineSize,
+ int bytesPerPixel)
+{
+ static int logStateNone = 0;
+ static int logStateUnknown = 0;
+
+ switch(layout) {
+ case FBTILE_NONE:
+ av_log_once(NULL, AV_LOG_WARNING, AV_LOG_VERBOSE, &logStateNone, "fbtile:conv:FBTILE_NONE: not (de)tiling\n");
+ return FBT_ERR;
+ case FBTILE_INTEL_XGEN9:
+ return fbtile_generic(op, w, h, dst, dstLineSize, src, srcLineSize, &txTileWalk);
+ case FBTILE_INTEL_YGEN9:
+ return fbtile_generic(op, w, h, dst, dstLineSize, src, srcLineSize, &tyTileWalk);
+ case FBTILE_INTEL_YF:
+ return fbtile_generic(op, w, h, dst, dstLineSize, src, srcLineSize, &tyfTileWalk);
+ default:
+ av_log_once(NULL, AV_LOG_WARNING, AV_LOG_VERBOSE, &logStateUnknown, "fbtile:conv: unknown layout [%d] specified, not (de)tiling\n", layout);
+ return FBT_ERR;
+ }
+}
+
+
+/*
+ * Copy one AVFrame into the other, tiling or detiling as required, if possible.
+ * NOTE: Either the Source or the Destination AVFrame (i.e one of them) should be linear.
+ * NOTE: If the tiling layout is not understood, it will do a simple copy.
+ */
+SCOPEIN int fbtile_frame_copy(AVFrame *dst, enum FBTileLayout dstTileLayout, AVFrame *src, enum FBTileLayout srcTileLayout,
+ enum FBTileFrameCopyStatus *status)
+{
+ int err;
+
+ if (dstTileLayout == FBTILE_NONE) { // i.e DeTile
+ err = fbtile_checkpixformats(src->format, dst->format);
+ if (!err) {
+ err = fbtile_conv(FBTILEOPS_DETILE, srcTileLayout,
+ dst->width, dst->height,
+ dst->data[0], dst->linesize[0],
+ src->data[0], src->linesize[0], 4);
+ if (!err) {
+ *status = FBTILE_FRAMECOPY_TILECOPY;
+ return FBT_OK;
+ }
+ }
+ } else if (srcTileLayout == FBTILE_NONE) { // i.e Tile
+ err = fbtile_checkpixformats(src->format, dst->format);
+ if (!err) {
+ err = fbtile_conv(FBTILEOPS_TILE, dstTileLayout,
+ src->width, src->height,
+ dst->data[0], dst->linesize[0],
+ src->data[0], src->linesize[0], 4);
+ if (!err) {
+ *status = FBTILE_FRAMECOPY_TILECOPY;
+ return FBT_OK;
+ }
+ }
+ } else {
+ av_log(NULL, AV_LOG_WARNING, "fbtile:framecopy: both src [%d] and dst [%d] layouts cant be tiled\n", srcTileLayout, dstTileLayout);
+ }
+ *status = FBTILE_FRAMECOPY_COPYONLY;
+ return av_frame_copy(dst, src);
+}
+
+
+// vim: set expandtab sts=4: //
new file mode 100644
@@ -0,0 +1,255 @@
+/*
+ * CPU based Framebuffer Generic Tile DeTile logic
+ * Copyright (c) 2020 C Hanish Menon <HanishKVC>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_FBTILE_H
+#define AVUTIL_FBTILE_H
+
+#include <stdint.h>
+#include "libavutil/pixfmt.h"
+#include "libavutil/frame.h"
+
+/**
+ * @file
+ * @brief CPU based Framebuffer tiler detiler
+ * @author C Hanish Menon <HanishKVC>
+ * @{
+ */
+
+
+/**
+ * Set scope of this api to be either public or internal (non-public)
+ */
+// #define FBTILE_SCOPE_PUBLIC 1
+#ifdef FBTILE_SCOPE_PUBLIC
+#define SCOPEIN
+#else
+#define SCOPEIN static
+#endif
+
+
+/**
+ * Set fbtile_generic to either simple or minimal optimised logic
+ */
+#define FBTILER_GENERIC_OPTI 1
+#ifdef FBTILER_GENERIC_OPTI
+#define fbtile_generic fbtile_generic_opti
+#else
+#define fbtile_generic fbtile_generic_simple
+#endif
+
+
+// Enable printing of the tile walk
+//#define DEBUG_FBTILE 1
+
+
+// Common return values
+#define FBT_OK 0
+#define FBT_ERR 1
+
+/**
+ * The FBTile related operations
+ */
+enum FBTileOps {
+ FBTILEOPS_NONE,
+ FBTILEOPS_TILE,
+ FBTILEOPS_DETILE,
+ FBTILEOPS_UNKNOWN
+};
+
+
+/**
+ * The FBTile related Layouts
+ * This identifies the supported tile layouts
+ */
+enum FBTileLayout {
+ FBTILE_NONE, // This also corresponds to linear layout
+ FBTILE_INTEL_XGEN9,
+ FBTILE_INTEL_YGEN9,
+ FBTILE_INTEL_YF,
+ FBTILE_UNKNOWN,
+};
+
+
+/**
+ * TileWalk Direction Change Entry
+ * Used to specify the tile walking of subtiles within a tile.
+ */
+struct FBTWDirChange {
+ int posOffset;
+ int xDelta;
+ int yDelta;
+};
+
+
+/**
+ * TileWalk, Contains info required for a given tile walking.
+ *
+ * @field bytesPerPixel the bytes per pixel for the image
+ * @field subTileWidth the width of subtile within the tile, in pixels
+ * @field subTileHeight the height of subtile within the tile, in pixels
+ * @field tileWidth the width of the tile, in pixels
+ * @field tileHeight the height of the tile, in pixels
+ * @field numDirChanges the number of dir changes involved in tile walk
+ * @field dirChanges the array of dir changes for the tile walk required
+ */
+struct FBTileWalk {
+ int bytesPerPixel;
+ int subTileWidth, subTileHeight;
+ int tileWidth, tileHeight;
+ int numDirChanges;
+ struct FBTWDirChange dirChanges[];
+};
+
+
+/**
+ * FBTile FrameCopy additional status
+ */
+enum FBTileFrameCopyStatus {
+ FBTILE_FRAMECOPY_TILECOPY,
+ FBTILE_FRAMECOPY_COPYONLY
+};
+
+
+#ifdef FBTILE_SCOPE_PUBLIC
+
+
+/**
+ * Map from formatmodifier to fbtile's internal mode.
+ *
+ * @param formatModifier the format_modifier to map
+ * @return the fbtile's equivalent internal mode
+ */
+#undef DEBUG_FBTILE_FORMATMODIFIER_MAPPING
+enum FBTileLayout fbtilelayoutid_from_drmformatmodifier(uint64_t formatModifier);
+
+
+/**
+ * Supported pixel formats by the fbtile logics
+ */
+extern const enum AVPixelFormat fbtilePixFormats[];
+/**
+ * Check if the given pixel formats are supported by fbtile logic.
+ *
+ * @param srcPixFormat pixel format of source image
+ * @param dstPixFormat pixel format of destination image
+ *
+ * @return 0 if supported, 1 if not
+ */
+int fbtile_checkpixformats(const enum AVPixelFormat srcPixFormat, const enum AVPixelFormat dstPixFormat);
+
+
+/**
+ * Generic Logic.
+ */
+
+
+/**
+ * Tile Walk parameters for Tile-X, Tile-Y, Tile-Yf
+ */
+extern struct FBTileWalk tyfTileWalk;
+extern struct FBTileWalk txTileWalk;
+extern struct FBTileWalk tyTileWalk;
+
+
+/**
+ * Generic Logic to Tile/Detile between tiled and linear layout.
+ *
+ * @param op whether to tile or detile
+ * @param w width of the image
+ * @param h height of the image
+ * @param dst the destination image buffer
+ * @param dstLineSize the size of each row in dst image, in bytes
+ * @param src the source image buffer
+ * @param srcLineSize the size of each row in src image, in bytes
+ * @param tw the structure which contains the tile walk parameters
+ *
+ * @return 0 if detiled, 1 if not
+ */
+
+
+/**
+ * Generic tile/detile simple version.
+ */
+int fbtile_generic_simple(enum FBTileOps op,
+ const int w, const int h,
+ uint8_t *dst, const int dstLineSize,
+ uint8_t *src, const int srcLineSize,
+ const struct FBTileWalk *tw);
+
+
+/**
+ * Generic tile/detile minimal optimised version.
+ */
+int fbtile_generic_opti(enum FBTileOps op,
+ const int w, const int h,
+ uint8_t *dst, const int dstLineSize,
+ uint8_t *src, const int srcLineSize,
+ const struct FBTileWalk *tw);
+
+
+/**
+ * tile/detile demuxer.
+ *
+ * @param op todo tiling or todo detiling
+ * @param layout specify the tile layout of dst/src framebuffer involved
+ * @param w width of the image
+ * @param h height of the image
+ * @param dst the destination image buffer
+ * @param dstLineSize the size of each row in dst image, in bytes
+ * @param src the source image buffer
+ * @param srcLineSize the size of each row in src image, in bytes
+ * @param bytesPerPixel the bytes per pixel for the image
+ *
+ * @return 0 if detiled, 1 if not
+ */
+int fbtile_conv(enum FBTileOps op, enum FBTileLayout layout,
+ int w, int h,
+ uint8_t *dst, int dstLineSize,
+ uint8_t *src, int srcLineSize,
+ int bytesPerPixel);
+
+
+/**
+ * Copy one AVFrame into the other, tiling or detiling as required, if possible.
+ * NOTE: Either the Source or the Destination AVFrame (i.e one of them) should be linear.
+ * NOTE: If the tiling layout is not understood, it will do a simple copy.
+ *
+ * @param dst the destination avframe
+ * @param dstTileLayout the framebuffer tiling layout expected for the destination avframe
+ * @param src the source avframe
+ * @param srcTileLayout the framebuffer tiling layout of the source avframe
+ *
+ * @return 0 if copied.
+ */
+int fbtile_frame_copy(AVFrame *dst, enum FBTileLayout dstTileLayout,
+ AVFrame *src, enum FBTileLayout srcTileLayout,
+ enum FBTileFrameCopyStatus *status);
+
+
+#endif // FBTILE_SCOPE_PUBLIC
+
+
+/**
+ * @}
+ */
+
+#endif /* AVUTIL_FBTILE_H */
+// vim: set expandtab sts=4: //
@@ -21,6 +21,7 @@
#include <unistd.h>
#include <drm.h>
+#include <drm_fourcc.h>
#include <xf86drm.h>
#include "avassert.h"
@@ -28,6 +29,10 @@
#include "hwcontext_drm.h"
#include "hwcontext_internal.h"
#include "imgutils.h"
+#include "fbtile.h"
+#ifndef FBTILE_SCOPE_PUBLIC
+#include "libavutil/fbtile.c"
+#endif
static void drm_device_free(AVHWDeviceContext *hwdev)
@@ -185,6 +190,35 @@ static int drm_transfer_get_formats(AVHWFramesContext *ctx,
return 0;
}
+// Can be overridden during compiling, if required.
+#ifndef HWCTXDRM_SYNCRELATED_FORMATMODIFIER
+#define HWCTXDRM_SYNCRELATED_FORMATMODIFIER 1
+#endif
+static int drm_transfer_with_detile(const AVFrame *hwAVFrame, AVFrame *dst, const AVFrame *src)
+{
+ int err;
+ uint64_t formatModifier;
+ enum FBTileLayout srcFBTileLayout, dstFBTileLayout;
+ enum FBTileFrameCopyStatus status;
+ AVDRMFrameDescriptor *drmFrame = NULL;
+
+ srcFBTileLayout = FBTILE_NONE;
+ dstFBTileLayout = FBTILE_NONE;
+ if (hwAVFrame->format == AV_PIX_FMT_DRM_PRIME) {
+ drmFrame = (AVDRMFrameDescriptor*)hwAVFrame->data[0];
+ formatModifier = drmFrame->objects[0].format_modifier;
+ srcFBTileLayout = fbtilelayoutid_from_drmformatmodifier(formatModifier);
+ }
+ err = fbtile_frame_copy(dst, dstFBTileLayout, src, srcFBTileLayout, &status);
+#if HWCTXDRM_SYNCRELATED_FORMATMODIFIER
+ if (!err && (status == FBTILE_FRAMECOPY_TILECOPY)) {
+ if (drmFrame != NULL)
+ drmFrame->objects[0].format_modifier = DRM_FORMAT_MOD_LINEAR;
+ }
+#endif
+ return err;
+}
+
static int drm_transfer_data_from(AVHWFramesContext *hwfc,
AVFrame *dst, const AVFrame *src)
{
@@ -206,7 +240,7 @@ static int drm_transfer_data_from(AVHWFramesContext *hwfc,
map->width = dst->width;
map->height = dst->height;
- err = av_frame_copy(dst, map);
+ err = drm_transfer_with_detile(src, dst, map);
if (err)
goto fail;