1/* 2 * Copyright (C) 2018 Rob Clark <robclark@freedesktop.org> 3 * Copyright © 2018 Google, Inc. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 * Authors: 25 * Rob Clark <robclark@freedesktop.org> 26 */ 27 28#include "drm-uapi/drm_fourcc.h" 29 30#include "fd6_resource.h" 31#include "fdl/fd6_format_table.h" 32 33#include "a6xx.xml.h" 34 35/* A subset of the valid tiled formats can be compressed. We do 36 * already require tiled in order to be compressed, but just because 37 * it can be tiled doesn't mean it can be compressed. 38 */ 39static bool 40ok_ubwc_format(struct pipe_screen *pscreen, enum pipe_format pfmt) 41{ 42 const struct fd_dev_info *info = fd_screen(pscreen)->info; 43 44 switch (pfmt) { 45 case PIPE_FORMAT_X24S8_UINT: 46 case PIPE_FORMAT_Z24_UNORM_S8_UINT: 47 /* We can't sample stencil with UBWC on a630, and we may need to be able 48 * to sample stencil at some point. We can't just use 49 * fd_resource_uncompress() at the point of stencil sampling because 50 * that itself uses stencil sampling in the fd_blitter_blit path. 51 */ 52 return info->a6xx.has_z24uint_s8uint; 53 54 case PIPE_FORMAT_R8_G8B8_420_UNORM: 55 return true; 56 57 default: 58 break; 59 } 60 61 switch (fd6_color_format(pfmt, TILE6_LINEAR)) { 62 case FMT6_10_10_10_2_UINT: 63 case FMT6_10_10_10_2_UNORM_DEST: 64 case FMT6_11_11_10_FLOAT: 65 case FMT6_16_FLOAT: 66 case FMT6_16_16_16_16_FLOAT: 67 case FMT6_16_16_16_16_SINT: 68 case FMT6_16_16_16_16_UINT: 69 case FMT6_16_16_FLOAT: 70 case FMT6_16_16_SINT: 71 case FMT6_16_16_UINT: 72 case FMT6_16_SINT: 73 case FMT6_16_UINT: 74 case FMT6_32_32_32_32_SINT: 75 case FMT6_32_32_32_32_UINT: 76 case FMT6_32_32_SINT: 77 case FMT6_32_32_UINT: 78 case FMT6_5_6_5_UNORM: 79 case FMT6_5_5_5_1_UNORM: 80 case FMT6_8_8_8_8_SINT: 81 case FMT6_8_8_8_8_UINT: 82 case FMT6_8_8_8_8_UNORM: 83 case FMT6_8_8_8_X8_UNORM: 84 case FMT6_8_8_SINT: 85 case FMT6_8_8_UINT: 86 case FMT6_8_8_UNORM: 87 case FMT6_Z24_UNORM_S8_UINT: 88 case FMT6_Z24_UNORM_S8_UINT_AS_R8G8B8A8: 89 return true; 90 case FMT6_8_UNORM: 91 return info->a6xx.has_8bpp_ubwc; 92 default: 93 return false; 94 } 95} 96 97static bool 98can_do_ubwc(struct pipe_resource *prsc) 99{ 100 /* limit things to simple single level 2d for now: */ 101 if ((prsc->depth0 != 1) || (prsc->array_size != 1) || 102 (prsc->last_level != 0)) 103 return false; 104 if (prsc->target != PIPE_TEXTURE_2D) 105 return false; 106 if (!ok_ubwc_format(prsc->screen, prsc->format)) 107 return false; 108 return true; 109} 110 111static bool 112is_norm(enum pipe_format format) 113{ 114 const struct util_format_description *desc = util_format_description(format); 115 116 return desc->is_snorm || desc->is_unorm; 117} 118 119static bool 120valid_format_cast(struct fd_resource *rsc, enum pipe_format format) 121{ 122 /* Special case "casting" format in hw: */ 123 if (format == PIPE_FORMAT_Z24_UNORM_S8_UINT_AS_R8G8B8A8) 124 return true; 125 126 /* For some color values (just "solid white") compression metadata maps to 127 * different pixel values for uint/sint vs unorm/snorm, so we can't reliably 128 * "cast" u/snorm to u/sint and visa versa: 129 */ 130 if (is_norm(format) != is_norm(rsc->b.b.format)) 131 return false; 132 133 /* The UBWC formats can be re-interpreted so long as the components 134 * have the same # of bits 135 */ 136 for (unsigned i = 0; i < 4; i++) { 137 unsigned sb, db; 138 139 sb = util_format_get_component_bits(rsc->b.b.format, UTIL_FORMAT_COLORSPACE_RGB, i); 140 db = util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, i); 141 142 if (sb != db) 143 return false; 144 } 145 146 return true; 147} 148 149/** 150 * R8G8 have a different block width/height and height alignment from other 151 * formats that would normally be compatible (like R16), and so if we are 152 * trying to, for example, sample R16 as R8G8 we need to demote to linear. 153 */ 154static bool 155is_r8g8(enum pipe_format format) 156{ 157 return (util_format_get_blocksize(format) == 2) && 158 (util_format_get_nr_components(format) == 2); 159} 160 161/** 162 * Ensure the rsc is in an ok state to be used with the specified format. 163 * This handles the case of UBWC buffers used with non-UBWC compatible 164 * formats, by triggering an uncompress. 165 */ 166void 167fd6_validate_format(struct fd_context *ctx, struct fd_resource *rsc, 168 enum pipe_format format) 169{ 170 enum pipe_format orig_format = rsc->b.b.format; 171 172 tc_assert_driver_thread(ctx->tc); 173 174 if (orig_format == format) 175 return; 176 177 if (rsc->layout.tile_mode && (is_r8g8(orig_format) != is_r8g8(format))) { 178 perf_debug_ctx(ctx, 179 "%" PRSC_FMT ": demoted to linear+uncompressed due to use as %s", 180 PRSC_ARGS(&rsc->b.b), util_format_short_name(format)); 181 182 fd_resource_uncompress(ctx, rsc, true); 183 return; 184 } 185 186 if (!rsc->layout.ubwc) 187 return; 188 189 if (ok_ubwc_format(rsc->b.b.screen, format) && valid_format_cast(rsc, format)) 190 return; 191 192 perf_debug_ctx(ctx, 193 "%" PRSC_FMT ": demoted to uncompressed due to use as %s", 194 PRSC_ARGS(&rsc->b.b), util_format_short_name(format)); 195 196 fd_resource_uncompress(ctx, rsc, false); 197} 198 199static void 200setup_lrz(struct fd_resource *rsc) 201{ 202 struct fd_screen *screen = fd_screen(rsc->b.b.screen); 203 unsigned width0 = rsc->b.b.width0; 204 unsigned height0 = rsc->b.b.height0; 205 206 /* LRZ buffer is super-sampled: */ 207 switch (rsc->b.b.nr_samples) { 208 case 4: 209 width0 *= 2; 210 FALLTHROUGH; 211 case 2: 212 height0 *= 2; 213 } 214 215 unsigned lrz_pitch = align(DIV_ROUND_UP(width0, 8), 32); 216 unsigned lrz_height = align(DIV_ROUND_UP(height0, 8), 16); 217 218 unsigned size = lrz_pitch * lrz_height * 2; 219 220 rsc->lrz_height = lrz_height; 221 rsc->lrz_width = lrz_pitch; 222 rsc->lrz_pitch = lrz_pitch; 223 rsc->lrz = fd_bo_new(screen->dev, size, FD_BO_NOMAP, "lrz"); 224} 225 226static uint32_t 227fd6_setup_slices(struct fd_resource *rsc) 228{ 229 struct pipe_resource *prsc = &rsc->b.b; 230 231 if (!FD_DBG(NOLRZ) && has_depth(rsc->b.b.format)) 232 setup_lrz(rsc); 233 234 if (rsc->layout.ubwc && !ok_ubwc_format(rsc->b.b.screen, rsc->b.b.format)) 235 rsc->layout.ubwc = false; 236 237 fdl6_layout(&rsc->layout, prsc->format, fd_resource_nr_samples(prsc), 238 prsc->width0, prsc->height0, prsc->depth0, prsc->last_level + 1, 239 prsc->array_size, prsc->target == PIPE_TEXTURE_3D, NULL); 240 241 return rsc->layout.size; 242} 243 244static int 245fill_ubwc_buffer_sizes(struct fd_resource *rsc) 246{ 247 struct pipe_resource *prsc = &rsc->b.b; 248 struct fdl_explicit_layout explicit = { 249 .offset = rsc->layout.slices[0].offset, 250 .pitch = rsc->layout.pitch0, 251 }; 252 253 if (!can_do_ubwc(prsc)) 254 return -1; 255 256 rsc->layout.ubwc = true; 257 rsc->layout.tile_mode = TILE6_3; 258 259 if (!fdl6_layout(&rsc->layout, prsc->format, fd_resource_nr_samples(prsc), 260 prsc->width0, prsc->height0, prsc->depth0, 261 prsc->last_level + 1, prsc->array_size, false, &explicit)) 262 return -1; 263 264 if (rsc->layout.size > fd_bo_size(rsc->bo)) 265 return -1; 266 267 return 0; 268} 269 270static int 271fd6_layout_resource_for_modifier(struct fd_resource *rsc, uint64_t modifier) 272{ 273 switch (modifier) { 274 case DRM_FORMAT_MOD_QCOM_COMPRESSED: 275 return fill_ubwc_buffer_sizes(rsc); 276 case DRM_FORMAT_MOD_LINEAR: 277 if (can_do_ubwc(&rsc->b.b)) { 278 perf_debug("%" PRSC_FMT 279 ": not UBWC: imported with DRM_FORMAT_MOD_LINEAR!", 280 PRSC_ARGS(&rsc->b.b)); 281 } 282 return 0; 283 case DRM_FORMAT_MOD_INVALID: 284 if (can_do_ubwc(&rsc->b.b)) { 285 perf_debug("%" PRSC_FMT 286 ": not UBWC: imported with DRM_FORMAT_MOD_INVALID!", 287 PRSC_ARGS(&rsc->b.b)); 288 } 289 return 0; 290 default: 291 return -1; 292 } 293} 294 295static const uint64_t supported_modifiers[] = { 296 DRM_FORMAT_MOD_LINEAR, 297 DRM_FORMAT_MOD_QCOM_COMPRESSED, 298}; 299 300void 301fd6_resource_screen_init(struct pipe_screen *pscreen) 302{ 303 struct fd_screen *screen = fd_screen(pscreen); 304 305 screen->setup_slices = fd6_setup_slices; 306 screen->layout_resource_for_modifier = fd6_layout_resource_for_modifier; 307 screen->supported_modifiers = supported_modifiers; 308 screen->num_supported_modifiers = ARRAY_SIZE(supported_modifiers); 309} 310