Skip to content

Commit 5011f80

Browse files
drm/apple: support interchange compression
Signed-off-by: Oliver Bestmann <oliver.bestmann@googlemail.com>
1 parent 7457799 commit 5011f80

2 files changed

Lines changed: 160 additions & 6 deletions

File tree

drivers/gpu/drm/apple/iomfb_plane.h

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@ enum dcp_xfer_func {
4949
DCP_XFER_FUNC_HDR = 16,
5050
};
5151

52+
enum dcp_address_format {
53+
DCP_ADDRESS_FORMAT_INTERCHANGE_TILED = 5,
54+
};
55+
56+
enum dcp_compression_type {
57+
DCP_COMPRESSION_TYPE_INTERCHANGE_TILED = 3,
58+
};
59+
5260
struct dcp_rect {
5361
u32 x;
5462
u32 y;
@@ -67,7 +75,26 @@ struct dcp_plane_info {
6775
u16 tile_size;
6876
u8 tile_w;
6977
u8 tile_h;
70-
u32 unk[13];
78+
u8 unk1[0xd];
79+
u8 address_format;
80+
u8 unk2[0x26];
81+
} __packed;
82+
83+
struct dcp_compression_info {
84+
u32 tile_w;
85+
u32 tile_h;
86+
u32 meta_offset;
87+
u32 data_offset;
88+
u32 tile_meta_bytes;
89+
u32 tiles_w;
90+
u32 tiles_h;
91+
u32 unk1;
92+
u32 compresson_type;
93+
u32 unk3;
94+
u8 _pad1[3];
95+
u32 tile_bytes;
96+
u32 row_stride;
97+
u8 pad2;
7198
} __packed;
7299

73100
struct dcp_component_types {
@@ -100,7 +127,7 @@ struct dcp_surface {
100127
u64 has_comp;
101128
struct dcp_plane_info planes[DCP_SURF_MAX_PLANES];
102129
u64 has_planes;
103-
u32 compression_info[DCP_SURF_MAX_PLANES][13];
130+
struct dcp_compression_info compression_info[DCP_SURF_MAX_PLANES];
104131
u64 has_compr_info;
105132
u32 unk_num;
106133
u32 unk_denom;

drivers/gpu/drm/apple/plane.c

Lines changed: 131 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,61 @@
99

1010
#include <drm/drm_atomic.h>
1111
#include <drm/drm_atomic_helper.h>
12-
#include <drm/drm_fourcc.h>
1312
#include <drm/drm_fb_dma_helper.h>
13+
#include <drm/drm_fourcc.h>
1414
#include <drm/drm_framebuffer.h>
1515
#include <drm/drm_gem.h>
1616
#include <drm/drm_gem_dma_helper.h>
1717
#include <drm/drm_plane.h>
1818

19+
#include <linux/align.h>
20+
#include <linux/log2.h>
21+
22+
#ifndef DRM_FORMAT_MOD_APPLE_INTERCHANGE_COMPRESSED
23+
#define DRM_FORMAT_MOD_APPLE_INTERCHANGE_COMPRESSED fourcc_mod_code(APPLE, 3)
24+
#endif
25+
1926
#define FRAC_16_16(mult, div) (((mult) << 16) / (div))
2027

28+
#define APPLE_GPU_CACHELINE 16
29+
30+
struct apple_interchange_layout {
31+
u32 tiles_width;
32+
u32 tiles_height;
33+
u32 tile_size_B;
34+
u32 meta_offset;
35+
u32 meta_size;
36+
};
37+
38+
static struct apple_interchange_layout
39+
get_apple_interchange_layout(u32 width, u32 height, u32 bpp)
40+
{
41+
u32 tw = DIV_ROUND_UP(width, 16);
42+
u32 th = DIV_ROUND_UP(height, 16);
43+
u32 tsize_B = 16 * 16 * (bpp / 8);
44+
45+
u32 meta_offset = ALIGN(tw * th * tsize_B, APPLE_GPU_CACHELINE);
46+
47+
/*
48+
* The metadata buffer contains 8 bytes per 16x16 compression tile.
49+
* Addressing is fully twiddled, so both width and height are padded to
50+
* powers-of-two.
51+
*/
52+
u32 w_tl = roundup_pow_of_two(tw);
53+
u32 h_tl = roundup_pow_of_two(th);
54+
u32 B_per_tl = 8;
55+
56+
u32 meta_size = ALIGN(w_tl * h_tl * B_per_tl, APPLE_GPU_CACHELINE);
57+
58+
return (struct apple_interchange_layout){
59+
.tiles_width = tw,
60+
.tiles_height = th,
61+
.tile_size_B = tsize_B,
62+
.meta_offset = meta_offset,
63+
.meta_size = meta_size,
64+
};
65+
}
66+
2167
static int apple_plane_atomic_check(struct drm_plane *plane,
2268
struct drm_atomic_state *state)
2369
{
@@ -105,6 +151,38 @@ static int apple_plane_atomic_check(struct drm_plane *plane,
105151
return -EINVAL;
106152
}
107153

154+
/*
155+
* The calculated size of the compression meta data must fit into the size
156+
* of the gem object
157+
*/
158+
for (u32 i = 0; i < new_plane_state->fb->format->num_planes; i++) {
159+
struct drm_framebuffer *fb = new_plane_state->fb;
160+
161+
if (fb->modifier != DRM_FORMAT_MOD_APPLE_INTERCHANGE_COMPRESSED)
162+
continue;
163+
164+
u32 width =
165+
drm_format_info_plane_width(fb->format, fb->width, i);
166+
u32 height =
167+
drm_format_info_plane_height(fb->format, fb->height, i);
168+
u32 bpp = drm_format_info_bpp(fb->format, i);
169+
struct apple_interchange_layout l =
170+
get_apple_interchange_layout(width, height, bpp);
171+
172+
u32 required_size =
173+
fb->offsets[0] + l.meta_offset + l.meta_size;
174+
175+
struct drm_gem_dma_object *obj = drm_fb_dma_get_gem_obj(fb, i);
176+
if (obj && required_size > obj->base.size) {
177+
dev_err_ratelimited(
178+
state->dev->dev,
179+
"dcp: atomic_check, required size of %u bytes is more than gem size of %zu\n",
180+
required_size, obj->base.size);
181+
182+
return -EINVAL;
183+
}
184+
}
185+
108186
return 0;
109187
}
110188

@@ -248,7 +326,6 @@ static void apple_plane_atomic_update(struct drm_plane *plane,
248326
.stride = fb->pitches[0],
249327
.width = fb->width,
250328
.height = fb->height,
251-
.buf_size = fb->height * fb->pitches[0],
252329
// .surface_id = req->swap.surf_ids[l],
253330

254331
/* Only used for compressed or multiplanar surfaces */
@@ -257,6 +334,7 @@ static void apple_plane_atomic_update(struct drm_plane *plane,
257334
.pel_h = 1,
258335
.has_comp = 1,
259336
.has_planes = 1,
337+
.has_compr_info = 1,
260338
};
261339

262340
/* Populate plane information for planar formats */
@@ -279,8 +357,33 @@ static void apple_plane_atomic_update(struct drm_plane *plane,
279357
.tile_h = bh,
280358
};
281359

282-
if (i > 0)
283-
surf->buf_size += surf->planes[i].size;
360+
if (fb->modifier == DRM_FORMAT_MOD_APPLE_INTERCHANGE_COMPRESSED) {
361+
u32 bpp = drm_format_info_bpp(fmt, i);
362+
struct apple_interchange_layout l =
363+
get_apple_interchange_layout(width, height, bpp);
364+
365+
surf->planes[i].tile_w = 16;
366+
surf->planes[i].tile_h = 16;
367+
surf->planes[i].stride = l.tiles_width * l.tile_size_B;
368+
surf->planes[i].size = l.meta_offset + l.meta_size;
369+
surf->planes[i].tile_size = l.tile_size_B;
370+
surf->planes[i].address_format = DCP_ADDRESS_FORMAT_INTERCHANGE_TILED;
371+
372+
surf->compression_info[i] = (struct dcp_compression_info){
373+
.tile_w = 16,
374+
.tile_h = 16,
375+
.data_offset = 0,
376+
.meta_offset = l.meta_offset,
377+
.tile_meta_bytes = 8,
378+
.tiles_w = l.tiles_width,
379+
.tiles_h = l.tiles_height,
380+
.tile_bytes = l.tile_size_B,
381+
.row_stride = l.tiles_width * l.tile_size_B,
382+
.compresson_type = DCP_COMPRESSION_TYPE_INTERCHANGE_TILED,
383+
};
384+
}
385+
386+
surf->buf_size += surf->planes[i].size;
284387
}
285388

286389
/* the obvious helper call drm_fb_dma_get_gem_addr() adjusts
@@ -337,6 +440,28 @@ apple_plane_duplicate_state(struct drm_plane *plane)
337440
return &apple_plane_state->base;
338441
}
339442

443+
static bool apple_plane_format_mod_supported(struct drm_plane *plane,
444+
uint32_t format, uint64_t modifier)
445+
{
446+
if (modifier != DRM_FORMAT_MOD_APPLE_INTERCHANGE_COMPRESSED) {
447+
return true;
448+
}
449+
450+
// interchange is only supported with rgba formats for now.
451+
switch (format) {
452+
case DRM_FORMAT_XRGB2101010:
453+
case DRM_FORMAT_ARGB2101010:
454+
case DRM_FORMAT_XRGB8888:
455+
case DRM_FORMAT_ARGB8888:
456+
case DRM_FORMAT_XBGR8888:
457+
case DRM_FORMAT_ABGR8888:
458+
return true;
459+
460+
default:
461+
return false;
462+
}
463+
}
464+
340465
// void apple_plane_destroy_state(struct drm_plane *plane,
341466
// struct drm_plane_state *state)
342467
// {
@@ -350,6 +475,7 @@ static const struct drm_plane_funcs apple_plane_funcs = {
350475
.atomic_duplicate_state = apple_plane_duplicate_state,
351476
// .atomic_destroy_state = apple_plane_destroy_state,
352477
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
478+
.format_mod_supported = apple_plane_format_mod_supported,
353479
};
354480

355481
/*
@@ -426,6 +552,7 @@ static const u32 dcp_overlay_formats_12_x[] = {
426552
};
427553

428554
u64 apple_format_modifiers[] = {
555+
DRM_FORMAT_MOD_APPLE_INTERCHANGE_COMPRESSED,
429556
DRM_FORMAT_MOD_LINEAR,
430557
DRM_FORMAT_MOD_INVALID
431558
};

0 commit comments

Comments
 (0)