diff --git a/Changelog b/Changelog
index ac3f1cf208..c25a28a428 100644
--- a/Changelog
+++ b/Changelog
@@ -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
diff --git a/libavutil/Makefile b/libavutil/Makefile
index 9b08372eb2..9b58ac5980 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -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                                               \
 
 
diff --git a/libavutil/fbtile.c b/libavutil/fbtile.c
new file mode 100644
index 0000000000..921e5de805
--- /dev/null
+++ b/libavutil/fbtile.c
@@ -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: //
diff --git a/libavutil/fbtile.h b/libavutil/fbtile.h
new file mode 100644
index 0000000000..8ac06b6c05
--- /dev/null
+++ b/libavutil/fbtile.h
@@ -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: //
diff --git a/libavutil/hwcontext_drm.c b/libavutil/hwcontext_drm.c
index 32cbde82eb..60058e0f08 100644
--- a/libavutil/hwcontext_drm.c
+++ b/libavutil/hwcontext_drm.c
@@ -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;
 
