summaryrefslogtreecommitdiff
path: root/utils/raspberrypi/ctt/ctt_awb.py
blob: bf45e54d5910a3241a97449c2f15cc7ac91db6e1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (C) 2019, Raspberry Pi Ltd
#
# ctt_awb.py - camera tuning tool for AWB

from ctt_image_load import *
import matplotlib.pyplot as plt
from bisect import bisect_left
from scipy.optimize import fmin


"""
obtain piecewise linear approximation for colour curve
"""
def awb(Cam, cal_cr_list, cal_cb_list, plot):
    imgs = Cam.imgs
    """
    condense alsc calibration tables into one dictionary
    """
    if cal_cr_list is None:
        colour_cals = None
    else:
        colour_cals = {}
        for cr, cb in zip(cal_cr_list, cal_cb_list):
            cr_tab = cr['table']
            cb_tab = cb['table']
            """
            normalise tables so min value is 1
            """
            cr_tab = cr_tab/np.min(cr_tab)
            cb_tab = cb_tab/np.min(cb_tab)
            colour_cals[cr['ct']] = [cr_tab, cb_tab]
    """
    obtain data from greyscale macbeth patches
    """
    rb_raw = []
    rbs_hat = []
    for Img in imgs:
        Cam.log += '\nProcessing '+Img.name
        """
        get greyscale patches with alsc applied if alsc enabled.
        Note: if alsc is disabled then colour_cals will be set to None and the
        function will just return the greyscale patches
        """
        r_patchs, b_patchs, g_patchs = get_alsc_patches(Img, colour_cals)
        """
        calculate ratio of r, b to g
        """
        r_g = np.mean(r_patchs/g_patchs)
        b_g = np.mean(b_patchs/g_patchs)
        Cam.log += '\n       r : {:.4f}       b : {:.4f}'.format(r_g, b_g)
        """
        The curve tends to be better behaved in so-called hatspace.
        R, B, G represent the individual channels. The colour curve is plotted in
        r, b space, where:
            r = R/G
            b = B/G
        This will be referred to as dehatspace... (sorry)
        Hatspace is defined as:
            r_hat = R/(R+B+G)
            b_hat = B/(R+B+G)
        To convert from dehatspace to hastpace (hat operation):
            r_hat = r/(1+r+b)
            b_hat = b/(1+r+b)
        To convert from hatspace to dehatspace (dehat operation):
            r = r_hat/(1-r_hat-b_hat)
            b = b_hat/(1-r_hat-b_hat)
        Proof is left as an excercise to the reader...
        Throughout the code, r and b are sometimes referred to as r_g and b_g
        as a reminder that they are ratios
        """
        r_g_hat = r_g/(1+r_g+b_g)
        b_g_hat = b_g/(1+r_g+b_g)
        Cam.log += '\n   r_hat : {:.4f}   b_hat : {:.4f}'.format(r_g_hat, b_g_hat)
        rbs_hat.append((r_g_hat, b_g_hat, Img.col))
        rb_raw.append((r_g, b_g))
        Cam.log += '\n'

    Cam.log += '\nFinished processing images'
    """
    sort all lits simultaneously by r_hat
    """
    rbs_zip = list(zip(rbs_hat, rb_raw))
    rbs_zip.sort(key=lambda x: x[0][0])
    rbs_hat, rb_raw = list(zip(*rbs_zip))
    """
    unzip tuples ready for processing
    """
    rbs_hat = list(zip(*rbs_hat))
    rb_raw = list(zip(*rb_raw))
    """
    fit quadratic fit to r_g hat and b_g_hat
    """
    a, b, c = np.polyfit(rbs_hat[0], rbs_hat[1], 2)
    Cam.log += '\nFit quadratic curve in hatspace'
    """
    the algorithm now approximates the shortest distance from each point to the
    curve in dehatspace. Since the fit is done in hatspace, it is easier to
    find the actual shortest distance in hatspace and use the projection back
    into dehatspace as an overestimate.
    The distance will be used for two things:
        1) In the case that colour temperature does not strictly decrease with
        increasing r/g, the closest point to the line will be chosen out of an
        increasing pair of colours.

        2) To calculate transverse negative an dpositive, the maximum positive
        and negative distance from the line are chosen. This benefits from the
        overestimate as the transverse pos/neg are upper bound values.
    """
    """
    define fit function
    """
    def f(x):
        return a*x**2 + b*x + c
    """
    iterate over points (R, B are x and y coordinates of points) and calculate
    distance to line in dehatspace
    """
    dists = []
    for i, (R, B) in enumerate(zip(rbs_hat[0], rbs_hat[1])):
        """
        define function to minimise as square distance between datapoint and
        point on curve. Squaring is monotonic so minimising radius squared is
        equivalent to minimising radius
        """
        def f_min(x):
            y = f(x)
            return((x-R)**2+(y-B)**2)
        """
        perform optimisation with scipy.optmisie.fmin
        """
        x_hat = fmin(f_min, R, disp=0)[0]
        y_hat = f(x_hat)
        """
        dehat
        """
        x = x_hat/(1-x_hat-y_hat)
        y = y_hat/(1-x_hat-y_hat)
        rr = R/(1-R-B)
        bb = B/(1-R-B)
        """
        calculate euclidean distance in dehatspace
        """
        dist = ((x-rr)**2+(y-bb)**2)**0.5
        """
        return negative if point is below the fit curve
        """
        if (x+y) > (rr+bb):
            dist *= -1
        dists.append(dist)
    Cam.log += '\nFound closest point on fit line to each point in dehatspace'
    """
    calculate wiggle factors in awb. 10% added since this is an upper bound
    """
    transverse_neg = - np.min(dists) * 1.1
    transverse_pos = np.max(dists) * 1.1
    Cam.log += '\nTransverse pos : {:.5f}'.format(transverse_pos)
    Cam.log += '\nTransverse neg : {:.5f}'.format(transverse_neg)
    """
    set minimum transverse wiggles to 0.1 .
    Wiggle factors dictate how far off of the curve the algorithm searches. 0.1
    is a suitable minimum that gives better results for lighting conditions not
    within calibration dataset. Anything less will generalise poorly.
    """
    if transverse_pos < 0.01:
        transverse_pos = 0.01
        Cam.log += '\nForced transverse pos to 0.01'
    if transverse_neg < 0.01:
        transverse_neg = 0.01
        Cam.log += '\nForced transverse neg to 0.01'

    """
    generate new b_hat values at each r_hat according to fit
    """
    r_hat_fit = np.array(rbs_hat[0])
    b_hat_fit = a*r_hat_fit**2 + b*r_hat_fit + c
    """
    transform from hatspace to dehatspace
    """
    r_fit = r_hat_fit/(1-r_hat_fit-b_hat_fit)
    b_fit = b_hat_fit/(1-r_hat_fit-b_hat_fit)
    c_fit = np.round(rbs_hat[2], 0)
    """
    round to 4dp
    """
    r_fit = np.where((1000*r_fit) % 1 <= 0.05, r_fit+0.0001, r_fit)
    r_fit = np.where((1000*r_fit) % 1 >= 0.95, r_fit-0.0001, r_fit)
    b_fit = np.where((1000*b_fit) % 1 <= 0.05, b_fit+0.0001, b_fit)
    b_fit = np.where((1000*b_fit) % 1 >= 0.95, b_fit-0.0001, b_fit)
    r_fit = np.round(r_fit, 4)
    b_fit = np.round(b_fit, 4)
    """
    The following code ensures that colour temperature decreases with
    increasing r/g
    """
    """
    iterate backwards over list for easier indexing
    """
    i = len(c_fit) - 1
    while i > 0:
        if c_fit[i] > c_fit[i-1]:
            Cam.log += '\nColour temperature increase found\n'
            Cam.log += '{} K at r = {} to '.format(c_fit[i-1], r_fit[i-1])
            Cam.log += '{} K at r = {}'.format(c_fit[i], r_fit[i])
            """
            if colour temperature increases then discard point furthest from
            the transformed fit (dehatspace)
            """
            error_1 = abs(dists[i-1])
            error_2 = abs(dists[i])
            Cam.log += '\nDistances from fit:\n'
            Cam.log += '{} K : {:.5f} , '.format(c_fit[i], error_1)
            Cam.log += '{} K : {:.5f}'.format(c_fit[i-1], error_2)
            """
            find bad index
            note that in python false = 0 and true = 1
            """
            bad = i - (error_1 < error_2)
            Cam.log += '\nPoint at {} K deleted as '.format(c_fit[bad])
            Cam.log += 'it is furthest from fit'
            """
            delete bad point
            """
            r_fit = np.delete(r_fit, bad)
            b_fit = np.delete(b_fit, bad)
            c_fit = np.delete(c_fit, bad).astype(np.uint16)
        """
        note that if a point has been discarded then the length has decreased
        by one, meaning that decreasing the index by one will reassess the kept
        point against the next point. It is therefore possible, in theory, for
        two adjacent points to be discarded, although probably rare
        """
        i -= 1

    """
    return formatted ct curve, ordered by increasing colour temperature
    """
    ct_curve = list(np.array(list(zip(b_fit, r_fit, c_fit))).flatten())[::-1]
    Cam.log += '\nFinal CT curve:'
    for i in range(len(ct_curve)//3):
        j = 3*i
        Cam.log += '\n  ct: {}  '.format(ct_curve[j])
        Cam.log += '  r: {}  '.format(ct_curve[j+1])
        Cam.log += '  b: {}  '.format(ct_curve[j+2])

    """
    plotting code for debug
    """
    if plot:
        x = np.linspace(np.min(rbs_hat[0]), np.max(rbs_hat[0]), 100)
        y = a*x**2 + b*x + c
        plt.subplot(2, 1, 1)
        plt.title('hatspace')
        plt.plot(rbs_hat[0], rbs_hat[1], ls='--', color='blue')
        plt.plot(x, y, color='green', ls='-')
        plt.scatter(rbs_hat[0], rbs_hat[1], color='red')
        for i, ct in enumerate(rbs_hat[2]):
            plt.annotate(str(ct), (rbs_hat[0][i], rbs_hat[1][i]))
        plt.xlabel('$\\hat{r}$')
        plt.ylabel('$\\hat{b}$')
        """
        optional set axes equal to shortest distance so line really does
        looks perpendicular and everybody is happy
        """
        # ax = plt.gca()
        # ax.set_aspect('equal')
        plt.grid()
        plt.subplot(2, 1, 2)
        plt.title('dehatspace - indoors?')
        plt.plot(r_fit, b_fit, color='blue')
        plt.scatter(rb_raw[0], rb_raw[1], color='green')
        plt.scatter(r_fit, b_fit, color='red')
        for i, ct in enumerate(c_fit):
            plt.annotate(str(ct), (r_fit[i], b_fit[i]))
        plt.xlabel('$r$')
        plt.ylabel('$b$')
        """
        optional set axes equal to shortest distance so line really does
        looks perpendicular and everybody is happy
        """
        # ax = plt.gca()
        # ax.set_aspect('equal')
        plt.subplots_adjust(hspace=0.5)
        plt.grid()
        plt.show()
    """
    end of plotting code
    """
    return(ct_curve, np.round(transverse_pos, 5), np.round(transverse_neg, 5))


"""
obtain greyscale patches and perform alsc colour correction
"""
def get_alsc_patches(Img, colour_cals, grey=True):
    """
    get patch centre coordinates, image colour and the actual
    patches for each channel, remembering to subtract blacklevel
    If grey then only greyscale patches considered
    """
    if grey:
        cen_coords = Img.cen_coords[3::4]
        col = Img.col
        patches = [np.array(Img.patches[i]) for i in Img.order]
        r_patchs = patches[0][3::4] - Img.blacklevel_16
        b_patchs = patches[3][3::4] - Img.blacklevel_16
        """
        note two green channels are averages
        """
        g_patchs = (patches[1][3::4]+patches[2][3::4])/2 - Img.blacklevel_16
    else:
        cen_coords = Img.cen_coords
        col = Img.col
        patches = [np.array(Img.patches[i]) for i in Img.order]
        r_patchs = patches[0] - Img.blacklevel_16
        b_patchs = patches[3] - Img.blacklevel_16
        g_patchs = (patches[1]+patches[2])/2 - Img.blacklevel_16

    if colour_cals is None:
        return r_patchs, b_patchs, g_patchs
    """
    find where image colour fits in alsc colour calibration tables
    """
    cts = list(colour_cals.keys())
    pos = bisect_left(cts, col)
    """
    if img colour is below minimum or above maximum alsc calibration colour, simply
    pick extreme closest to img colour
    """
    if pos % len(cts) == 0:
        """
        this works because -0 = 0 = first and -1 = last index
        """
        col_tabs = np.array(colour_cals[cts[-pos//len(cts)]])
        """
    else, perform linear interpolation between existing alsc colour
    calibration tables
    """
    else:
        bef = cts[pos-1]
        aft = cts[pos]
        da = col-bef
        db = aft-col
        bef_tabs = np.array(colour_cals[bef])
        aft_tabs = np.array(colour_cals[aft])
        col_tabs = (bef_tabs*db + aft_tabs*da)/(da+db)
    col_tabs = np.reshape(col_tabs, (2, 12, 16))
    """
    calculate dx, dy used to calculate alsc table
    """
    w, h = Img.w/2, Img.h/2
    dx, dy = int(-(-(w-1)//16)), int(-(-(h-1)//12))
    """
    make list of pairs of gains for each patch by selecting the correct value
    in alsc colour calibration table
    """
    patch_gains = []
    for cen in cen_coords:
        x, y = cen[0]//dx, cen[1]//dy
        # We could probably do with some better spatial interpolation here?
        col_gains = (col_tabs[0][y][x], col_tabs[1][y][x])
        patch_gains.append(col_gains)

    """
    multiply the r and b channels in each patch by the respective gain, finally
    performing the alsc colour correction
    """
    for i, gains in enumerate(patch_gains):
        r_patchs[i] = r_patchs[i] * gains[0]
        b_patchs[i] = b_patchs[i] * gains[1]

    """
    return greyscale patches, g channel and correct r, b channels
    """
    return r_patchs, b_patchs, g_patchs
1', '5') /* [15:0] R:G:B:x 5:5:5:1 little endian */ #define DRM_FORMAT_BGRX5551 fourcc_code('B', 'X', '1', '5') /* [15:0] B:G:R:x 5:5:5:1 little endian */ #define DRM_FORMAT_ARGB1555 fourcc_code('A', 'R', '1', '5') /* [15:0] A:R:G:B 1:5:5:5 little endian */ #define DRM_FORMAT_ABGR1555 fourcc_code('A', 'B', '1', '5') /* [15:0] A:B:G:R 1:5:5:5 little endian */ #define DRM_FORMAT_RGBA5551 fourcc_code('R', 'A', '1', '5') /* [15:0] R:G:B:A 5:5:5:1 little endian */ #define DRM_FORMAT_BGRA5551 fourcc_code('B', 'A', '1', '5') /* [15:0] B:G:R:A 5:5:5:1 little endian */ #define DRM_FORMAT_RGB565 fourcc_code('R', 'G', '1', '6') /* [15:0] R:G:B 5:6:5 little endian */ #define DRM_FORMAT_BGR565 fourcc_code('B', 'G', '1', '6') /* [15:0] B:G:R 5:6:5 little endian */ /* 24 bpp RGB */ #define DRM_FORMAT_RGB888 fourcc_code('R', 'G', '2', '4') /* [23:0] R:G:B little endian */ #define DRM_FORMAT_BGR888 fourcc_code('B', 'G', '2', '4') /* [23:0] B:G:R little endian */ /* 32 bpp RGB */ #define DRM_FORMAT_XRGB8888 fourcc_code('X', 'R', '2', '4') /* [31:0] x:R:G:B 8:8:8:8 little endian */ #define DRM_FORMAT_XBGR8888 fourcc_code('X', 'B', '2', '4') /* [31:0] x:B:G:R 8:8:8:8 little endian */ #define DRM_FORMAT_RGBX8888 fourcc_code('R', 'X', '2', '4') /* [31:0] R:G:B:x 8:8:8:8 little endian */ #define DRM_FORMAT_BGRX8888 fourcc_code('B', 'X', '2', '4') /* [31:0] B:G:R:x 8:8:8:8 little endian */ #define DRM_FORMAT_ARGB8888 fourcc_code('A', 'R', '2', '4') /* [31:0] A:R:G:B 8:8:8:8 little endian */ #define DRM_FORMAT_ABGR8888 fourcc_code('A', 'B', '2', '4') /* [31:0] A:B:G:R 8:8:8:8 little endian */ #define DRM_FORMAT_RGBA8888 fourcc_code('R', 'A', '2', '4') /* [31:0] R:G:B:A 8:8:8:8 little endian */ #define DRM_FORMAT_BGRA8888 fourcc_code('B', 'A', '2', '4') /* [31:0] B:G:R:A 8:8:8:8 little endian */ #define DRM_FORMAT_XRGB2101010 fourcc_code('X', 'R', '3', '0') /* [31:0] x:R:G:B 2:10:10:10 little endian */ #define DRM_FORMAT_XBGR2101010 fourcc_code('X', 'B', '3', '0') /* [31:0] x:B:G:R 2:10:10:10 little endian */ #define DRM_FORMAT_RGBX1010102 fourcc_code('R', 'X', '3', '0') /* [31:0] R:G:B:x 10:10:10:2 little endian */ #define DRM_FORMAT_BGRX1010102 fourcc_code('B', 'X', '3', '0') /* [31:0] B:G:R:x 10:10:10:2 little endian */ #define DRM_FORMAT_ARGB2101010 fourcc_code('A', 'R', '3', '0') /* [31:0] A:R:G:B 2:10:10:10 little endian */ #define DRM_FORMAT_ABGR2101010 fourcc_code('A', 'B', '3', '0') /* [31:0] A:B:G:R 2:10:10:10 little endian */ #define DRM_FORMAT_RGBA1010102 fourcc_code('R', 'A', '3', '0') /* [31:0] R:G:B:A 10:10:10:2 little endian */ #define DRM_FORMAT_BGRA1010102 fourcc_code('B', 'A', '3', '0') /* [31:0] B:G:R:A 10:10:10:2 little endian */ /* * Floating point 64bpp RGB * IEEE 754-2008 binary16 half-precision float * [15:0] sign:exponent:mantissa 1:5:10 */ #define DRM_FORMAT_XRGB16161616F fourcc_code('X', 'R', '4', 'H') /* [63:0] x:R:G:B 16:16:16:16 little endian */ #define DRM_FORMAT_XBGR16161616F fourcc_code('X', 'B', '4', 'H') /* [63:0] x:B:G:R 16:16:16:16 little endian */ #define DRM_FORMAT_ARGB16161616F fourcc_code('A', 'R', '4', 'H') /* [63:0] A:R:G:B 16:16:16:16 little endian */ #define DRM_FORMAT_ABGR16161616F fourcc_code('A', 'B', '4', 'H') /* [63:0] A:B:G:R 16:16:16:16 little endian */ /* * RGBA format with 10-bit components packed in 64-bit per pixel, with 6 bits * of unused padding per component: */ #define DRM_FORMAT_AXBXGXRX106106106106 fourcc_code('A', 'B', '1', '0') /* [63:0] A:x:B:x:G:x:R:x 10:6:10:6:10:6:10:6 little endian */ /* packed YCbCr */ #define DRM_FORMAT_YUYV fourcc_code('Y', 'U', 'Y', 'V') /* [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian */ #define DRM_FORMAT_YVYU fourcc_code('Y', 'V', 'Y', 'U') /* [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian */ #define DRM_FORMAT_UYVY fourcc_code('U', 'Y', 'V', 'Y') /* [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian */ #define DRM_FORMAT_VYUY fourcc_code('V', 'Y', 'U', 'Y') /* [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian */ #define DRM_FORMAT_AYUV fourcc_code('A', 'Y', 'U', 'V') /* [31:0] A:Y:Cb:Cr 8:8:8:8 little endian */ #define DRM_FORMAT_XYUV8888 fourcc_code('X', 'Y', 'U', 'V') /* [31:0] X:Y:Cb:Cr 8:8:8:8 little endian */ #define DRM_FORMAT_VUY888 fourcc_code('V', 'U', '2', '4') /* [23:0] Cr:Cb:Y 8:8:8 little endian */ #define DRM_FORMAT_VUY101010 fourcc_code('V', 'U', '3', '0') /* Y followed by U then V, 10:10:10. Non-linear modifier only */ /* * packed Y2xx indicate for each component, xx valid data occupy msb * 16-xx padding occupy lsb */ #define DRM_FORMAT_Y210 fourcc_code('Y', '2', '1', '0') /* [63:0] Cr0:0:Y1:0:Cb0:0:Y0:0 10:6:10:6:10:6:10:6 little endian per 2 Y pixels */ #define DRM_FORMAT_Y212 fourcc_code('Y', '2', '1', '2') /* [63:0] Cr0:0:Y1:0:Cb0:0:Y0:0 12:4:12:4:12:4:12:4 little endian per 2 Y pixels */ #define DRM_FORMAT_Y216 fourcc_code('Y', '2', '1', '6') /* [63:0] Cr0:Y1:Cb0:Y0 16:16:16:16 little endian per 2 Y pixels */ /* * packed Y4xx indicate for each component, xx valid data occupy msb * 16-xx padding occupy lsb except Y410 */ #define DRM_FORMAT_Y410 fourcc_code('Y', '4', '1', '0') /* [31:0] A:Cr:Y:Cb 2:10:10:10 little endian */ #define DRM_FORMAT_Y412 fourcc_code('Y', '4', '1', '2') /* [63:0] A:0:Cr:0:Y:0:Cb:0 12:4:12:4:12:4:12:4 little endian */ #define DRM_FORMAT_Y416 fourcc_code('Y', '4', '1', '6') /* [63:0] A:Cr:Y:Cb 16:16:16:16 little endian */ #define DRM_FORMAT_XVYU2101010 fourcc_code('X', 'V', '3', '0') /* [31:0] X:Cr:Y:Cb 2:10:10:10 little endian */ #define DRM_FORMAT_XVYU12_16161616 fourcc_code('X', 'V', '3', '6') /* [63:0] X:0:Cr:0:Y:0:Cb:0 12:4:12:4:12:4:12:4 little endian */ #define DRM_FORMAT_XVYU16161616 fourcc_code('X', 'V', '4', '8') /* [63:0] X:Cr:Y:Cb 16:16:16:16 little endian */ /* * packed YCbCr420 2x2 tiled formats * first 64 bits will contain Y,Cb,Cr components for a 2x2 tile */ /* [63:0] A3:A2:Y3:0:Cr0:0:Y2:0:A1:A0:Y1:0:Cb0:0:Y0:0 1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian */ #define DRM_FORMAT_Y0L0 fourcc_code('Y', '0', 'L', '0') /* [63:0] X3:X2:Y3:0:Cr0:0:Y2:0:X1:X0:Y1:0:Cb0:0:Y0:0 1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian */ #define DRM_FORMAT_X0L0 fourcc_code('X', '0', 'L', '0') /* [63:0] A3:A2:Y3:Cr0:Y2:A1:A0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian */ #define DRM_FORMAT_Y0L2 fourcc_code('Y', '0', 'L', '2') /* [63:0] X3:X2:Y3:Cr0:Y2:X1:X0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian */ #define DRM_FORMAT_X0L2 fourcc_code('X', '0', 'L', '2') /* * 1-plane YUV 4:2:0 * In these formats, the component ordering is specified (Y, followed by U * then V), but the exact Linear layout is undefined. * These formats can only be used with a non-Linear modifier. */ #define DRM_FORMAT_YUV420_8BIT fourcc_code('Y', 'U', '0', '8') #define DRM_FORMAT_YUV420_10BIT fourcc_code('Y', 'U', '1', '0') /* * 2 plane RGB + A * index 0 = RGB plane, same format as the corresponding non _A8 format has * index 1 = A plane, [7:0] A */ #define DRM_FORMAT_XRGB8888_A8 fourcc_code('X', 'R', 'A', '8') #define DRM_FORMAT_XBGR8888_A8 fourcc_code('X', 'B', 'A', '8') #define DRM_FORMAT_RGBX8888_A8 fourcc_code('R', 'X', 'A', '8') #define DRM_FORMAT_BGRX8888_A8 fourcc_code('B', 'X', 'A', '8') #define DRM_FORMAT_RGB888_A8 fourcc_code('R', '8', 'A', '8') #define DRM_FORMAT_BGR888_A8 fourcc_code('B', '8', 'A', '8') #define DRM_FORMAT_RGB565_A8 fourcc_code('R', '5', 'A', '8') #define DRM_FORMAT_BGR565_A8 fourcc_code('B', '5', 'A', '8') /* * 2 plane YCbCr * index 0 = Y plane, [7:0] Y * index 1 = Cr:Cb plane, [15:0] Cr:Cb little endian * or * index 1 = Cb:Cr plane, [15:0] Cb:Cr little endian */ #define DRM_FORMAT_NV12 fourcc_code('N', 'V', '1', '2') /* 2x2 subsampled Cr:Cb plane */ #define DRM_FORMAT_NV21 fourcc_code('N', 'V', '2', '1') /* 2x2 subsampled Cb:Cr plane */ #define DRM_FORMAT_NV16 fourcc_code('N', 'V', '1', '6') /* 2x1 subsampled Cr:Cb plane */ #define DRM_FORMAT_NV61 fourcc_code('N', 'V', '6', '1') /* 2x1 subsampled Cb:Cr plane */ #define DRM_FORMAT_NV24 fourcc_code('N', 'V', '2', '4') /* non-subsampled Cr:Cb plane */ #define DRM_FORMAT_NV42 fourcc_code('N', 'V', '4', '2') /* non-subsampled Cb:Cr plane */ /* * 2 plane YCbCr * index 0 = Y plane, [39:0] Y3:Y2:Y1:Y0 little endian * index 1 = Cr:Cb plane, [39:0] Cr1:Cb1:Cr0:Cb0 little endian */ #define DRM_FORMAT_NV15 fourcc_code('N', 'V', '1', '5') /* 2x2 subsampled Cr:Cb plane */ /* * 2 plane YCbCr MSB aligned * index 0 = Y plane, [15:0] Y:x [10:6] little endian * index 1 = Cr:Cb plane, [31:0] Cr:x:Cb:x [10:6:10:6] little endian */ #define DRM_FORMAT_P210 fourcc_code('P', '2', '1', '0') /* 2x1 subsampled Cr:Cb plane, 10 bit per channel */ /* * 2 plane YCbCr MSB aligned * index 0 = Y plane, [15:0] Y:x [10:6] little endian * index 1 = Cr:Cb plane, [31:0] Cr:x:Cb:x [10:6:10:6] little endian */ #define DRM_FORMAT_P010 fourcc_code('P', '0', '1', '0') /* 2x2 subsampled Cr:Cb plane 10 bits per channel */ /* * 2 plane YCbCr MSB aligned * index 0 = Y plane, [15:0] Y:x [12:4] little endian * index 1 = Cr:Cb plane, [31:0] Cr:x:Cb:x [12:4:12:4] little endian */ #define DRM_FORMAT_P012 fourcc_code('P', '0', '1', '2') /* 2x2 subsampled Cr:Cb plane 12 bits per channel */ /* * 2 plane YCbCr MSB aligned * index 0 = Y plane, [15:0] Y little endian * index 1 = Cr:Cb plane, [31:0] Cr:Cb [16:16] little endian */ #define DRM_FORMAT_P016 fourcc_code('P', '0', '1', '6') /* 2x2 subsampled Cr:Cb plane 16 bits per channel */ /* 3 plane non-subsampled (444) YCbCr * 16 bits per component, but only 10 bits are used and 6 bits are padded * index 0: Y plane, [15:0] Y:x [10:6] little endian * index 1: Cb plane, [15:0] Cb:x [10:6] little endian * index 2: Cr plane, [15:0] Cr:x [10:6] little endian */ #define DRM_FORMAT_Q410 fourcc_code('Q', '4', '1', '0') /* 3 plane non-subsampled (444) YCrCb * 16 bits per component, but only 10 bits are used and 6 bits are padded * index 0: Y plane, [15:0] Y:x [10:6] little endian * index 1: Cr plane, [15:0] Cr:x [10:6] little endian * index 2: Cb plane, [15:0] Cb:x [10:6] little endian */ #define DRM_FORMAT_Q401 fourcc_code('Q', '4', '0', '1') /* * 3 plane YCbCr * index 0: Y plane, [7:0] Y * index 1: Cb plane, [7:0] Cb * index 2: Cr plane, [7:0] Cr * or * index 1: Cr plane, [7:0] Cr * index 2: Cb plane, [7:0] Cb */ #define DRM_FORMAT_YUV410 fourcc_code('Y', 'U', 'V', '9') /* 4x4 subsampled Cb (1) and Cr (2) planes */ #define DRM_FORMAT_YVU410 fourcc_code('Y', 'V', 'U', '9') /* 4x4 subsampled Cr (1) and Cb (2) planes */ #define DRM_FORMAT_YUV411 fourcc_code('Y', 'U', '1', '1') /* 4x1 subsampled Cb (1) and Cr (2) planes */ #define DRM_FORMAT_YVU411 fourcc_code('Y', 'V', '1', '1') /* 4x1 subsampled Cr (1) and Cb (2) planes */ #define DRM_FORMAT_YUV420 fourcc_code('Y', 'U', '1', '2') /* 2x2 subsampled Cb (1) and Cr (2) planes */ #define DRM_FORMAT_YVU420 fourcc_code('Y', 'V', '1', '2') /* 2x2 subsampled Cr (1) and Cb (2) planes */ #define DRM_FORMAT_YUV422 fourcc_code('Y', 'U', '1', '6') /* 2x1 subsampled Cb (1) and Cr (2) planes */ #define DRM_FORMAT_YVU422 fourcc_code('Y', 'V', '1', '6') /* 2x1 subsampled Cr (1) and Cb (2) planes */ #define DRM_FORMAT_YUV444 fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */ #define DRM_FORMAT_YVU444 fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */ /* Compressed formats */ #define DRM_FORMAT_MJPEG fourcc_code('M', 'J', 'P', 'G') /* Motion-JPEG */ /* * Bayer formats * * Bayer formats contain green, red and blue components, with alternating lines * of red and green, and blue and green pixels in different orders. For each * block of 2x2 pixels there is one pixel with a red filter, two with a green * filter, and one with a blue filter. The filters can be arranged in different * patterns. * * For example, RGGB: * row0: RGRGRGRG... * row1: GBGBGBGB... * row3: RGRGRGRG... * row4: GBGBGBGB... * ... * * Vendors have different methods to pack the sampling formats to increase data * density. For this reason the fourcc only describes pixel sample size and the * filter pattern for each block of 2x2 pixels. A modifier is needed to * describe the memory layout. * * In addition to vendor modifiers for memory layout DRM_FORMAT_MOD_LINEAR may * be used to describe a layout where all samples are placed consecutively in * memory. If the sample does not fit inside a single byte, the sample storage * is extended to the minimum number of (little endian) bytes that can hold the * sample and any unused most-significant bits are defined as padding. * * For example, SRGGB10: * Each 10-bit sample is contained in 2 consecutive little endian bytes, where * the 6 most-significant bits are unused. */ /* 8-bit Bayer formats */ #define DRM_FORMAT_SRGGB8 fourcc_code('R', 'G', 'G', 'B') #define DRM_FORMAT_SGRBG8 fourcc_code('G', 'R', 'B', 'G') #define DRM_FORMAT_SGBRG8 fourcc_code('G', 'B', 'R', 'G') #define DRM_FORMAT_SBGGR8 fourcc_code('B', 'A', '8', '1') /* 10-bit Bayer formats */ #define DRM_FORMAT_SRGGB10 fourcc_code('R', 'G', '1', '0') #define DRM_FORMAT_SGRBG10 fourcc_code('B', 'A', '1', '0') #define DRM_FORMAT_SGBRG10 fourcc_code('G', 'B', '1', '0') #define DRM_FORMAT_SBGGR10 fourcc_code('B', 'G', '1', '0') /* 12-bit Bayer formats */ #define DRM_FORMAT_SRGGB12 fourcc_code('R', 'G', '1', '2') #define DRM_FORMAT_SGRBG12 fourcc_code('B', 'A', '1', '2') #define DRM_FORMAT_SGBRG12 fourcc_code('G', 'B', '1', '2') #define DRM_FORMAT_SBGGR12 fourcc_code('B', 'G', '1', '2') /* 14-bit Bayer formats */ #define DRM_FORMAT_SRGGB14 fourcc_code('R', 'G', '1', '4') #define DRM_FORMAT_SGRBG14 fourcc_code('B', 'A', '1', '4') #define DRM_FORMAT_SGBRG14 fourcc_code('G', 'B', '1', '4') #define DRM_FORMAT_SBGGR14 fourcc_code('B', 'G', '1', '4') /* 16-bit Bayer formats */ #define DRM_FORMAT_SRGGB16 fourcc_code('R', 'G', 'B', '6') #define DRM_FORMAT_SGRBG16 fourcc_code('G', 'R', '1', '6') #define DRM_FORMAT_SGBRG16 fourcc_code('G', 'B', '1', '6') #define DRM_FORMAT_SBGGR16 fourcc_code('B', 'Y', 'R', '2') /* * Format Modifiers: * * Format modifiers describe, typically, a re-ordering or modification * of the data in a plane of an FB. This can be used to express tiled/ * swizzled formats, or compression, or a combination of the two. * * The upper 8 bits of the format modifier are a vendor-id as assigned * below. The lower 56 bits are assigned as vendor sees fit. */ /* Vendor Ids: */ #define DRM_FORMAT_MOD_VENDOR_NONE 0 #define DRM_FORMAT_MOD_VENDOR_INTEL 0x01 #define DRM_FORMAT_MOD_VENDOR_AMD 0x02 #define DRM_FORMAT_MOD_VENDOR_NVIDIA 0x03 #define DRM_FORMAT_MOD_VENDOR_SAMSUNG 0x04 #define DRM_FORMAT_MOD_VENDOR_QCOM 0x05 #define DRM_FORMAT_MOD_VENDOR_VIVANTE 0x06 #define DRM_FORMAT_MOD_VENDOR_BROADCOM 0x07 #define DRM_FORMAT_MOD_VENDOR_ARM 0x08 #define DRM_FORMAT_MOD_VENDOR_ALLWINNER 0x09 #define DRM_FORMAT_MOD_VENDOR_AMLOGIC 0x0a #define DRM_FORMAT_MOD_VENDOR_MIPI 0x0b /* add more to the end as needed */ #define DRM_FORMAT_RESERVED ((1ULL << 56) - 1) #define fourcc_mod_code(vendor, val) \ ((((__u64)DRM_FORMAT_MOD_VENDOR_## vendor) << 56) | ((val) & 0x00ffffffffffffffULL)) /* * Format Modifier tokens: * * When adding a new token please document the layout with a code comment, * similar to the fourcc codes above. drm_fourcc.h is considered the * authoritative source for all of these. * * Generic modifier names: * * DRM_FORMAT_MOD_GENERIC_* definitions are used to provide vendor-neutral names * for layouts which are common across multiple vendors. To preserve * compatibility, in cases where a vendor-specific definition already exists and * a generic name for it is desired, the common name is a purely symbolic alias * and must use the same numerical value as the original definition. * * Note that generic names should only be used for modifiers which describe * generic layouts (such as pixel re-ordering), which may have * independently-developed support across multiple vendors. * * In future cases where a generic layout is identified before merging with a * vendor-specific modifier, a new 'GENERIC' vendor or modifier using vendor * 'NONE' could be considered. This should only be for obvious, exceptional * cases to avoid polluting the 'GENERIC' namespace with modifiers which only * apply to a single vendor. * * Generic names should not be used for cases where multiple hardware vendors * have implementations of the same standardised compression scheme (such as * AFBC). In those cases, all implementations should use the same format * modifier(s), reflecting the vendor of the standard. */ #define DRM_FORMAT_MOD_GENERIC_16_16_TILE DRM_FORMAT_MOD_SAMSUNG_16_16_TILE /* * Invalid Modifier * * This modifier can be used as a sentinel to terminate the format modifiers * list, or to initialize a variable with an invalid modifier. It might also be * used to report an error back to userspace for certain APIs. */ #define DRM_FORMAT_MOD_INVALID fourcc_mod_code(NONE, DRM_FORMAT_RESERVED) /* * Linear Layout * * Just plain linear layout. Note that this is different from no specifying any * modifier (e.g. not setting DRM_MODE_FB_MODIFIERS in the DRM_ADDFB2 ioctl), * which tells the driver to also take driver-internal information into account * and so might actually result in a tiled framebuffer. */ #define DRM_FORMAT_MOD_LINEAR fourcc_mod_code(NONE, 0) /* * Deprecated: use DRM_FORMAT_MOD_LINEAR instead * * The "none" format modifier doesn't actually mean that the modifier is * implicit, instead it means that the layout is linear. Whether modifiers are * used is out-of-band information carried in an API-specific way (e.g. in a * flag for drm_mode_fb_cmd2). */ #define DRM_FORMAT_MOD_NONE 0 /* Intel framebuffer modifiers */ /* * Intel X-tiling layout * * This is a tiled layout using 4Kb tiles (except on gen2 where the tiles 2Kb) * in row-major layout. Within the tile bytes are laid out row-major, with * a platform-dependent stride. On top of that the memory can apply * platform-depending swizzling of some higher address bits into bit6. * * Note that this layout is only accurate on intel gen 8+ or valleyview chipsets. * On earlier platforms the is highly platforms specific and not useful for * cross-driver sharing. It exists since on a given platform it does uniquely * identify the layout in a simple way for i915-specific userspace, which * facilitated conversion of userspace to modifiers. Additionally the exact * format on some really old platforms is not known. */ #define I915_FORMAT_MOD_X_TILED fourcc_mod_code(INTEL, 1) /* * Intel Y-tiling layout * * This is a tiled layout using 4Kb tiles (except on gen2 where the tiles 2Kb) * in row-major layout. Within the tile bytes are laid out in OWORD (16 bytes) * chunks column-major, with a platform-dependent height. On top of that the * memory can apply platform-depending swizzling of some higher address bits * into bit6. * * Note that this layout is only accurate on intel gen 8+ or valleyview chipsets. * On earlier platforms the is highly platforms specific and not useful for * cross-driver sharing. It exists since on a given platform it does uniquely * identify the layout in a simple way for i915-specific userspace, which * facilitated conversion of userspace to modifiers. Additionally the exact * format on some really old platforms is not known. */ #define I915_FORMAT_MOD_Y_TILED fourcc_mod_code(INTEL, 2) /* * Intel Yf-tiling layout * * This is a tiled layout using 4Kb tiles in row-major layout. * Within the tile pixels are laid out in 16 256 byte units / sub-tiles which * are arranged in four groups (two wide, two high) with column-major layout. * Each group therefore consits out of four 256 byte units, which are also laid * out as 2x2 column-major. * 256 byte units are made out of four 64 byte blocks of pixels, producing * either a square block or a 2:1 unit. * 64 byte blocks of pixels contain four pixel rows of 16 bytes, where the width * in pixel depends on the pixel depth. */ #define I915_FORMAT_MOD_Yf_TILED fourcc_mod_code(INTEL, 3) /* * Intel color control surface (CCS) for render compression * * The framebuffer format must be one of the 8:8:8:8 RGB formats. * The main surface will be plane index 0 and must be Y/Yf-tiled, * the CCS will be plane index 1. * * Each CCS tile matches a 1024x512 pixel area of the main surface. * To match certain aspects of the 3D hardware the CCS is * considered to be made up of normal 128Bx32 Y tiles, Thus * the CCS pitch must be specified in multiples of 128 bytes. * * In reality the CCS tile appears to be a 64Bx64 Y tile, composed * of QWORD (8 bytes) chunks instead of OWORD (16 bytes) chunks. * But that fact is not relevant unless the memory is accessed * directly. */ #define I915_FORMAT_MOD_Y_TILED_CCS fourcc_mod_code(INTEL, 4) #define I915_FORMAT_MOD_Yf_TILED_CCS fourcc_mod_code(INTEL, 5) /* * Intel color control surfaces (CCS) for Gen-12 render compression. * * The main surface is Y-tiled and at plane index 0, the CCS is linear and * at index 1. A 64B CCS cache line corresponds to an area of 4x1 tiles in * main surface. In other words, 4 bits in CCS map to a main surface cache * line pair. The main surface pitch is required to be a multiple of four * Y-tile widths. */ #define I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS fourcc_mod_code(INTEL, 6) /* * Intel color control surfaces (CCS) for Gen-12 media compression * * The main surface is Y-tiled and at plane index 0, the CCS is linear and * at index 1. A 64B CCS cache line corresponds to an area of 4x1 tiles in * main surface. In other words, 4 bits in CCS map to a main surface cache * line pair. The main surface pitch is required to be a multiple of four * Y-tile widths. For semi-planar formats like NV12, CCS planes follow the * Y and UV planes i.e., planes 0 and 1 are used for Y and UV surfaces, * planes 2 and 3 for the respective CCS. */ #define I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS fourcc_mod_code(INTEL, 7) /* * Intel Color Control Surface with Clear Color (CCS) for Gen-12 render * compression. * * The main surface is Y-tiled and is at plane index 0 whereas CCS is linear * and at index 1. The clear color is stored at index 2, and the pitch should * be ignored. The clear color structure is 256 bits. The first 128 bits * represents Raw Clear Color Red, Green, Blue and Alpha color each represented * by 32 bits. The raw clear color is consumed by the 3d engine and generates * the converted clear color of size 64 bits. The first 32 bits store the Lower * Converted Clear Color value and the next 32 bits store the Higher Converted * Clear Color value when applicable. The Converted Clear Color values are * consumed by the DE. The last 64 bits are used to store Color Discard Enable * and Depth Clear Value Valid which are ignored by the DE. A CCS cache line * corresponds to an area of 4x1 tiles in the main surface. The main surface * pitch is required to be a multiple of 4 tile widths. */ #define I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC fourcc_mod_code(INTEL, 8) /* * IPU3 Bayer packing layout * * The IPU3 raw Bayer formats use a custom packing layout where there are no * gaps between each 10-bit sample. It packs 25 pixels into 32 bytes leaving * the 6 most significant bits in the last byte unused. The format is little * endian. */ #define IPU3_FORMAT_MOD_PACKED fourcc_mod_code(INTEL, 9) /* * Tiled, NV12MT, grouped in 64 (pixels) x 32 (lines) -sized macroblocks * * Macroblocks are laid in a Z-shape, and each pixel data is following the * standard NV12 style. * As for NV12, an image is the result of two frame buffers: one for Y, * one for the interleaved Cb/Cr components (1/2 the height of the Y buffer). * Alignment requirements are (for each buffer): * - multiple of 128 pixels for the width * - multiple of 32 pixels for the height * * For more information: see https://linuxtv.org/downloads/v4l-dvb-apis/re32.html */ #define DRM_FORMAT_MOD_SAMSUNG_64_32_TILE fourcc_mod_code(SAMSUNG, 1) /* * Tiled, 16 (pixels) x 16 (lines) - sized macroblocks * * This is a simple tiled layout using tiles of 16x16 pixels in a row-major * layout. For YCbCr formats Cb/Cr components are taken in such a way that * they correspond to their 16x16 luma block. */ #define DRM_FORMAT_MOD_SAMSUNG_16_16_TILE fourcc_mod_code(SAMSUNG, 2) /* * Qualcomm Compressed Format * * Refers to a compressed variant of the base format that is compressed. * Implementation may be platform and base-format specific. * * Each macrotile consists of m x n (mostly 4 x 4) tiles. * Pixel data pitch/stride is aligned with macrotile width. * Pixel data height is aligned with macrotile height. * Entire pixel data buffer is aligned with 4k(bytes). */ #define DRM_FORMAT_MOD_QCOM_COMPRESSED fourcc_mod_code(QCOM, 1) /* Vivante framebuffer modifiers */ /* * Vivante 4x4 tiling layout * * This is a simple tiled layout using tiles of 4x4 pixels in a row-major * layout. */ #define DRM_FORMAT_MOD_VIVANTE_TILED fourcc_mod_code(VIVANTE, 1) /* * Vivante 64x64 super-tiling layout * * This is a tiled layout using 64x64 pixel super-tiles, where each super-tile * contains 8x4 groups of 2x4 tiles of 4x4 pixels (like above) each, all in row- * major layout. * * For more information: see * https://github.com/etnaviv/etna_viv/blob/master/doc/hardware.md#texture-tiling */ #define DRM_FORMAT_MOD_VIVANTE_SUPER_TILED fourcc_mod_code(VIVANTE, 2) /* * Vivante 4x4 tiling layout for dual-pipe * * Same as the 4x4 tiling layout, except every second 4x4 pixel tile starts at a * different base address. Offsets from the base addresses are therefore halved * compared to the non-split tiled layout. */ #define DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED fourcc_mod_code(VIVANTE, 3) /* * Vivante 64x64 super-tiling layout for dual-pipe * * Same as the 64x64 super-tiling layout, except every second 4x4 pixel tile * starts at a different base address. Offsets from the base addresses are * therefore halved compared to the non-split super-tiled layout. */ #define DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED fourcc_mod_code(VIVANTE, 4) /* NVIDIA frame buffer modifiers */ /* * Tegra Tiled Layout, used by Tegra 2, 3 and 4. * * Pixels are arranged in simple tiles of 16 x 16 bytes. */ #define DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED fourcc_mod_code(NVIDIA, 1) /* * Generalized Block Linear layout, used by desktop GPUs starting with NV50/G80, * and Tegra GPUs starting with Tegra K1. * * Pixels are arranged in Groups of Bytes (GOBs). GOB size and layout varies * based on the architecture generation. GOBs themselves are then arranged in * 3D blocks, with the block dimensions (in terms of GOBs) always being a power * of two, and hence expressible as their log2 equivalent (E.g., "2" represents * a block depth or height of "4"). * * Chapter 20 "Pixel Memory Formats" of the Tegra X1 TRM describes this format * in full detail. * * Macro * Bits Param Description * ---- ----- ----------------------------------------------------------------- * * 3:0 h log2(height) of each block, in GOBs. Placed here for * compatibility with the existing * DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK()-based modifiers. * * 4:4 - Must be 1, to indicate block-linear layout. Necessary for * compatibility with the existing * DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK()-based modifiers. * * 8:5 - Reserved (To support 3D-surfaces with variable log2(depth) block * size). Must be zero. * * Note there is no log2(width) parameter. Some portions of the * hardware support a block width of two gobs, but it is impractical * to use due to lack of support elsewhere, and has no known * benefits. * * 11:9 - Reserved (To support 2D-array textures with variable array stride * in blocks, specified via log2(tile width in blocks)). Must be * zero. * * 19:12 k Page Kind. This value directly maps to a field in the page * tables of all GPUs >= NV50. It affects the exact layout of bits * in memory and can be derived from the tuple * * (format, GPU model, compression type, samples per pixel) * * Where compression type is defined below. If GPU model were * implied by the format modifier, format, or memory buffer, page * kind would not need to be included in the modifier itself, but * since the modifier should define the layout of the associated * memory buffer independent from any device or other context, it * must be included here. * * 21:20 g GOB Height and Page Kind Generation. The height of a GOB changed * starting with Fermi GPUs. Additionally, the mapping between page * kind and bit layout has changed at various points. * * 0 = Gob Height 8, Fermi - Volta, Tegra K1+ Page Kind mapping * 1 = Gob Height 4, G80 - GT2XX Page Kind mapping * 2 = Gob Height 8, Turing+ Page Kind mapping * 3 = Reserved for future use. * * 22:22 s Sector layout. On Tegra GPUs prior to Xavier, there is a further * bit remapping step that occurs at an even lower level than the * page kind and block linear swizzles. This causes the layout of * surfaces mapped in those SOC's GPUs to be incompatible with the * equivalent mapping on other GPUs in the same system. * * 0 = Tegra K1 - Tegra Parker/TX2 Layout. * 1 = Desktop GPU and Tegra Xavier+ Layout * * 25:23 c Lossless Framebuffer Compression type. * * 0 = none * 1 = ROP/3D, layout 1, exact compression format implied by Page * Kind field * 2 = ROP/3D, layout 2, exact compression format implied by Page * Kind field * 3 = CDE horizontal * 4 = CDE vertical * 5 = Reserved for future use * 6 = Reserved for future use * 7 = Reserved for future use * * 55:25 - Reserved for future use. Must be zero. */ #define DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(c, s, g, k, h) \ fourcc_mod_code(NVIDIA, (0x10 | \ ((h) & 0xf) | \ (((k) & 0xff) << 12) | \ (((g) & 0x3) << 20) | \ (((s) & 0x1) << 22) | \ (((c) & 0x7) << 23))) /* To grandfather in prior block linear format modifiers to the above layout, * the page kind "0", which corresponds to "pitch/linear" and hence is unusable * with block-linear layouts, is remapped within drivers to the value 0xfe, * which corresponds to the "generic" kind used for simple single-sample * uncompressed color formats on Fermi - Volta GPUs. */ static __inline__ __u64 drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier) { if (!(modifier & 0x10) || (modifier & (0xff << 12))) return modifier; else return modifier | (0xfe << 12); } /* * 16Bx2 Block Linear layout, used by Tegra K1 and later * * Pixels are arranged in 64x8 Groups Of Bytes (GOBs). GOBs are then stacked * vertically by a power of 2 (1 to 32 GOBs) to form a block. * * Within a GOB, data is ordered as 16B x 2 lines sectors laid in Z-shape. * * Parameter 'v' is the log2 encoding of the number of GOBs stacked vertically. * Valid values are: * * 0 == ONE_GOB * 1 == TWO_GOBS * 2 == FOUR_GOBS * 3 == EIGHT_GOBS * 4 == SIXTEEN_GOBS * 5 == THIRTYTWO_GOBS * * Chapter 20 "Pixel Memory Formats" of the Tegra X1 TRM describes this format * in full detail. */ #define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(v) \ DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 0, 0, 0, (v)) #define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_ONE_GOB \ DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0) #define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_TWO_GOB \ DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1) #define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_FOUR_GOB \ DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2) #define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_EIGHT_GOB \ DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3) #define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_SIXTEEN_GOB \ DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4) #define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_THIRTYTWO_GOB \ DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5) /* * Some Broadcom modifiers take parameters, for example the number of * vertical lines in the image. Reserve the lower 32 bits for modifier * type, and the next 24 bits for parameters. Top 8 bits are the * vendor code. */ #define __fourcc_mod_broadcom_param_shift 8 #define __fourcc_mod_broadcom_param_bits 48 #define fourcc_mod_broadcom_code(val, params) \ fourcc_mod_code(BROADCOM, ((((__u64)params) << __fourcc_mod_broadcom_param_shift) | val)) #define fourcc_mod_broadcom_param(m) \ ((int)(((m) >> __fourcc_mod_broadcom_param_shift) & \ ((1ULL << __fourcc_mod_broadcom_param_bits) - 1))) #define fourcc_mod_broadcom_mod(m) \ ((m) & ~(((1ULL << __fourcc_mod_broadcom_param_bits) - 1) << \ __fourcc_mod_broadcom_param_shift)) /* * Broadcom VC4 "T" format * * This is the primary layout that the V3D GPU can texture from (it * can't do linear). The T format has: * * - 64b utiles of pixels in a raster-order grid according to cpp. It's 4x4 * pixels at 32 bit depth. * * - 1k subtiles made of a 4x4 raster-order grid of 64b utiles (so usually * 16x16 pixels). * * - 4k tiles made of a 2x2 grid of 1k subtiles (so usually 32x32 pixels). On * even 4k tile rows, they're arranged as (BL, TL, TR, BR), and on odd rows * they're (TR, BR, BL, TL), where bottom left is start of memory. * * - an image made of 4k tiles in rows either left-to-right (even rows of 4k * tiles) or right-to-left (odd rows of 4k tiles). */ #define DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED fourcc_mod_code(BROADCOM, 1) /* * Broadcom SAND format * * This is the native format that the H.264 codec block uses. For VC4 * HVS, it is only valid for H.264 (NV12/21) and RGBA modes. * * The image can be considered to be split into columns, and the * columns are placed consecutively into memory. The width of those * columns can be either 32, 64, 128, or 256 pixels, but in practice * only 128 pixel columns are used. * * The pitch between the start of each column is set to optimally * switch between SDRAM banks. This is passed as the number of lines * of column width in the modifier (we can't use the stride value due * to various core checks that look at it , so you should set the * stride to width*cpp). * * Note that the column height for this format modifier is the same * for all of the planes, assuming that each column contains both Y * and UV. Some SAND-using hardware stores UV in a separate tiled * image from Y to reduce the column height, which is not supported * with these modifiers. */ #define DRM_FORMAT_MOD_BROADCOM_SAND32_COL_HEIGHT(v) \ fourcc_mod_broadcom_code(2, v) #define DRM_FORMAT_MOD_BROADCOM_SAND64_COL_HEIGHT(v) \ fourcc_mod_broadcom_code(3, v) #define DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT(v) \ fourcc_mod_broadcom_code(4, v) #define DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(v) \ fourcc_mod_broadcom_code(5, v) #define DRM_FORMAT_MOD_BROADCOM_SAND32 \ DRM_FORMAT_MOD_BROADCOM_SAND32_COL_HEIGHT(0) #define DRM_FORMAT_MOD_BROADCOM_SAND64 \ DRM_FORMAT_MOD_BROADCOM_SAND64_COL_HEIGHT(0) #define DRM_FORMAT_MOD_BROADCOM_SAND128 \ DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT(0) #define DRM_FORMAT_MOD_BROADCOM_SAND256 \ DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(0) /* Broadcom UIF format * * This is the common format for the current Broadcom multimedia * blocks, including V3D 3.x and newer, newer video codecs, and * displays. * * The image consists of utiles (64b blocks), UIF blocks (2x2 utiles), * and macroblocks (4x4 UIF blocks). Those 4x4 UIF block groups are * stored in columns, with padding between the columns to ensure that * moving from one column to the next doesn't hit the same SDRAM page * bank. * * To calculate the padding, it is assumed that each hardware block * and the software driving it knows the platform's SDRAM page size, * number of banks, and XOR address, and that it's identical between * all blocks using the format. This tiling modifier will use XOR as * necessary to reduce the padding. If a hardware block can't do XOR, * the assumption is that a no-XOR tiling modifier will be created. */ #define DRM_FORMAT_MOD_BROADCOM_UIF fourcc_mod_code(BROADCOM, 6) /* * Arm Framebuffer Compression (AFBC) modifiers * * AFBC is a proprietary lossless image compression protocol and format. * It provides fine-grained random access and minimizes the amount of data * transferred between IP blocks. * * AFBC has several features which may be supported and/or used, which are * represented using bits in the modifier. Not all combinations are valid, * and different devices or use-cases may support different combinations. * * Further information on the use of AFBC modifiers can be found in * Documentation/gpu/afbc.rst */ /* * The top 4 bits (out of the 56 bits alloted for specifying vendor specific * modifiers) denote the category for modifiers. Currently we have only two * categories of modifiers ie AFBC and MISC. We can have a maximum of sixteen * different categories. */ #define DRM_FORMAT_MOD_ARM_CODE(__type, __val) \ fourcc_mod_code(ARM, ((__u64)(__type) << 52) | ((__val) & 0x000fffffffffffffULL)) #define DRM_FORMAT_MOD_ARM_TYPE_AFBC 0x00 #define DRM_FORMAT_MOD_ARM_TYPE_MISC 0x01 #define DRM_FORMAT_MOD_ARM_AFBC(__afbc_mode) \ DRM_FORMAT_MOD_ARM_CODE(DRM_FORMAT_MOD_ARM_TYPE_AFBC, __afbc_mode) /* * AFBC superblock size * * Indicates the superblock size(s) used for the AFBC buffer. The buffer * size (in pixels) must be aligned to a multiple of the superblock size. * Four lowest significant bits(LSBs) are reserved for block size. * * Where one superblock size is specified, it applies to all planes of the * buffer (e.g. 16x16, 32x8). When multiple superblock sizes are specified, * the first applies to the Luma plane and the second applies to the Chroma * plane(s). e.g. (32x8_64x4 means 32x8 Luma, with 64x4 Chroma). * Multiple superblock sizes are only valid for multi-plane YCbCr formats. */ #define AFBC_FORMAT_MOD_BLOCK_SIZE_MASK 0xf #define AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 (1ULL) #define AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 (2ULL) #define AFBC_FORMAT_MOD_BLOCK_SIZE_64x4 (3ULL) #define AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4 (4ULL) /* * AFBC lossless colorspace transform * * Indicates that the buffer makes use of the AFBC lossless colorspace * transform. */ #define AFBC_FORMAT_MOD_YTR (1ULL << 4) /* * AFBC block-split * * Indicates that the payload of each superblock is split. The second * half of the payload is positioned at a predefined offset from the start * of the superblock payload. */ #define AFBC_FORMAT_MOD_SPLIT (1ULL << 5) /* * AFBC sparse layout * * This flag indicates that the payload of each superblock must be stored at a * predefined position relative to the other superblocks in the same AFBC * buffer. This order is the same order used by the header buffer. In this mode * each superblock is given the same amount of space as an uncompressed * superblock of the particular format would require, rounding up to the next * multiple of 128 bytes in size. */ #define AFBC_FORMAT_MOD_SPARSE (1ULL << 6)