diff options
author | Eric Anholt <eric@anholt.net> | 2014-08-21 14:34:01 -0700 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2015-06-04 14:15:18 -0700 |
commit | 314f621460514b8fa081ce976e279fdecf2d1cc0 (patch) | |
tree | 092b946112fcd1a623ca40c0990426d7abb3bf8c | |
parent | b02eb5ff854b847710f7df4527f90c2d12beb094 (diff) | |
download | linux-314f621460514b8fa081ce976e279fdecf2d1cc0.tar.gz |
drm/vc4: Add texture tiling support and fix multi-level texture validation.
Signed-off-by: Eric Anholt <eric@anholt.net>
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_packet.h | 22 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_validate.c | 180 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_validate_shaders.c | 1 |
3 files changed, 154 insertions, 49 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_packet.h b/drivers/gpu/drm/vc4/vc4_packet.h index e455c2fe76a5..eef5be99a046 100644 --- a/drivers/gpu/drm/vc4/vc4_packet.h +++ b/drivers/gpu/drm/vc4/vc4_packet.h @@ -221,4 +221,26 @@ enum vc4_packet { #define VC4_RENDER_CONFIG_TILE_BUFFER_64BIT (1 << 1) #define VC4_RENDER_CONFIG_MS_MODE_4X (1 << 0) + +enum vc4_texture_data_type { + VC4_TEXTURE_TYPE_RGBA8888 = 0, + VC4_TEXTURE_TYPE_RGBX8888 = 1, + VC4_TEXTURE_TYPE_RGBA4444 = 2, + VC4_TEXTURE_TYPE_RGBA5551 = 3, + VC4_TEXTURE_TYPE_RGB565 = 4, + VC4_TEXTURE_TYPE_LUMINANCE = 5, + VC4_TEXTURE_TYPE_ALPHA = 6, + VC4_TEXTURE_TYPE_LUMALPHA = 7, + VC4_TEXTURE_TYPE_ETC1 = 8, + VC4_TEXTURE_TYPE_S16F = 9, + VC4_TEXTURE_TYPE_S8 = 10, + VC4_TEXTURE_TYPE_S16 = 11, + VC4_TEXTURE_TYPE_BW1 = 12, + VC4_TEXTURE_TYPE_A4 = 13, + VC4_TEXTURE_TYPE_A1 = 14, + VC4_TEXTURE_TYPE_RGBA64 = 15, + VC4_TEXTURE_TYPE_RGBA32R = 16, + VC4_TEXTURE_TYPE_YUV422R = 17, +}; + #endif /* VC4_PACKET_H */ diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c index 5cf4643f8c0b..55de3cd433e5 100644 --- a/drivers/gpu/drm/vc4/vc4_validate.c +++ b/drivers/gpu/drm/vc4/vc4_validate.c @@ -47,6 +47,53 @@ void *validated, \ void *untrusted + +/** Return the width in pixels of a 64-byte microtile. */ +static uint32_t +utile_width(int cpp) +{ + switch (cpp) { + case 1: + case 2: + return 8; + case 4: + return 4; + case 8: + return 2; + default: + DRM_ERROR("unknown cpp: %d\n", cpp); + return 1; + } +} + +/** Return the height in pixels of a 64-byte microtile. */ +static uint32_t +utile_height(int cpp) +{ + switch (cpp) { + case 1: + return 8; + case 2: + case 4: + case 8: + return 4; + default: + DRM_ERROR("unknown cpp: %d\n", cpp); + return 1; + } +} + +/** + * The texture unit decides what tiling format a particular miplevel is using + * this function, so we lay out our miptrees accordingly. + */ +static bool +size_is_lt(uint32_t width, uint32_t height, int cpp) +{ + return (width <= 4 * utile_width(cpp) || + height <= 4 * utile_height(cpp)); +} + static bool vc4_use_bo(struct exec_info *exec, uint32_t hindex, @@ -105,47 +152,50 @@ check_tex_size(struct exec_info *exec, struct drm_gem_cma_object *fbo, uint32_t offset, uint8_t tiling_format, uint32_t width, uint32_t height, uint8_t cpp) { - uint32_t width_align, height_align; - uint32_t aligned_row_len, aligned_h, size; + uint32_t aligned_width, aligned_height, stride, size; + uint32_t utile_w = utile_width(cpp); + uint32_t utile_h = utile_height(cpp); + + /* The values are limited by the packet/texture parameter bitfields, + * so we don't need to worry as much about integer overflow. + */ + BUG_ON(width > 65535); + BUG_ON(height > 65535); switch (tiling_format) { case VC4_TILING_FORMAT_LINEAR: - width_align = 16; - height_align = 1; + aligned_width = roundup(width, 16 / cpp); + aligned_height = height; break; case VC4_TILING_FORMAT_T: - width_align = 128; - height_align = 32; + aligned_width = roundup(width, utile_w * 8); + aligned_height = roundup(height, utile_h * 8); break; case VC4_TILING_FORMAT_LT: - width_align = 16; - height_align = 4; + aligned_width = roundup(width, utile_w); + aligned_height = roundup(height, utile_h); break; default: DRM_ERROR("buffer tiling %d unsupported\n", tiling_format); return false; } - /* The values are limited by the packet/texture parameter bitfields, - * so we don't need to worry as much about integer overflow. - */ - BUG_ON(width > 65535); - BUG_ON(height > 65535); + stride = aligned_width * cpp; - aligned_row_len = roundup(width * cpp, width_align); - aligned_h = roundup(height, height_align); - - if (INT_MAX / aligned_row_len < aligned_h) { - DRM_ERROR("Overflow in fbo size (%d * %d)\n", - aligned_row_len, aligned_h); + if (INT_MAX / stride < aligned_height) { + DRM_ERROR("Overflow in fbo size (%dx%d -> %dx%d)\n", + width, height, + aligned_width, aligned_height); return false; } - size = aligned_row_len * aligned_h; + size = stride * aligned_height; if (size + offset < size || size + offset > fbo->base.size) { - DRM_ERROR("Overflow in %dx%d fbo size (%d + %d > %d)\n", - width, height, size, offset, fbo->base.size); + DRM_ERROR("Overflow in %dx%d (%dx%d) fbo size (%d + %d > %d)\n", + width, height, + aligned_width, aligned_height, + size, offset, fbo->base.size); return false; } @@ -703,11 +753,12 @@ reloc_tex(struct exec_info *exec, uint32_t p1 = *(uint32_t *)(uniform_data_u + sample->p_offset[1]); uint32_t *validated_p0 = exec->uniforms_v + sample->p_offset[0]; uint32_t offset = p0 & ~0xfff; - uint32_t miplevels = (p0 & 0x15); + uint32_t miplevels = (p0 & 15); uint32_t width = (p1 >> 8) & 2047; uint32_t height = (p1 >> 20) & 2047; - uint32_t type, cpp, tiling_format; + uint32_t cpp, tiling_format, utile_w, utile_h; uint32_t i; + enum vc4_texture_data_type type; if (width == 0) width = 2048; @@ -722,40 +773,44 @@ reloc_tex(struct exec_info *exec, type = ((p0 >> 4) & 15) | ((p1 >> 31) << 4); switch (type) { - case 0: /* RGBA8888 */ - case 1: /* RGBX8888 */ - case 16: /* RGBA32R */ + case VC4_TEXTURE_TYPE_RGBA8888: + case VC4_TEXTURE_TYPE_RGBX8888: + case VC4_TEXTURE_TYPE_RGBA32R: cpp = 4; break; - case 2: /* RGBA4444 */ - case 3: /* RGBA5551 */ - case 4: /* RGB565 */ - case 7: /* LUMALPHA */ - case 9: /* S16F */ - case 11: /* S16 */ + case VC4_TEXTURE_TYPE_RGBA4444: + case VC4_TEXTURE_TYPE_RGBA5551: + case VC4_TEXTURE_TYPE_RGB565: + case VC4_TEXTURE_TYPE_LUMALPHA: + case VC4_TEXTURE_TYPE_S16F: + case VC4_TEXTURE_TYPE_S16: cpp = 2; break; - case 5: /* LUMINANCE */ - case 6: /* ALPHA */ - case 10: /* S8 */ + case VC4_TEXTURE_TYPE_LUMINANCE: + case VC4_TEXTURE_TYPE_ALPHA: + case VC4_TEXTURE_TYPE_S8: cpp = 1; break; - case 8: /* ETC1 */ - case 12: /* BW1 */ - case 13: /* A4 */ - case 14: /* A1 */ - case 15: /* RGBA64 */ - case 17: /* YUV422R */ + case VC4_TEXTURE_TYPE_ETC1: + case VC4_TEXTURE_TYPE_BW1: + case VC4_TEXTURE_TYPE_A4: + case VC4_TEXTURE_TYPE_A1: + case VC4_TEXTURE_TYPE_RGBA64: + case VC4_TEXTURE_TYPE_YUV422R: default: DRM_ERROR("Texture format %d unsupported\n", type); return false; } + utile_w = utile_width(cpp); + utile_h = utile_height(cpp); - if (type == 16) { + if (type == VC4_TEXTURE_TYPE_RGBA32R) { tiling_format = VC4_TILING_FORMAT_LINEAR; } else { - DRM_ERROR("Tiling formats not yet supported\n"); - return false; + if (size_is_lt(width, height, cpp)) + tiling_format = VC4_TILING_FORMAT_LT; + else + tiling_format = VC4_TILING_FORMAT_T; } if (!vc4_use_bo(exec, texture_handle_index, VC4_MODE_RENDER, &tex)) @@ -770,17 +825,44 @@ reloc_tex(struct exec_info *exec, * sure there is actually space in the BO. */ for (i = 1; i <= miplevels; i++) { - uint32_t level_width = roundup(max(width >> i, 1u), 16 / cpp); + uint32_t level_width = max(width >> i, 1u); uint32_t level_height = max(height >> i, 1u); - uint32_t level_size = level_width * level_height * cpp; + uint32_t aligned_width, aligned_height; + uint32_t level_size; + + /* Once the levels get small enough, they drop from T to LT. */ + if (tiling_format == VC4_TILING_FORMAT_T && + size_is_lt(level_width, level_height, cpp)) { + tiling_format = VC4_TILING_FORMAT_LT; + } + + switch (tiling_format) { + case VC4_TILING_FORMAT_T: + aligned_width = roundup(level_width, utile_w * 8); + aligned_height = roundup(level_height, utile_h * 8); + break; + case VC4_TILING_FORMAT_LT: + aligned_width = roundup(level_width, utile_w); + aligned_height = roundup(level_height, utile_h); + break; + default: + aligned_width = roundup(level_width, 16 / cpp); + aligned_height = height; + break; + } + + level_size = aligned_width * cpp * aligned_height; if (offset < level_size) { - DRM_ERROR("Level %d (%dx%d) size %db overflowed " - "buffer bounds (offset %d)\n", + DRM_ERROR("Level %d (%dx%d -> %dx%d) size %db " + "overflowed buffer bounds (offset %d)\n", i, level_width, level_height, + aligned_width, aligned_height, level_size, offset); return false; } + + offset -= level_size; } *validated_p0 = tex->paddr + p0; diff --git a/drivers/gpu/drm/vc4/vc4_validate_shaders.c b/drivers/gpu/drm/vc4/vc4_validate_shaders.c index c53807603a51..f7f35cebd228 100644 --- a/drivers/gpu/drm/vc4/vc4_validate_shaders.c +++ b/drivers/gpu/drm/vc4/vc4_validate_shaders.c @@ -255,6 +255,7 @@ vc4_validate_shader(struct drm_gem_cma_object *shader_obj, case QPU_SIG_NONE: case QPU_SIG_WAIT_FOR_SCOREBOARD: case QPU_SIG_SCOREBOARD_UNLOCK: + case QPU_SIG_COLOR_LOAD: case QPU_SIG_LOAD_TMU0: case QPU_SIG_LOAD_TMU1: if (!check_instruction_writes(inst, validated_shader, |