diff mbox series

[FFmpeg-devel,v08,2/3] fbtile tile/detile, hwcontext_drm detile NonLinear

Message ID 20200711075239.109277-3-hanishkvc@gmail.com
State Superseded
Headers show
Series *** kmsgrab, fbtile hwdownload_drm, VFs *** | expand

Checks

Context Check Description
andriy/default pending
andriy/make_warn warning New warnings during build
andriy/make success Make finished
andriy/make_fate success Make fate finished

Commit Message

hanishkvc July 11, 2020, 7:52 a.m. UTC
** fbtile cpu based framebuffer tile/detile helpers

Add helper routines which can be used to tile/detile framebuffer
layouts between linear and specified tile layout, using the cpu.

Currently it supports Legacy Intel Tile-X, Legacy Intel Tile-Y and
Newer Intel Tile-Yf tiled layouts.

Currently supported pixel format is 32bit RGB.

It also contains fbtile_generic logic, which can be easily configured
to support different kinds of tiling layouts, at the expense of some
additional processing cycles, compared to developing custom (de)tiling
logic. One requires to provide the tile walking parameters for the
new tile layout to be supported. Once it is done, both tiling and
detiling of the new tile layout can be handled automatically.

This is non-public by default.

** hwcontext_drm detile non linear layout, if possible

If the framebuffer is a tiled layout, use the fbtile helper routines
to try and detile it into linear layout, if supported by fbtile.

It uses the format_modifier associated with the framebuffer to decide
whether to apply detiling or not and inturn which specific detiling
to apply.

If user is using kmsgrab, they will have to use -format_modifer option
of kmsgrab to force a specific detile logic, in case they dont want to
use the original format_modifier related detiling. Or they could even
use -format_modifier 0 to make hwcontext_drm bypass this detiling.
---
 Changelog                 |   2 +
 libavutil/Makefile        |   2 +
 libavutil/fbtile.c        | 434 ++++++++++++++++++++++++++++++++++++++
 libavutil/fbtile.h        | 255 ++++++++++++++++++++++
 libavutil/hwcontext_drm.c |  36 +++-
 5 files changed, 728 insertions(+), 1 deletion(-)
 create mode 100644 libavutil/fbtile.c
 create mode 100644 libavutil/fbtile.h

Comments

Lynne July 11, 2020, 11:50 a.m. UTC | #1
Jul 11, 2020, 08:52 by hanishkvc@gmail.com:

> ** fbtile cpu based framebuffer tile/detile helpers
>
> Add helper routines which can be used to tile/detile framebuffer
> layouts between linear and specified tile layout, using the cpu.
>
> Currently it supports Legacy Intel Tile-X, Legacy Intel Tile-Y and
> Newer Intel Tile-Yf tiled layouts.
>
> Currently supported pixel format is 32bit RGB.
>
> It also contains fbtile_generic logic, which can be easily configured
> to support different kinds of tiling layouts, at the expense of some
> additional processing cycles, compared to developing custom (de)tiling
> logic. One requires to provide the tile walking parameters for the
> new tile layout to be supported. Once it is done, both tiling and
> detiling of the new tile layout can be handled automatically.
>
> This is non-public by default.
>

I thought I made myself clear. No compile time public header options.
That means no SCOPEIN, no HWCTXDRM_SYNCRELATED_FORMATMODIFIER,
no DEBUG_FBTILE_FORMATMODIFIER_MAPPING, no FBTILE_SCOPE_PUBLIC,
no FBTILER_OPTI_UNROLL (just always unroll), no FBTILER_GENERIC_OPTI,
none of those please, at all. No, this is not up for discussion.
I can't review this patch well at all with this.
You can depend on CONFIG_LIBDRM always being available, as we're never ever
going to be using this code outside of hwcontext_drm.c.
We align our switch cases with the switch indentation, so no extra indent. Its not a block.
Use av_log instead of av_log_once.
Also fix the changelog.
And please stop submitting the fbdetile filter patch, even for informative reasons.
Just dump it in a git repository somewhere.


> +// Common return values> +#define FBT_OK 0> +#define FBT_ERR 1

Really? Use 0 for ok and AVERROR... for errors.


> +/*> + * 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.> + */

If the contents aren't going to change you can avoid copying by just using av_frame_ref.


Like I said, this is just a fraction of what I can review with all those ifdefs around the code.
hanishkvc July 11, 2020, 3:01 p.m. UTC | #2
Hi Lynne,

On Sat, Jul 11, 2020 at 5:20 PM Lynne <dev@lynne.ee> wrote:

> Jul 11, 2020, 08:52 by hanishkvc@gmail.com:
>
> > ** fbtile cpu based framebuffer tile/detile helpers
> >
> > Add helper routines which can be used to tile/detile framebuffer
> > layouts between linear and specified tile layout, using the cpu.
> >
> > Currently it supports Legacy Intel Tile-X, Legacy Intel Tile-Y and
> > Newer Intel Tile-Yf tiled layouts.
> >
> > Currently supported pixel format is 32bit RGB.
> >
> > It also contains fbtile_generic logic, which can be easily configured
> > to support different kinds of tiling layouts, at the expense of some
> > additional processing cycles, compared to developing custom (de)tiling
> > logic. One requires to provide the tile walking parameters for the
> > new tile layout to be supported. Once it is done, both tiling and
> > detiling of the new tile layout can be handled automatically.
> >
> > This is non-public by default.
> >
>
> I thought I made myself clear. No compile time public header options.
> That means no SCOPEIN, no HWCTXDRM_SYNCRELATED_FORMATMODIFIER,
> no DEBUG_FBTILE_FORMATMODIFIER_MAPPING, no FBTILE_SCOPE_PUBLIC,
> no FBTILER_OPTI_UNROLL (just always unroll), no FBTILER_GENERIC_OPTI,
> none of those please, at all. No, this is not up for discussion.
>

Reason HWCTXDRM_SYNCRELATED_FORMATMODIFIER is provided is because currently
as the AVFrame doesn't have any generic tiling info related member, so the
related HW AVFrame is currently used to notify any other users in future
within hwcontext_drm that it has been detiled. But then again has there is
no single right or wrong way here at one level, so I put it under a ifdef
block and what I felt as a potentially sane default for now was set for the
same.

The DEBUG defs (DEBUG_FBTILE and DEBUG_...MAPPING) are provided so that in
future, if someone wants to debug the flow for some reason like say a new
tile layout being added or some other reason, then they don't have to hunt
as to where to put debug prints to help understand the flow, instead they
could use the already available compile time option to enable the debug
logs and then get one level of understanding. And again currently a sane
default of keeping it disabled (undef'd) is used.

The reason UNROLL is put within ifdef is because if for some reason a
tiling layout which involves less than 4x4 subtile block is required to be
supported in future, then the unrolling will need to be avoided in this
function or a new function without unrolling will have to be created. Again
to help a future developer who may face such a situation, the code is
properly identified and put into suitable ifdef blocks and suitably
commented in the code. Again a sane default which is fine for the current
situation is setup.

Again the idea of FBTILE_SCOPE_PUBLIC, is so that a logically independent
code, can be embedded into a some other code in a structured way, while at
same time providing the flexibility to move it into a independent public
api if required in future, if another use case for the logic comes up.

I do agree that these compile time options won't be changed in a normal
compile, but then again it is not for a normal compile situation, but for
future flow changes if required in future for a developer (or a user who
wants to experiment) who may have to touch the code.

I am not sure your way of thinking of trying to structure everything to an
immediate specific need, is the right way of approaching things in general,
when the underlying logic is in reality independent and even when things
are potentially (I do accept different people may implement the things in
slightly different ways) structured in a sane way to provide future
flexibility.

At the same time I appreciate and am thankful to the volunteering you and
other developers are doing here and will change the code to be more
specific if you still feel that is what you, as an active ffmpeg developer,
feel.

I can't review this patch well at all with this.
> You can depend on CONFIG_LIBDRM always being available, as we're never ever
> going to be using this code outside of hwcontext_drm.c.
>

As what I have mentioned above already, you seem to want to structure the
code to be very specific to the current immediate use case, while I
normally prefer structuring things to be flexible and adaptable for the
unknown future, especially when the logic in question is in reality
independent at one level.

Also in this case I feel it is a sensible ifdef'd block for drm specific
code (to map from format_modifier to the logic's id for the tiling layout)
in an otherwise generic logic and we should retain it.


> We align our switch cases with the switch indentation, so no extra indent.
> Its not a block.
>

Understood the ffmpeg convention, will update.


> Use av_log instead of av_log_once.
>

In a video flow, has the same unwanted setup can trigger more than once in
a single run, like say an unknown tile layout, in such a situation I didnt
want to flood the 'by-default' user visible log with message about the same
more than once, so I used av_log_once and inturn changed the log level
between the 1st and subsequent log entries. Isn't it what one is expected
to do in such a situation, or am I missing something.


> Also fix the changelog.
>

Sorry I didn't understand this fully. Can I assume that you don't want to
mention about the fbtile helpers as an entry in the changelog, because its
not a public api? From my perspective the reason why I added it to the
changelog is so that if someone is looking at availability of some
framebuffer tiling/detiling support in future, the changelog notes the same
in a simple way. However if you feel it's not needed I will remove it. Or
did you mean something else?


> And please stop submitting the fbdetile filter patch, even for informative
> reasons.
> Just dump it in a git repository somewhere.
>
>
As was being discussed in another thread in the mailing list, currently
there is no central registry of available video filters out there, so dont
you think mailing list is the next best location to have the source patch
for the filter, for someone who may (or may not) look for things in future?
Just asking and thinking out loud.


>
> > +// Common return values> +#define FBT_OK 0> +#define FBT_ERR 1
>
> Really? Use 0 for ok and AVERROR... for errors.
>
> Will change ;-)


>
> > +/*> + * 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.> + */
>
> If the contents aren't going to change you can avoid copying by just using
> av_frame_ref.
>
>
Thanks for suggesting the same (as previously mentioned, I haven't worked
on ffmpeg before so am not aware of all the ffmpeg helper routines, and did
this code more to solve a specific use case I had and parallely wanted to
have some fun implementing the logic, as well as contribute something
possibly useful back to ffmpeg as a thank you to all involved).

However at the same time, when used for example like in hwcontext_drm, the
underlying source is a specific hardware's mmap'd memory, so should one
pass the source reference along to the destination (i am assuming that is
what av_frame_ref is, have to check still), or shouldn't one move the data
out of the hardware specific memory, as early as possible.


>
> Like I said, this is just a fraction of what I can review with all those
> ifdefs around the code.
>

Thanks once again for providing the feedback, and sorry for all the
ifdef's I have put in, I have specified the reason for some of those ifdefs
above, based on your response, I will remove most of them, if that is what
you feel is right.


> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
hanishkvc July 12, 2020, 5:30 a.m. UTC | #3
Hi Lynne,

On Sat, 11 Jul, 2020, 20:31 C Hanish Menon, <hanishkvc@gmail.com> wrote:

> Hi Lynne,
>
> On Sat, Jul 11, 2020 at 5:20 PM Lynne <dev@lynne.ee> wrote:
>
>> Jul 11, 2020, 08:52 by hanishkvc@gmail.com:
>>
>> > ** fbtile cpu based framebuffer tile/detile helpers
>> >
>> > Add helper routines which can be used to tile/detile framebuffer
>> > layouts between linear and specified tile layout, using the cpu.
>> >
>> > Currently it supports Legacy Intel Tile-X, Legacy Intel Tile-Y and
>> > Newer Intel Tile-Yf tiled layouts.
>> >
>> > Currently supported pixel format is 32bit RGB.
>> >
>> > It also contains fbtile_generic logic, which can be easily configured
>> > to support different kinds of tiling layouts, at the expense of some
>> > additional processing cycles, compared to developing custom (de)tiling
>> > logic. One requires to provide the tile walking parameters for the
>> > new tile layout to be supported. Once it is done, both tiling and
>> > detiling of the new tile layout can be handled automatically.
>> >
>> > This is non-public by default.
>> >
>>
>> I thought I made myself clear. No compile time public header options.
>> That means no SCOPEIN, no HWCTXDRM_SYNCRELATED_FORMATMODIFIER,
>> no DEBUG_FBTILE_FORMATMODIFIER_MAPPING, no FBTILE_SCOPE_PUBLIC,
>> no FBTILER_OPTI_UNROLL (just always unroll), no FBTILER_GENERIC_OPTI,
>> none of those please, at all. No, this is not up for discussion.
>>
>
> Reason HWCTXDRM_SYNCRELATED_FORMATMODIFIER is provided is because
> currently as the AVFrame doesn't have any generic tiling info related
> member, so the related HW AVFrame is currently used to notify any other
> users in future within hwcontext_drm that it has been detiled. But then
> again has there is no single right or wrong way here at one level, so I put
> it under a ifdef block and what I felt as a potentially sane default for
> now was set for the same.
>
> The DEBUG defs (DEBUG_FBTILE and DEBUG_...MAPPING) are provided so that in
> future, if someone wants to debug the flow for some reason like say a new
> tile layout being added or some other reason, then they don't have to hunt
> as to where to put debug prints to help understand the flow, instead they
> could use the already available compile time option to enable the debug
> logs and then get one level of understanding. And again currently a sane
> default of keeping it disabled (undef'd) is used.
>
> The reason UNROLL is put within ifdef is because if for some reason a
> tiling layout which involves less than 4x4 subtile block is required to be
> supported in future, then the unrolling will need to be avoided in this
> function or a new function without unrolling will have to be created. Again
> to help a future developer who may face such a situation, the code is
> properly identified and put into suitable ifdef blocks and suitably
> commented in the code. Again a sane default which is fine for the current
> situation is setup.
>

Rather to be more clear, once unrolled the logic can't be used for subtiles
and walks involving non multiples of 4 (along vertical direction) in this
case.

Will modify code to use unrolled opti version where this condition is
satisfied, which is the case for currently supported tile layouts. At same
time if this condition is not met by a new layout in future, the non
parallel simple version, which is also provided, can be used. The same is
noted as a comment in the code.


> Again the idea of FBTILE_SCOPE_PUBLIC, is so that a logically independent
> code, can be embedded into a some other code in a structured way, while at
> same time providing the flexibility to move it into a independent public
> api if required in future, if another use case for the logic comes up.
>

Had a look at the ffmpeg coding convention, will use the ff_ prefixed
convention for non static but internal to library helper functions. That
will keep the code simple and clean, while allowing it to be used by others
if required in future.


> I do agree that these compile time options won't be changed in a normal
> compile, but then again it is not for a normal compile situation, but for
> future flow changes if required in future for a developer (or a user who
> wants to experiment) who may have to touch the code.
>
> I am not sure your way of thinking of trying to structure everything to an
> immediate specific need, is the right way of approaching things in general,
> when the underlying logic is in reality independent and even when things
> are potentially (I do accept different people may implement the things in
> slightly different ways) structured in a sane way to provide future
> flexibility.
>
> At the same time I appreciate and am thankful to the volunteering you and
> other developers are doing here and will change the code to be more
> specific if you still feel that is what you, as an active ffmpeg developer,
> feel.
>
> I can't review this patch well at all with this.
>> You can depend on CONFIG_LIBDRM always being available, as we're never
>> ever
>> going to be using this code outside of hwcontext_drm.c.
>>
>
> As what I have mentioned above already, you seem to want to structure the
> code to be very specific to the current immediate use case, while I
> normally prefer structuring things to be flexible and adaptable for the
> unknown future, especially when the logic in question is in reality
> independent at one level.
>
> Also in this case I feel it is a sensible ifdef'd block for drm specific
> code (to map from format_modifier to the logic's id for the tiling layout)
> in an otherwise generic logic and we should retain it.
>
>
>> We align our switch cases with the switch indentation, so no extra
>> indent. Its not a block.
>>
>
> Understood the ffmpeg convention, will update.
>
>
>> Use av_log instead of av_log_once.
>>
>
> In a video flow, has the same unwanted setup can trigger more than once in
> a single run, like say an unknown tile layout, in such a situation I didnt
> want to flood the 'by-default' user visible log with message about the same
> more than once, so I used av_log_once and inturn changed the log level
> between the 1st and subsequent log entries. Isn't it what one is expected
> to do in such a situation, or am I missing something.
>
>
>> Also fix the changelog.
>>
>
> Sorry I didn't understand this fully. Can I assume that you don't want to
> mention about the fbtile helpers as an entry in the changelog, because its
> not a public api? From my perspective the reason why I added it to the
> changelog is so that if someone is looking at availability of some
> framebuffer tiling/detiling support in future, the changelog notes the same
> in a simple way. However if you feel it's not needed I will remove it. Or
> did you mean something else?
>
>
>> And please stop submitting the fbdetile filter patch, even for
>> informative reasons.
>> Just dump it in a git repository somewhere.
>>
>>
> As was being discussed in another thread in the mailing list, currently
> there is no central registry of available video filters out there, so dont
> you think mailing list is the next best location to have the source patch
> for the filter, for someone who may (or may not) look for things in future?
> Just asking and thinking out loud.
>
>
>>
>> > +// Common return values> +#define FBT_OK 0> +#define FBT_ERR 1
>>
>> Really? Use 0 for ok and AVERROR... for errors.
>>
>> Will change ;-)
>
>
>>
>> > +/*> + * 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.> + */
>>
>> If the contents aren't going to change you can avoid copying by just
>> using av_frame_ref.
>>
>>
> Thanks for suggesting the same (as previously mentioned, I haven't worked
> on ffmpeg before so am not aware of all the ffmpeg helper routines, and did
> this code more to solve a specific use case I had and parallely wanted to
> have some fun implementing the logic, as well as contribute something
> possibly useful back to ffmpeg as a thank you to all involved).
>
> However at the same time, when used for example like in hwcontext_drm, the
> underlying source is a specific hardware's mmap'd memory, so should one
> pass the source reference along to the destination (i am assuming that is
> what av_frame_ref is, have to check still), or shouldn't one move the data
> out of the hardware specific memory, as early as possible.
>
>
>>
>> Like I said, this is just a fraction of what I can review with all those
>> ifdefs around the code.
>>
>
> Thanks once again for providing the feedback, and sorry for all the
> ifdef's I have put in, I have specified the reason for some of those ifdefs
> above, based on your response, I will remove most of them, if that is what
> you feel is right.
>
>
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel@ffmpeg.org
>> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>
>> To unsubscribe, visit link above, or email
>> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
>
>
>
> --
> Keep ;-)
> HanishKVC
>
Moritz Barsnick July 12, 2020, 1:01 p.m. UTC | #4
On Sat, Jul 11, 2020 at 20:31:40 +0530, C Hanish Menon wrote:
> > Also fix the changelog.
>
> Sorry I didn't understand this fully. Can I assume that you don't want to
> mention about the fbtile helpers as an entry in the changelog, because its
> not a public api?

I believe what Lynne meant is:

Changelog entries are added at the bottom, not at the top of the list.
You can how other commits did something, before making assumptions.

> Thanks for suggesting the same (as previously mentioned, I haven't worked
> on ffmpeg before so am not aware of all the ffmpeg helper routines,

Just have a look around the code and observe the mailing list. to learn
about the conventions.

Moritz
hanishkvc July 12, 2020, 2:28 p.m. UTC | #5
Hi Mortiz,

On Sun, 12 Jul, 2020, 18:31 Moritz Barsnick, <barsnick@gmx.net> wrote:

> On Sat, Jul 11, 2020 at 20:31:40 +0530, C Hanish Menon wrote:
> > > Also fix the changelog.
> >
> > Sorry I didn't understand this fully. Can I assume that you don't want to
> > mention about the fbtile helpers as an entry in the changelog, because
> its
> > not a public api?
>
> I believe what Lynne meant is:
>
> Changelog entries are added at the bottom, not at the top of the list.
> You can how other commits did something, before making assumptions.
>

Thanks for the input.


> > Thanks for suggesting the same (as previously mentioned, I haven't worked
> > on ffmpeg before so am not aware of all the ffmpeg helper routines,
>
> Just have a look around the code and observe the mailing list. to learn
> about the conventions.
>

Sure agree and I have tried to explore some of the related code to get
things going.

Wrt the specific suggestion that Lynne had given wrt av_frame_ref, for
which I was responding there, like what I had mentioned in my previous
email, I am not sure that is the right thing in that situation for two
reasons

A) to do with hardware mmaped memory being one of the buffers in question,
like what I had mentioned

And also because

B) the logic is mainly called where previously av_frame_copy would have got
called so also the fall back should be av_frame_copy rather than
av_frame_ref.


> Moritz
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
diff mbox series

Patch

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;