1 /* 2 * Copyright (c) 2012-2015 Etnaviv Project 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sub license, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the 12 * next paragraph) shall be included in all copies or substantial portions 13 * of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 * 23 * Authors: 24 * Wladimir J. van der Laan <laanwj (at) gmail.com> 25 */ 26 27 #include "etnaviv_resource.h" 28 29 #include "hw/common.xml.h" 30 31 #include "etnaviv_context.h" 32 #include "etnaviv_debug.h" 33 #include "etnaviv_screen.h" 34 #include "etnaviv_translate.h" 35 36 #include "util/u_inlines.h" 37 #include "util/u_memory.h" 38 39 /* A tile is 4x4 pixels, having 'screen->specs.bits_per_tile' of tile status. 40 * So, in a buffer of N pixels, there are N / (4 * 4) tiles. 41 * We need N * screen->specs.bits_per_tile / (4 * 4) bits of tile status, or 42 * N * screen->specs.bits_per_tile / (4 * 4 * 8) bytes. 43 */ 44 bool 45 etna_screen_resource_alloc_ts(struct pipe_screen *pscreen, 46 struct etna_resource *rsc) 47 { 48 struct etna_screen *screen = etna_screen(pscreen); 49 size_t rt_ts_size, ts_layer_stride, pixels; 50 51 assert(!rsc->ts_bo); 52 53 /* TS only for level 0 -- XXX is this formula correct? */ 54 pixels = rsc->levels[0].layer_stride / util_format_get_blocksize(rsc->base.format); 55 ts_layer_stride = align(pixels * screen->specs.bits_per_tile / 0x80, 0x100); 56 rt_ts_size = ts_layer_stride * rsc->base.array_size; 57 if (rt_ts_size == 0) 58 return true; 59 60 DBG_F(ETNA_DBG_RESOURCE_MSGS, "%p: Allocating tile status of size %zu", 61 rsc, rt_ts_size); 62 63 struct etna_bo *rt_ts; 64 rt_ts = etna_bo_new(screen->dev, rt_ts_size, DRM_ETNA_GEM_CACHE_WC); 65 66 if (unlikely(!rt_ts)) { 67 BUG("Problem allocating tile status for resource"); 68 return false; 69 } 70 71 rsc->ts_bo = rt_ts; 72 rsc->levels[0].ts_offset = 0; 73 rsc->levels[0].ts_layer_stride = ts_layer_stride; 74 rsc->levels[0].ts_size = rt_ts_size; 75 76 /* It is important to initialize the TS, as random pattern 77 * can result in crashes. Do this on the CPU as this only happens once 78 * per surface anyway and it's a small area, so it may not be worth 79 * queuing this to the GPU. */ 80 void *ts_map = etna_bo_map(rt_ts); 81 memset(ts_map, screen->specs.ts_clear_value, rt_ts_size); 82 83 return true; 84 } 85 86 static boolean 87 etna_screen_can_create_resource(struct pipe_screen *pscreen, 88 const struct pipe_resource *templat) 89 { 90 struct etna_screen *screen = etna_screen(pscreen); 91 if (!translate_samples_to_xyscale(templat->nr_samples, NULL, NULL, NULL)) 92 return false; 93 94 /* templat->bind is not set here, so we must use the minimum sizes */ 95 uint max_size = 96 MIN2(screen->specs.max_rendertarget_size, screen->specs.max_texture_size); 97 98 if (templat->width0 > max_size || templat->height0 > max_size) 99 return false; 100 101 return true; 102 } 103 104 static unsigned 105 setup_miptree(struct etna_resource *rsc, unsigned paddingX, unsigned paddingY, 106 unsigned msaa_xscale, unsigned msaa_yscale) 107 { 108 struct pipe_resource *prsc = &rsc->base; 109 unsigned level, size = 0; 110 unsigned width = prsc->width0; 111 unsigned height = prsc->height0; 112 unsigned depth = prsc->depth0; 113 114 for (level = 0; level <= prsc->last_level; level++) { 115 struct etna_resource_level *mip = &rsc->levels[level]; 116 117 mip->width = width; 118 mip->height = height; 119 mip->padded_width = align(width * msaa_xscale, paddingX); 120 mip->padded_height = align(height * msaa_yscale, paddingY); 121 mip->stride = util_format_get_stride(prsc->format, mip->padded_width); 122 mip->offset = size; 123 mip->layer_stride = mip->stride * util_format_get_nblocksy(prsc->format, mip->padded_height); 124 mip->size = prsc->array_size * mip->layer_stride; 125 126 /* align levels to 64 bytes to be able to render to them */ 127 size += align(mip->size, ETNA_PE_ALIGNMENT) * depth; 128 129 width = u_minify(width, 1); 130 height = u_minify(height, 1); 131 depth = u_minify(depth, 1); 132 } 133 134 return size; 135 } 136 137 /* Create a new resource object, using the given template info */ 138 struct pipe_resource * 139 etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout, 140 const struct pipe_resource *templat) 141 { 142 struct etna_screen *screen = etna_screen(pscreen); 143 unsigned size; 144 145 DBG_F(ETNA_DBG_RESOURCE_MSGS, 146 "target=%d, format=%s, %ux%ux%u, array_size=%u, " 147 "last_level=%u, nr_samples=%u, usage=%u, bind=%x, flags=%x", 148 templat->target, util_format_name(templat->format), templat->width0, 149 templat->height0, templat->depth0, templat->array_size, 150 templat->last_level, templat->nr_samples, templat->usage, 151 templat->bind, templat->flags); 152 153 /* Determine scaling for antialiasing, allow override using debug flag */ 154 int nr_samples = templat->nr_samples; 155 if ((templat->bind & (PIPE_BIND_RENDER_TARGET | PIPE_BIND_DEPTH_STENCIL)) && 156 !(templat->bind & PIPE_BIND_SAMPLER_VIEW)) { 157 if (DBG_ENABLED(ETNA_DBG_MSAA_2X)) 158 nr_samples = 2; 159 if (DBG_ENABLED(ETNA_DBG_MSAA_4X)) 160 nr_samples = 4; 161 } 162 163 int msaa_xscale = 1, msaa_yscale = 1; 164 if (!translate_samples_to_xyscale(nr_samples, &msaa_xscale, &msaa_yscale, NULL)) { 165 /* Number of samples not supported */ 166 return NULL; 167 } 168 169 /* If we have the TEXTURE_HALIGN feature, we can always align to the 170 * resolve engine's width. If not, we must not align resources used 171 * only for textures. */ 172 bool rs_align = VIV_FEATURE(screen, chipMinorFeatures1, TEXTURE_HALIGN) || 173 !etna_resource_sampler_only(templat); 174 175 /* Determine needed padding (alignment of height/width) */ 176 unsigned paddingX = 0, paddingY = 0; 177 unsigned halign = TEXTURE_HALIGN_FOUR; 178 etna_layout_multiple(layout, screen->specs.pixel_pipes, rs_align, &paddingX, 179 &paddingY, &halign); 180 assert(paddingX && paddingY); 181 182 if (templat->bind != PIPE_BUFFER) { 183 unsigned min_paddingY = 4 * screen->specs.pixel_pipes; 184 if (paddingY < min_paddingY) 185 paddingY = min_paddingY; 186 } 187 188 struct etna_resource *rsc = CALLOC_STRUCT(etna_resource); 189 190 if (!rsc) 191 return NULL; 192 193 rsc->base = *templat; 194 rsc->base.screen = pscreen; 195 rsc->base.nr_samples = nr_samples; 196 rsc->layout = layout; 197 rsc->halign = halign; 198 199 pipe_reference_init(&rsc->base.reference, 1); 200 list_inithead(&rsc->list); 201 202 size = setup_miptree(rsc, paddingX, paddingY, msaa_xscale, msaa_yscale); 203 204 uint32_t flags = DRM_ETNA_GEM_CACHE_WC; 205 if (templat->bind & PIPE_BIND_VERTEX_BUFFER) 206 flags |= DRM_ETNA_GEM_FORCE_MMU; 207 struct etna_bo *bo = etna_bo_new(screen->dev, size, flags); 208 if (unlikely(bo == NULL)) { 209 BUG("Problem allocating video memory for resource"); 210 return NULL; 211 } 212 213 rsc->bo = bo; 214 rsc->ts_bo = 0; /* TS is only created when first bound to surface */ 215 216 if (templat->bind & PIPE_BIND_SCANOUT) 217 rsc->scanout = renderonly_scanout_for_resource(&rsc->base, screen->ro); 218 219 if (DBG_ENABLED(ETNA_DBG_ZERO)) { 220 void *map = etna_bo_map(bo); 221 memset(map, 0, size); 222 } 223 224 return &rsc->base; 225 } 226 227 static struct pipe_resource * 228 etna_resource_create(struct pipe_screen *pscreen, 229 const struct pipe_resource *templat) 230 { 231 struct etna_screen *screen = etna_screen(pscreen); 232 233 /* Figure out what tiling to use -- for now, assume that textures cannot be 234 * supertiled, and cannot be linear. 235 * There is a feature flag SUPERTILED_TEXTURE (not supported on any known hw) 236 * that may allow this, as well 237 * as LINEAR_TEXTURE_SUPPORT (supported on gc880 and gc2000 at least), but 238 * not sure how it works. 239 * Buffers always have LINEAR layout. 240 */ 241 unsigned layout = ETNA_LAYOUT_LINEAR; 242 if (etna_resource_sampler_only(templat)) { 243 /* The buffer is only used for texturing, so create something 244 * directly compatible with the sampler. Such a buffer can 245 * never be rendered to. */ 246 layout = ETNA_LAYOUT_TILED; 247 248 if (util_format_is_compressed(templat->format)) 249 layout = ETNA_LAYOUT_LINEAR; 250 } else if (templat->target != PIPE_BUFFER) { 251 bool want_multitiled = screen->specs.pixel_pipes > 1; 252 bool want_supertiled = screen->specs.can_supertile && !DBG_ENABLED(ETNA_DBG_NO_SUPERTILE); 253 254 /* Keep single byte blocksized resources as tiled, since we 255 * are unable to use the RS blit to de-tile them. However, 256 * if they're used as a render target or depth/stencil, they 257 * must be multi-tiled for GPUs with multiple pixel pipes. 258 * Ignore depth/stencil here, but it is an error for a render 259 * target. 260 */ 261 if (util_format_get_blocksize(templat->format) == 1 && 262 !(templat->bind & PIPE_BIND_DEPTH_STENCIL)) { 263 assert(!(templat->bind & PIPE_BIND_RENDER_TARGET && want_multitiled)); 264 want_multitiled = want_supertiled = false; 265 } 266 267 layout = ETNA_LAYOUT_BIT_TILE; 268 if (want_multitiled) 269 layout |= ETNA_LAYOUT_BIT_MULTI; 270 if (want_supertiled) 271 layout |= ETNA_LAYOUT_BIT_SUPER; 272 } 273 274 if (templat->target == PIPE_TEXTURE_3D) 275 layout = ETNA_LAYOUT_LINEAR; 276 277 return etna_resource_alloc(pscreen, layout, templat); 278 } 279 280 static void 281 etna_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc) 282 { 283 struct etna_resource *rsc = etna_resource(prsc); 284 285 if (rsc->bo) 286 etna_bo_del(rsc->bo); 287 288 if (rsc->ts_bo) 289 etna_bo_del(rsc->ts_bo); 290 291 if (rsc->scanout) 292 renderonly_scanout_destroy(rsc->scanout); 293 294 list_delinit(&rsc->list); 295 296 pipe_resource_reference(&rsc->texture, NULL); 297 298 FREE(rsc); 299 } 300 301 static struct pipe_resource * 302 etna_resource_from_handle(struct pipe_screen *pscreen, 303 const struct pipe_resource *tmpl, 304 struct winsys_handle *handle, unsigned usage) 305 { 306 struct etna_screen *screen = etna_screen(pscreen); 307 struct etna_resource *rsc = CALLOC_STRUCT(etna_resource); 308 struct etna_resource_level *level = &rsc->levels[0]; 309 struct pipe_resource *prsc = &rsc->base; 310 struct pipe_resource *ptiled = NULL; 311 312 DBG("target=%d, format=%s, %ux%ux%u, array_size=%u, last_level=%u, " 313 "nr_samples=%u, usage=%u, bind=%x, flags=%x", 314 tmpl->target, util_format_name(tmpl->format), tmpl->width0, 315 tmpl->height0, tmpl->depth0, tmpl->array_size, tmpl->last_level, 316 tmpl->nr_samples, tmpl->usage, tmpl->bind, tmpl->flags); 317 318 if (!rsc) 319 return NULL; 320 321 *prsc = *tmpl; 322 323 pipe_reference_init(&prsc->reference, 1); 324 list_inithead(&rsc->list); 325 prsc->screen = pscreen; 326 327 rsc->bo = etna_screen_bo_from_handle(pscreen, handle, &level->stride); 328 if (!rsc->bo) 329 goto fail; 330 331 level->width = tmpl->width0; 332 level->height = tmpl->height0; 333 334 /* We will be using the RS to copy with this resource, so we must 335 * ensure that it is appropriately aligned for the RS requirements. */ 336 unsigned paddingX = ETNA_RS_WIDTH_MASK + 1; 337 unsigned paddingY = (ETNA_RS_HEIGHT_MASK + 1) * screen->specs.pixel_pipes; 338 339 level->padded_width = align(level->width, paddingX); 340 level->padded_height = align(level->height, paddingY); 341 342 /* The DDX must give us a BO which conforms to our padding size. 343 * The stride of the BO must be greater or equal to our padded 344 * stride. The size of the BO must accomodate the padded height. */ 345 if (level->stride < util_format_get_stride(tmpl->format, level->padded_width)) { 346 BUG("BO stride is too small for RS engine width padding"); 347 goto fail; 348 } 349 if (etna_bo_size(rsc->bo) < level->stride * level->padded_height) { 350 BUG("BO size is too small for RS engine height padding"); 351 goto fail; 352 } 353 354 if (handle->type == DRM_API_HANDLE_TYPE_SHARED && tmpl->bind & PIPE_BIND_RENDER_TARGET) { 355 /* Render targets are linear in Xorg but must be tiled 356 * here. It would be nice if dri_drawable_get_format() 357 * set scanout for these buffers too. */ 358 struct etna_resource *tiled; 359 360 ptiled = etna_resource_create(pscreen, tmpl); 361 if (!ptiled) 362 goto fail; 363 364 tiled = etna_resource(ptiled); 365 tiled->scanout = renderonly_scanout_for_prime(prsc, screen->ro); 366 if (!tiled->scanout) 367 goto fail; 368 369 return ptiled; 370 } 371 372 return prsc; 373 374 fail: 375 etna_resource_destroy(pscreen, prsc); 376 if (ptiled) 377 etna_resource_destroy(pscreen, ptiled); 378 379 return NULL; 380 } 381 382 static boolean 383 etna_resource_get_handle(struct pipe_screen *pscreen, 384 struct pipe_context *pctx, 385 struct pipe_resource *prsc, 386 struct winsys_handle *handle, unsigned usage) 387 { 388 struct etna_resource *rsc = etna_resource(prsc); 389 390 if (renderonly_get_handle(rsc->scanout, handle)) 391 return TRUE; 392 393 return etna_screen_bo_get_handle(pscreen, rsc->bo, rsc->levels[0].stride, 394 handle); 395 } 396 397 void 398 etna_resource_used(struct etna_context *ctx, struct pipe_resource *prsc, 399 enum etna_resource_status status) 400 { 401 struct etna_resource *rsc; 402 403 if (!prsc) 404 return; 405 406 rsc = etna_resource(prsc); 407 rsc->status |= status; 408 409 /* TODO resources can actually be shared across contexts, 410 * so I'm not sure a single list-head will do the trick? */ 411 debug_assert((rsc->pending_ctx == ctx) || !rsc->pending_ctx); 412 list_delinit(&rsc->list); 413 list_addtail(&rsc->list, &ctx->used_resources); 414 rsc->pending_ctx = ctx; 415 } 416 417 void 418 etna_resource_wait(struct pipe_context *pctx, struct etna_resource *rsc) 419 { 420 if (rsc->status & ETNA_PENDING_WRITE) { 421 struct pipe_fence_handle *fence; 422 struct pipe_screen *pscreen = pctx->screen; 423 424 pctx->flush(pctx, &fence, 0); 425 426 if (!pscreen->fence_finish(pscreen, pctx, fence, 5000000000ULL)) 427 BUG("fence timed out (hung GPU?)"); 428 429 pscreen->fence_reference(pscreen, &fence, NULL); 430 } 431 } 432 433 void 434 etna_resource_screen_init(struct pipe_screen *pscreen) 435 { 436 pscreen->can_create_resource = etna_screen_can_create_resource; 437 pscreen->resource_create = etna_resource_create; 438 pscreen->resource_from_handle = etna_resource_from_handle; 439 pscreen->resource_get_handle = etna_resource_get_handle; 440 pscreen->resource_destroy = etna_resource_destroy; 441 } 442