asahi: Add tilebuffer layout helpers
Laying out the tilebuffer is nontrivial and a task shared between GL and VK, so add unit-tested helpers. Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/19871>
This commit is contained in:

committed by
Marge Bot

parent
5d3243ea2d
commit
66a680a043
110
src/asahi/lib/agx_tilebuffer.c
Normal file
110
src/asahi/lib/agx_tilebuffer.c
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2022 Alyssa Rosenzweig
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "util/format/u_format.h"
|
||||
#include "agx_tilebuffer.h"
|
||||
#include "agx_formats.h"
|
||||
#include "agx_usc.h"
|
||||
|
||||
/* Maximum number of bytes per tile on G13G. This may change in future versions
|
||||
* of the architecture.
|
||||
*/
|
||||
#define MAX_BYTES_PER_TILE (32768 - 1)
|
||||
|
||||
/* Select the largest tile size that fits */
|
||||
static struct agx_tile_size
|
||||
agx_select_tile_size(unsigned bytes_per_pixel)
|
||||
{
|
||||
struct agx_tile_size sizes[] = {
|
||||
{ 32, 32 },
|
||||
{ 32, 16 },
|
||||
{ 16, 16 }
|
||||
};
|
||||
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(sizes); ++i) {
|
||||
struct agx_tile_size size = sizes[i];
|
||||
|
||||
if ((bytes_per_pixel * size.width * size.height) <= MAX_BYTES_PER_TILE)
|
||||
return size;
|
||||
}
|
||||
|
||||
unreachable("No supported tile size meets the bytes per pixel requirement");
|
||||
}
|
||||
|
||||
struct agx_tilebuffer_layout
|
||||
agx_build_tilebuffer_layout(enum pipe_format *formats,
|
||||
uint8_t nr_cbufs,
|
||||
uint8_t nr_samples)
|
||||
{
|
||||
struct agx_tilebuffer_layout tib = {
|
||||
.nr_samples = nr_samples
|
||||
};
|
||||
|
||||
uint32_t offset_B = 0;
|
||||
|
||||
for (unsigned rt = 0; rt < nr_cbufs; ++rt) {
|
||||
tib.logical_format[rt] = formats[rt];
|
||||
|
||||
/* Require natural alignment for tilebuffer allocations. This could be
|
||||
* optimized, but this shouldn't be a problem in practice.
|
||||
*/
|
||||
enum pipe_format physical_fmt = agx_tilebuffer_physical_format(&tib, rt);
|
||||
unsigned align_B = util_format_get_blocksize(physical_fmt);
|
||||
offset_B = ALIGN_POT(offset_B, align_B);
|
||||
|
||||
tib.offset_B[rt] = offset_B;
|
||||
|
||||
unsigned nr = util_format_get_nr_components(physical_fmt) == 1 ?
|
||||
util_format_get_nr_components(formats[rt]) : 1;
|
||||
|
||||
unsigned size_B = align_B * nr;
|
||||
offset_B += size_B;
|
||||
}
|
||||
|
||||
assert(offset_B <= 128 && "should fit in uint8");
|
||||
tib.sample_size_B = ALIGN_POT(offset_B, 8);
|
||||
|
||||
tib.tile_size = agx_select_tile_size(tib.sample_size_B * nr_samples);
|
||||
return tib;
|
||||
}
|
||||
|
||||
enum pipe_format
|
||||
agx_tilebuffer_physical_format(struct agx_tilebuffer_layout *tib, unsigned rt)
|
||||
{
|
||||
return agx_pixel_format[tib->logical_format[rt]].internal;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
agx_shared_layout_from_tile_size(struct agx_tile_size t)
|
||||
{
|
||||
if (t.width == 32 && t.height == 32)
|
||||
return AGX_SHARED_LAYOUT_32X32;
|
||||
else if (t.width == 32 && t.height == 16)
|
||||
return AGX_SHARED_LAYOUT_32X16;
|
||||
else if (t.width == 16 && t.height == 16)
|
||||
return AGX_SHARED_LAYOUT_16X16;
|
||||
else
|
||||
unreachable("Invalid tile size");
|
||||
}
|
||||
|
||||
uint32_t
|
||||
agx_tilebuffer_total_size(struct agx_tilebuffer_layout *tib)
|
||||
{
|
||||
return tib->sample_size_B * tib->nr_samples *
|
||||
tib->tile_size.width * tib->tile_size.height;
|
||||
}
|
||||
|
||||
void
|
||||
agx_usc_tilebuffer(struct agx_usc_builder *b, struct agx_tilebuffer_layout *tib)
|
||||
{
|
||||
agx_usc_pack(b, SHARED, cfg) {
|
||||
cfg.uses_shared_memory = true;
|
||||
cfg.layout = agx_shared_layout_from_tile_size(tib->tile_size);
|
||||
cfg.sample_stride_in_8_bytes = tib->sample_size_B / 8;
|
||||
cfg.sample_count = tib->nr_samples;
|
||||
cfg.bytes_per_threadgroup = agx_tilebuffer_total_size(tib);
|
||||
}
|
||||
}
|
64
src/asahi/lib/agx_tilebuffer.h
Normal file
64
src/asahi/lib/agx_tilebuffer.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2022 Alyssa Rosenzweig
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef __AGX_TILEBUFFER_H
|
||||
#define __AGX_TILEBUFFER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "util/format/u_formats.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Forward declarations to keep the header lean */
|
||||
struct nir_shader;
|
||||
struct agx_usc_builder;
|
||||
|
||||
struct agx_tile_size {
|
||||
uint8_t width;
|
||||
uint8_t height;
|
||||
};
|
||||
|
||||
struct agx_tilebuffer_layout {
|
||||
/* Logical format of each render target. Use agx_tilebuffer_physical_format
|
||||
* to get the physical format.
|
||||
*/
|
||||
enum pipe_format logical_format[8];
|
||||
|
||||
/* Offset into the sample of each render target */
|
||||
uint8_t offset_B[8];
|
||||
|
||||
/* Total bytes per sample, rounded up as needed */
|
||||
uint8_t sample_size_B;
|
||||
|
||||
/* Number of samples per pixel */
|
||||
uint8_t nr_samples;
|
||||
|
||||
/* Selected tile size */
|
||||
struct agx_tile_size tile_size;
|
||||
};
|
||||
|
||||
struct agx_tilebuffer_layout
|
||||
agx_build_tilebuffer_layout(enum pipe_format *formats, uint8_t nr_cbufs, uint8_t nr_samples);
|
||||
|
||||
bool
|
||||
agx_nir_lower_tilebuffer(struct nir_shader *shader, struct agx_tilebuffer_layout *tib);
|
||||
|
||||
void
|
||||
agx_usc_tilebuffer(struct agx_usc_builder *b, struct agx_tilebuffer_layout *tib);
|
||||
|
||||
uint32_t
|
||||
agx_tilebuffer_total_size(struct agx_tilebuffer_layout *tib);
|
||||
|
||||
enum pipe_format
|
||||
agx_tilebuffer_physical_format(struct agx_tilebuffer_layout *tib, unsigned rt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern C */
|
||||
#endif
|
||||
|
||||
#endif
|
@@ -24,6 +24,7 @@ dep_iokit = dependency('IOKit', required : false)
|
||||
libasahi_lib_files = files(
|
||||
'agx_device.c',
|
||||
'agx_formats.c',
|
||||
'agx_tilebuffer.c',
|
||||
'agx_ppp.h',
|
||||
'pool.c',
|
||||
)
|
||||
@@ -74,12 +75,13 @@ if with_tests
|
||||
'libasahi_tests',
|
||||
files(
|
||||
'tests/test-packing.cpp',
|
||||
'tests/test-tilebuffer.cpp',
|
||||
),
|
||||
c_args : [c_msvc_compat_args, no_override_init_args],
|
||||
gnu_symbol_visibility : 'hidden',
|
||||
include_directories : [inc_include, inc_src, inc_mesa],
|
||||
dependencies: [idep_gtest, idep_agx_pack],
|
||||
link_with : [],
|
||||
dependencies: [idep_gtest, idep_agx_pack, idep_mesautil],
|
||||
link_with : [libasahi_lib],
|
||||
),
|
||||
suite : ['asahi'],
|
||||
protocol : gtest_test_protocol,
|
||||
|
158
src/asahi/lib/tests/test-tilebuffer.cpp
Normal file
158
src/asahi/lib/tests/test-tilebuffer.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright 2022 Alyssa Rosenzweig
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "util/format/u_format.h"
|
||||
#include "agx_tilebuffer.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
struct test {
|
||||
const char *name;
|
||||
uint8_t nr_samples;
|
||||
enum pipe_format formats[8];
|
||||
struct agx_tilebuffer_layout layout;
|
||||
uint32_t total_size;
|
||||
};
|
||||
|
||||
struct test tests[] = {
|
||||
{
|
||||
"Simple test",
|
||||
1,
|
||||
{ PIPE_FORMAT_R8G8B8A8_UNORM },
|
||||
{
|
||||
.offset_B = { 0 },
|
||||
.sample_size_B = 8,
|
||||
.nr_samples = 1,
|
||||
.tile_size = { 32, 32 },
|
||||
},
|
||||
8192
|
||||
},
|
||||
{
|
||||
"MSAA 2x",
|
||||
2,
|
||||
{ PIPE_FORMAT_R8G8B8A8_UNORM },
|
||||
{
|
||||
.offset_B = { 0 },
|
||||
.sample_size_B = 8,
|
||||
.nr_samples = 2,
|
||||
.tile_size = { 32, 32 },
|
||||
},
|
||||
16384
|
||||
},
|
||||
{
|
||||
"MSAA 4x",
|
||||
4,
|
||||
{ PIPE_FORMAT_R8G8B8A8_UNORM },
|
||||
{
|
||||
.offset_B = { 0 },
|
||||
.sample_size_B = 8,
|
||||
.nr_samples = 4,
|
||||
.tile_size = { 32, 16 },
|
||||
},
|
||||
16384
|
||||
},
|
||||
{
|
||||
"MRT",
|
||||
1,
|
||||
{
|
||||
PIPE_FORMAT_R16_SINT,
|
||||
PIPE_FORMAT_R32G32_FLOAT,
|
||||
PIPE_FORMAT_R8_SINT,
|
||||
PIPE_FORMAT_R32G32_SINT,
|
||||
},
|
||||
{
|
||||
.offset_B = { 0, 4, 12, 16 },
|
||||
.sample_size_B = 24,
|
||||
.nr_samples = 1,
|
||||
.tile_size = { 32, 32 },
|
||||
},
|
||||
24576
|
||||
},
|
||||
{
|
||||
"MRT with MSAA 2x",
|
||||
2,
|
||||
{
|
||||
PIPE_FORMAT_R16_SINT,
|
||||
PIPE_FORMAT_R32G32_FLOAT,
|
||||
PIPE_FORMAT_R8_SINT,
|
||||
PIPE_FORMAT_R32G32_SINT,
|
||||
},
|
||||
{
|
||||
.offset_B = { 0, 4, 12, 16 },
|
||||
.sample_size_B = 24,
|
||||
.nr_samples = 2,
|
||||
.tile_size = { 32, 16 },
|
||||
},
|
||||
24576
|
||||
},
|
||||
{
|
||||
"MRT with MSAA 4x",
|
||||
4,
|
||||
{
|
||||
PIPE_FORMAT_R16_SINT,
|
||||
PIPE_FORMAT_R32G32_FLOAT,
|
||||
PIPE_FORMAT_R8_SINT,
|
||||
PIPE_FORMAT_R32G32_SINT,
|
||||
},
|
||||
{
|
||||
.offset_B = { 0, 4, 12, 16 },
|
||||
.sample_size_B = 24,
|
||||
.nr_samples = 4,
|
||||
.tile_size = { 16, 16 },
|
||||
},
|
||||
24576
|
||||
},
|
||||
{
|
||||
"MRT test requiring 2 alignment on the second RT",
|
||||
1,
|
||||
{ PIPE_FORMAT_R8_UNORM, PIPE_FORMAT_R16G16_SNORM },
|
||||
{
|
||||
.offset_B = { 0, 2 },
|
||||
.sample_size_B = 8,
|
||||
.nr_samples = 1,
|
||||
.tile_size = { 32, 32 },
|
||||
},
|
||||
8192
|
||||
},
|
||||
{
|
||||
"Simple MRT test requiring 4 alignment on the second RT",
|
||||
1,
|
||||
{ PIPE_FORMAT_R8_UNORM, PIPE_FORMAT_R10G10B10A2_UNORM },
|
||||
{
|
||||
.offset_B = { 0, 4 },
|
||||
.sample_size_B = 8,
|
||||
.nr_samples = 1,
|
||||
.tile_size = { 32, 32 },
|
||||
},
|
||||
8192
|
||||
}
|
||||
};
|
||||
|
||||
TEST(Tilebuffer, Layouts)
|
||||
{
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(tests); ++i) {
|
||||
unsigned nr_cbufs;
|
||||
|
||||
for (nr_cbufs = 0;
|
||||
nr_cbufs < ARRAY_SIZE(tests[i].formats) &&
|
||||
tests[i].formats[nr_cbufs] != PIPE_FORMAT_NONE;
|
||||
++nr_cbufs);
|
||||
|
||||
struct agx_tilebuffer_layout actual =
|
||||
agx_build_tilebuffer_layout(tests[i].formats, nr_cbufs,
|
||||
tests[i].nr_samples);
|
||||
|
||||
ASSERT_EQ(tests[i].layout.sample_size_B, actual.sample_size_B) <<
|
||||
tests[i].name;
|
||||
ASSERT_EQ(tests[i].layout.nr_samples, actual.nr_samples) << tests[i].name;
|
||||
ASSERT_EQ(tests[i].layout.tile_size.width, actual.tile_size.width) <<
|
||||
tests[i].name;
|
||||
ASSERT_EQ(tests[i].layout.tile_size.height, actual.tile_size.height) <<
|
||||
tests[i].name;
|
||||
ASSERT_EQ(tests[i].total_size,
|
||||
agx_tilebuffer_total_size(&tests[i].layout)) <<
|
||||
tests[i].name;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user