1/* 2 * Copyright 2010 Red Hat Inc. 3 * Copyright © 2014-2017 Broadcom 4 * Copyright (C) 2019-2020 Collabora, Ltd. 5 * Copyright 2006 VMware, Inc. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * on the rights to use, copy, modify, merge, publish, distribute, sub 11 * license, and/or sell copies of the Software, and to permit persons to whom 12 * the Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the next 15 * paragraph) shall be included in all copies or substantial portions of the 16 * Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 21 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24 * USE OR OTHER DEALINGS IN THE SOFTWARE. 25 */ 26#include <stdio.h> 27#include <errno.h> 28#include "pipe/p_defines.h" 29#include "pipe/p_state.h" 30#include "pipe/p_context.h" 31#include "pipe/p_screen.h" 32#include "util/u_memory.h" 33#include "util/u_screen.h" 34#include "util/u_inlines.h" 35#include "util/format/u_format.h" 36#include "util/u_upload_mgr.h" 37#include "util/half_float.h" 38#include "frontend/winsys_handle.h" 39#include "frontend/sw_winsys.h" 40#include "gallium/auxiliary/util/u_transfer.h" 41#include "gallium/auxiliary/util/u_transfer_helper.h" 42#include "gallium/auxiliary/util/u_surface.h" 43#include "gallium/auxiliary/util/u_framebuffer.h" 44#include "agx_public.h" 45#include "agx_state.h" 46#include "magic.h" 47#include "asahi/compiler/agx_compile.h" 48#include "asahi/lib/decode.h" 49#include "asahi/lib/tiling.h" 50#include "asahi/lib/agx_formats.h" 51 52static const struct debug_named_value agx_debug_options[] = { 53 {"trace", AGX_DBG_TRACE, "Trace the command stream"}, 54 {"deqp", AGX_DBG_DEQP, "Hacks for dEQP"}, 55 {"no16", AGX_DBG_NO16, "Disable 16-bit support"}, 56 DEBUG_NAMED_VALUE_END 57}; 58 59void agx_init_state_functions(struct pipe_context *ctx); 60 61static struct pipe_query * 62agx_create_query(struct pipe_context *ctx, unsigned query_type, unsigned index) 63{ 64 struct agx_query *query = CALLOC_STRUCT(agx_query); 65 66 return (struct pipe_query *)query; 67} 68 69static void 70agx_destroy_query(struct pipe_context *ctx, struct pipe_query *query) 71{ 72 FREE(query); 73} 74 75static bool 76agx_begin_query(struct pipe_context *ctx, struct pipe_query *query) 77{ 78 return true; 79} 80 81static bool 82agx_end_query(struct pipe_context *ctx, struct pipe_query *query) 83{ 84 return true; 85} 86 87static bool 88agx_get_query_result(struct pipe_context *ctx, 89 struct pipe_query *query, 90 bool wait, 91 union pipe_query_result *vresult) 92{ 93 uint64_t *result = (uint64_t*)vresult; 94 95 *result = 0; 96 return true; 97} 98 99static void 100agx_set_active_query_state(struct pipe_context *pipe, bool enable) 101{ 102} 103 104 105/* 106 * resource 107 */ 108 109static struct pipe_resource * 110agx_resource_from_handle(struct pipe_screen *pscreen, 111 const struct pipe_resource *templat, 112 struct winsys_handle *whandle, 113 unsigned usage) 114{ 115 unreachable("Imports todo"); 116} 117 118static bool 119agx_resource_get_handle(struct pipe_screen *pscreen, 120 struct pipe_context *ctx, 121 struct pipe_resource *pt, 122 struct winsys_handle *handle, 123 unsigned usage) 124{ 125 unreachable("Handles todo"); 126} 127 128/* Linear textures require specifying their strides explicitly, which only 129 * works for 2D textures. Rectangle textures are a special case of 2D. 130 */ 131static bool 132agx_is_2d(enum pipe_texture_target target) 133{ 134 return (target == PIPE_TEXTURE_2D || target == PIPE_TEXTURE_RECT); 135} 136 137static uint64_t 138agx_select_modifier(const struct agx_resource *pres) 139{ 140 /* Buffers are always linear */ 141 if (pres->base.target == PIPE_BUFFER) 142 return DRM_FORMAT_MOD_LINEAR; 143 144 /* Optimize streaming textures */ 145 if (pres->base.usage == PIPE_USAGE_STREAM && agx_is_2d(pres->base.target)) 146 return DRM_FORMAT_MOD_LINEAR; 147 148 /* Default to tiled */ 149 return DRM_FORMAT_MOD_APPLE_64X64_MORTON_ORDER; 150} 151 152static struct pipe_resource * 153agx_resource_create(struct pipe_screen *screen, 154 const struct pipe_resource *templ) 155{ 156 struct agx_device *dev = agx_device(screen); 157 struct agx_resource *nresource; 158 159 nresource = CALLOC_STRUCT(agx_resource); 160 if (!nresource) 161 return NULL; 162 163 nresource->base = *templ; 164 nresource->base.screen = screen; 165 166 nresource->modifier = agx_select_modifier(nresource); 167 nresource->mipmapped = (templ->last_level > 0); 168 nresource->internal_format = nresource->base.format; 169 170 unsigned offset = 0; 171 unsigned blocksize = util_format_get_blocksize(templ->format); 172 173 for (unsigned l = 0; l <= templ->last_level; ++l) { 174 unsigned width = u_minify(templ->width0, l); 175 unsigned height = u_minify(templ->height0, l); 176 177 if (nresource->modifier == DRM_FORMAT_MOD_APPLE_64X64_MORTON_ORDER) { 178 unsigned tile = agx_select_tile_size(templ->width0, templ->height0, l, blocksize); 179 180 width = ALIGN_POT(width, tile); 181 height = ALIGN_POT(height, tile); 182 } 183 184 /* Align stride to presumed cache line */ 185 nresource->slices[l].line_stride = util_format_get_stride(templ->format, width); 186 if (nresource->modifier == DRM_FORMAT_MOD_LINEAR) { 187 nresource->slices[l].line_stride = ALIGN_POT(nresource->slices[l].line_stride, 64); 188 } 189 190 nresource->slices[l].offset = offset; 191 nresource->slices[l].size = ALIGN_POT(nresource->slices[l].line_stride * height, 0x80); 192 193 offset += nresource->slices[l].size; 194 } 195 196 /* Arrays and cubemaps have the entire miptree duplicated and page aligned (16K) */ 197 nresource->array_stride = ALIGN_POT(offset, 0x4000); 198 unsigned size = nresource->array_stride * templ->array_size * templ->depth0; 199 200 pipe_reference_init(&nresource->base.reference, 1); 201 202 struct sw_winsys *winsys = ((struct agx_screen *) screen)->winsys; 203 204 if (templ->bind & (PIPE_BIND_DISPLAY_TARGET | 205 PIPE_BIND_SCANOUT | 206 PIPE_BIND_SHARED)) { 207 unsigned width0 = templ->width0, height0 = templ->height0; 208 209 if (nresource->modifier == DRM_FORMAT_MOD_APPLE_64X64_MORTON_ORDER) { 210 width0 = ALIGN_POT(width0, 64); 211 height0 = ALIGN_POT(height0, 64); 212 } 213 214 nresource->dt = winsys->displaytarget_create(winsys, 215 templ->bind, 216 templ->format, 217 width0, 218 height0, 219 64, 220 NULL /*map_front_private*/, 221 &nresource->dt_stride); 222 223 nresource->slices[0].line_stride = nresource->dt_stride; 224 assert((nresource->dt_stride & 0xF) == 0); 225 226 offset = nresource->slices[0].line_stride * ALIGN_POT(templ->height0, 64); 227 228 if (nresource->dt == NULL) { 229 FREE(nresource); 230 return NULL; 231 } 232 } 233 234 nresource->bo = agx_bo_create(dev, size, AGX_MEMORY_TYPE_FRAMEBUFFER); 235 236 if (!nresource->bo) { 237 FREE(nresource); 238 return NULL; 239 } 240 241 return &nresource->base; 242} 243 244static void 245agx_resource_destroy(struct pipe_screen *screen, 246 struct pipe_resource *prsrc) 247{ 248 struct agx_resource *rsrc = (struct agx_resource *)prsrc; 249 250 if (rsrc->dt) { 251 /* display target */ 252 struct agx_screen *agx_screen = (struct agx_screen*)screen; 253 struct sw_winsys *winsys = agx_screen->winsys; 254 winsys->displaytarget_destroy(winsys, rsrc->dt); 255 } 256 257 agx_bo_unreference(rsrc->bo); 258 FREE(rsrc); 259} 260 261 262/* 263 * transfer 264 */ 265 266static void 267agx_transfer_flush_region(struct pipe_context *pipe, 268 struct pipe_transfer *transfer, 269 const struct pipe_box *box) 270{ 271} 272 273static void * 274agx_transfer_map(struct pipe_context *pctx, 275 struct pipe_resource *resource, 276 unsigned level, 277 unsigned usage, /* a combination of PIPE_MAP_x */ 278 const struct pipe_box *box, 279 struct pipe_transfer **out_transfer) 280{ 281 struct agx_context *ctx = agx_context(pctx); 282 struct agx_resource *rsrc = agx_resource(resource); 283 unsigned blocksize = util_format_get_blocksize(resource->format); 284 285 /* Can't map tiled/compressed directly */ 286 if ((usage & PIPE_MAP_DIRECTLY) && rsrc->modifier != DRM_FORMAT_MOD_LINEAR) 287 return NULL; 288 289 if (ctx->batch->cbufs[0] && resource == ctx->batch->cbufs[0]->texture) 290 pctx->flush(pctx, NULL, 0); 291 if (ctx->batch->zsbuf && resource == ctx->batch->zsbuf->texture) 292 pctx->flush(pctx, NULL, 0); 293 294 struct agx_transfer *transfer = CALLOC_STRUCT(agx_transfer); 295 transfer->base.level = level; 296 transfer->base.usage = usage; 297 transfer->base.box = *box; 298 299 pipe_resource_reference(&transfer->base.resource, resource); 300 *out_transfer = &transfer->base; 301 302 if (rsrc->modifier == DRM_FORMAT_MOD_APPLE_64X64_MORTON_ORDER) { 303 transfer->base.stride = box->width * blocksize; 304 transfer->base.layer_stride = transfer->base.stride * box->height; 305 transfer->map = calloc(transfer->base.layer_stride, box->depth); 306 307 if ((usage & PIPE_MAP_READ) && BITSET_TEST(rsrc->data_valid, level)) { 308 for (unsigned z = 0; z < box->depth; ++z) { 309 uint8_t *map = agx_map_texture_cpu(rsrc, level, box->z + z); 310 uint8_t *dst = (uint8_t *) transfer->map + 311 transfer->base.layer_stride * z; 312 313 agx_detile(map, dst, 314 u_minify(resource->width0, level), blocksize * 8, 315 transfer->base.stride / blocksize, 316 box->x, box->y, box->x + box->width, box->y + box->height, 317 agx_select_tile_shift(resource->width0, resource->height0, level, blocksize)); 318 } 319 } 320 321 return transfer->map; 322 } else { 323 assert (rsrc->modifier == DRM_FORMAT_MOD_LINEAR); 324 325 transfer->base.stride = rsrc->slices[level].line_stride; 326 transfer->base.layer_stride = rsrc->array_stride; 327 328 /* Be conservative for direct writes */ 329 330 if ((usage & PIPE_MAP_WRITE) && (usage & PIPE_MAP_DIRECTLY)) 331 BITSET_SET(rsrc->data_valid, level); 332 333 return (uint8_t *) agx_map_texture_cpu(rsrc, level, box->z) 334 + transfer->base.box.y * rsrc->slices[level].line_stride 335 + transfer->base.box.x * blocksize; 336 } 337} 338 339static void 340agx_transfer_unmap(struct pipe_context *pctx, 341 struct pipe_transfer *transfer) 342{ 343 /* Gallium expects writeback here, so we tile */ 344 345 struct agx_transfer *trans = agx_transfer(transfer); 346 struct pipe_resource *prsrc = transfer->resource; 347 struct agx_resource *rsrc = (struct agx_resource *) prsrc; 348 unsigned blocksize = util_format_get_blocksize(prsrc->format); 349 350 if (transfer->usage & PIPE_MAP_WRITE) 351 BITSET_SET(rsrc->data_valid, transfer->level); 352 353 /* Tiling will occur in software from a staging cpu buffer */ 354 if ((transfer->usage & PIPE_MAP_WRITE) && 355 rsrc->modifier == DRM_FORMAT_MOD_APPLE_64X64_MORTON_ORDER) { 356 assert(trans->map != NULL); 357 358 for (unsigned z = 0; z < transfer->box.depth; ++z) { 359 uint8_t *map = agx_map_texture_cpu(rsrc, transfer->level, 360 transfer->box.z + z); 361 uint8_t *src = (uint8_t *) trans->map + 362 transfer->layer_stride * z; 363 364 agx_tile(map, src, 365 u_minify(transfer->resource->width0, transfer->level), 366 blocksize * 8, 367 transfer->stride / blocksize, 368 transfer->box.x, transfer->box.y, 369 transfer->box.x + transfer->box.width, 370 transfer->box.y + transfer->box.height, 371 agx_select_tile_shift(transfer->resource->width0, 372 transfer->resource->height0, 373 transfer->level, blocksize)); 374 } 375 } 376 377 /* Free the transfer */ 378 free(trans->map); 379 pipe_resource_reference(&transfer->resource, NULL); 380 FREE(transfer); 381} 382 383/* 384 * clear/copy 385 */ 386static void 387agx_clear(struct pipe_context *pctx, unsigned buffers, const struct pipe_scissor_state *scissor_state, 388 const union pipe_color_union *color, double depth, unsigned stencil) 389{ 390 struct agx_context *ctx = agx_context(pctx); 391 392 /* TODO: support partial clears */ 393 if (ctx->batch->clear | ctx->batch->draw) 394 pctx->flush(pctx, NULL, 0); 395 396 ctx->batch->clear |= buffers; 397 398 if (buffers & PIPE_CLEAR_COLOR0) 399 memcpy(ctx->batch->clear_color, color->f, sizeof(color->f)); 400 401 if (buffers & PIPE_CLEAR_DEPTH) 402 ctx->batch->clear_depth = depth; 403 404 if (buffers & PIPE_CLEAR_STENCIL) 405 ctx->batch->clear_stencil = stencil; 406} 407 408 409static void 410agx_flush_resource(struct pipe_context *ctx, 411 struct pipe_resource *resource) 412{ 413} 414 415/* 416 * context 417 */ 418static void 419agx_flush(struct pipe_context *pctx, 420 struct pipe_fence_handle **fence, 421 unsigned flags) 422{ 423 struct agx_context *ctx = agx_context(pctx); 424 425 if (fence) 426 *fence = NULL; 427 428 /* Nothing to do */ 429 if (!(ctx->batch->draw | ctx->batch->clear)) 430 return; 431 432 /* Finalize the encoder */ 433 uint8_t stop[5 + 64] = { 0x00, 0x00, 0x00, 0xc0, 0x00 }; 434 memcpy(ctx->batch->encoder_current, stop, sizeof(stop)); 435 436 /* Emit the commandbuffer */ 437 uint64_t pipeline_clear = 0, pipeline_reload = 0; 438 bool clear_pipeline_textures = false; 439 440 struct agx_device *dev = agx_device(pctx->screen); 441 442 uint16_t clear_colour[4] = { 443 _mesa_float_to_half(ctx->batch->clear_color[0]), 444 _mesa_float_to_half(ctx->batch->clear_color[1]), 445 _mesa_float_to_half(ctx->batch->clear_color[2]), 446 _mesa_float_to_half(ctx->batch->clear_color[3]) 447 }; 448 449 pipeline_clear = agx_build_clear_pipeline(ctx, 450 dev->internal.clear, 451 agx_pool_upload(&ctx->batch->pool, clear_colour, sizeof(clear_colour))); 452 453 if (ctx->batch->cbufs[0]) { 454 enum pipe_format fmt = ctx->batch->cbufs[0]->format; 455 enum agx_format internal = agx_pixel_format[fmt].internal; 456 uint32_t shader = dev->reload.format[internal]; 457 458 pipeline_reload = agx_build_reload_pipeline(ctx, shader, 459 ctx->batch->cbufs[0]); 460 } 461 462 if (ctx->batch->cbufs[0] && !(ctx->batch->clear & PIPE_CLEAR_COLOR0)) { 463 clear_pipeline_textures = true; 464 pipeline_clear = pipeline_reload; 465 } 466 467 uint64_t pipeline_store = 0; 468 469 if (ctx->batch->cbufs[0]) { 470 pipeline_store = 471 agx_build_store_pipeline(ctx, 472 dev->internal.store, 473 agx_pool_upload(&ctx->batch->pool, ctx->render_target[0], sizeof(ctx->render_target))); 474 } 475 476 /* Pipelines must 64 aligned */ 477 for (unsigned i = 0; i < ctx->batch->nr_cbufs; ++i) { 478 struct agx_resource *rt = agx_resource(ctx->batch->cbufs[i]->texture); 479 BITSET_SET(rt->data_valid, 0); 480 } 481 482 struct agx_resource *zbuf = ctx->batch->zsbuf ? 483 agx_resource(ctx->batch->zsbuf->texture) : NULL; 484 485 if (zbuf) { 486 BITSET_SET(zbuf->data_valid, 0); 487 488 if (zbuf->separate_stencil) 489 BITSET_SET(zbuf->separate_stencil->data_valid, 0); 490 } 491 492 /* BO list for a given batch consists of: 493 * - BOs for the batch's framebuffer surfaces 494 * - BOs for the batch's pools 495 * - BOs for the encoder 496 * - BO for internal shaders 497 * - BOs added to the batch explicitly 498 */ 499 struct agx_batch *batch = ctx->batch; 500 501 agx_batch_add_bo(batch, batch->encoder); 502 agx_batch_add_bo(batch, batch->scissor.bo); 503 agx_batch_add_bo(batch, batch->depth_bias.bo); 504 agx_batch_add_bo(batch, dev->internal.bo); 505 agx_batch_add_bo(batch, dev->reload.bo); 506 507 for (unsigned i = 0; i < batch->nr_cbufs; ++i) { 508 struct pipe_surface *surf = batch->cbufs[i]; 509 assert(surf != NULL && surf->texture != NULL); 510 struct agx_resource *rsrc = agx_resource(surf->texture); 511 agx_batch_add_bo(batch, rsrc->bo); 512 } 513 514 if (batch->zsbuf) { 515 struct pipe_surface *surf = batch->zsbuf; 516 struct agx_resource *rsrc = agx_resource(surf->texture); 517 agx_batch_add_bo(batch, rsrc->bo); 518 519 if (rsrc->separate_stencil) 520 agx_batch_add_bo(batch, rsrc->separate_stencil->bo); 521 } 522 523 unsigned handle_count = 524 BITSET_COUNT(batch->bo_list) + 525 agx_pool_num_bos(&batch->pool) + 526 agx_pool_num_bos(&batch->pipeline_pool); 527 528 uint32_t *handles = calloc(sizeof(uint32_t), handle_count); 529 unsigned handle = 0, handle_i = 0; 530 531 BITSET_FOREACH_SET(handle, batch->bo_list, sizeof(batch->bo_list) * 8) { 532 handles[handle_i++] = handle; 533 } 534 535 agx_pool_get_bo_handles(&batch->pool, handles + handle_i); 536 handle_i += agx_pool_num_bos(&batch->pool); 537 538 agx_pool_get_bo_handles(&batch->pipeline_pool, handles + handle_i); 539 handle_i += agx_pool_num_bos(&batch->pipeline_pool); 540 541 /* Size calculation should've been exact */ 542 assert(handle_i == handle_count); 543 544 unsigned cmdbuf_id = agx_get_global_id(dev); 545 unsigned encoder_id = agx_get_global_id(dev); 546 547 unsigned cmdbuf_size = demo_cmdbuf(dev->cmdbuf.ptr.cpu, 548 dev->cmdbuf.size, 549 &ctx->batch->pool, 550 &ctx->framebuffer, 551 ctx->batch->encoder->ptr.gpu, 552 encoder_id, 553 ctx->batch->scissor.bo->ptr.gpu, 554 ctx->batch->depth_bias.bo->ptr.gpu, 555 pipeline_clear, 556 pipeline_reload, 557 pipeline_store, 558 clear_pipeline_textures, 559 ctx->batch->clear_depth, 560 ctx->batch->clear_stencil); 561 562 /* Generate the mapping table from the BO list */ 563 demo_mem_map(dev->memmap.ptr.cpu, dev->memmap.size, handles, handle_count, 564 cmdbuf_id, encoder_id, cmdbuf_size); 565 566 free(handles); 567 568 agx_submit_cmdbuf(dev, dev->cmdbuf.handle, dev->memmap.handle, dev->queue.id); 569 570 agx_wait_queue(dev->queue); 571 572 if (dev->debug & AGX_DBG_TRACE) { 573 agxdecode_cmdstream(dev->cmdbuf.handle, dev->memmap.handle, true); 574 agxdecode_next_frame(); 575 } 576 577 memset(batch->bo_list, 0, sizeof(batch->bo_list)); 578 agx_pool_cleanup(&ctx->batch->pool); 579 agx_pool_cleanup(&ctx->batch->pipeline_pool); 580 agx_pool_init(&ctx->batch->pool, dev, AGX_MEMORY_TYPE_FRAMEBUFFER, true); 581 agx_pool_init(&ctx->batch->pipeline_pool, dev, AGX_MEMORY_TYPE_CMDBUF_32, true); 582 ctx->batch->clear = 0; 583 ctx->batch->draw = 0; 584 ctx->batch->encoder_current = ctx->batch->encoder->ptr.cpu; 585 ctx->batch->scissor.count = 0; 586 ctx->dirty = ~0; 587} 588 589static void 590agx_destroy_context(struct pipe_context *pctx) 591{ 592 struct agx_context *ctx = agx_context(pctx); 593 594 if (pctx->stream_uploader) 595 u_upload_destroy(pctx->stream_uploader); 596 597 if (ctx->blitter) 598 util_blitter_destroy(ctx->blitter); 599 600 util_unreference_framebuffer_state(&ctx->framebuffer); 601 602 FREE(ctx); 603} 604 605static void 606agx_invalidate_resource(struct pipe_context *ctx, 607 struct pipe_resource *resource) 608{ 609} 610 611static struct pipe_context * 612agx_create_context(struct pipe_screen *screen, 613 void *priv, unsigned flags) 614{ 615 struct agx_context *ctx = CALLOC_STRUCT(agx_context); 616 struct pipe_context *pctx = &ctx->base; 617 618 if (!ctx) 619 return NULL; 620 621 pctx->screen = screen; 622 pctx->priv = priv; 623 624 ctx->batch = CALLOC_STRUCT(agx_batch); 625 agx_pool_init(&ctx->batch->pool, 626 agx_device(screen), AGX_MEMORY_TYPE_FRAMEBUFFER, true); 627 agx_pool_init(&ctx->batch->pipeline_pool, 628 agx_device(screen), AGX_MEMORY_TYPE_SHADER, true); 629 ctx->batch->encoder = agx_bo_create(agx_device(screen), 0x80000, AGX_MEMORY_TYPE_FRAMEBUFFER); 630 ctx->batch->encoder_current = ctx->batch->encoder->ptr.cpu; 631 ctx->batch->scissor.bo = agx_bo_create(agx_device(screen), 0x80000, AGX_MEMORY_TYPE_FRAMEBUFFER); 632 ctx->batch->depth_bias.bo = agx_bo_create(agx_device(screen), 0x80000, AGX_MEMORY_TYPE_FRAMEBUFFER); 633 634 /* Upload fixed shaders (TODO: compile them?) */ 635 636 pctx->stream_uploader = u_upload_create_default(pctx); 637 if (!pctx->stream_uploader) { 638 FREE(pctx); 639 return NULL; 640 } 641 pctx->const_uploader = pctx->stream_uploader; 642 643 pctx->destroy = agx_destroy_context; 644 pctx->flush = agx_flush; 645 pctx->clear = agx_clear; 646 pctx->resource_copy_region = util_resource_copy_region; 647 pctx->blit = agx_blit; 648 pctx->flush_resource = agx_flush_resource; 649 pctx->create_query = agx_create_query; 650 pctx->destroy_query = agx_destroy_query; 651 pctx->begin_query = agx_begin_query; 652 pctx->end_query = agx_end_query; 653 pctx->get_query_result = agx_get_query_result; 654 pctx->set_active_query_state = agx_set_active_query_state; 655 656 pctx->buffer_map = u_transfer_helper_transfer_map; 657 pctx->buffer_unmap = u_transfer_helper_transfer_unmap; 658 pctx->texture_map = u_transfer_helper_transfer_map; 659 pctx->texture_unmap = u_transfer_helper_transfer_unmap; 660 pctx->transfer_flush_region = u_transfer_helper_transfer_flush_region; 661 662 pctx->buffer_subdata = u_default_buffer_subdata; 663 pctx->texture_subdata = u_default_texture_subdata; 664 pctx->invalidate_resource = agx_invalidate_resource; 665 agx_init_state_functions(pctx); 666 667 668 ctx->blitter = util_blitter_create(pctx); 669 670 return pctx; 671} 672 673static void 674agx_flush_frontbuffer(struct pipe_screen *_screen, 675 struct pipe_context *pctx, 676 struct pipe_resource *prsrc, 677 unsigned level, unsigned layer, 678 void *context_private, struct pipe_box *box) 679{ 680 struct agx_resource *rsrc = (struct agx_resource *) prsrc; 681 struct agx_screen *agx_screen = (struct agx_screen*)_screen; 682 struct sw_winsys *winsys = agx_screen->winsys; 683 684 /* Dump the framebuffer */ 685 assert (rsrc->dt); 686 void *map = winsys->displaytarget_map(winsys, rsrc->dt, PIPE_USAGE_DEFAULT); 687 assert(map != NULL); 688 689 if (rsrc->modifier == DRM_FORMAT_MOD_APPLE_64X64_MORTON_ORDER) { 690 agx_detile(rsrc->bo->ptr.cpu, map, 691 rsrc->base.width0, 32, rsrc->dt_stride / 4, 692 0, 0, rsrc->base.width0, rsrc->base.height0, 6); 693 } else { 694 memcpy(map, rsrc->bo->ptr.cpu, rsrc->dt_stride * rsrc->base.height0); 695 } 696 697 winsys->displaytarget_display(winsys, rsrc->dt, context_private, box); 698} 699 700static const char * 701agx_get_vendor(struct pipe_screen* pscreen) 702{ 703 return "Asahi"; 704} 705 706static const char * 707agx_get_device_vendor(struct pipe_screen* pscreen) 708{ 709 return "Apple"; 710} 711 712static const char * 713agx_get_name(struct pipe_screen* pscreen) 714{ 715 return "Apple M1 (G13G B0)"; 716} 717 718static int 719agx_get_param(struct pipe_screen* pscreen, enum pipe_cap param) 720{ 721 bool is_deqp = agx_device(pscreen)->debug & AGX_DBG_DEQP; 722 723 switch (param) { 724 case PIPE_CAP_NPOT_TEXTURES: 725 case PIPE_CAP_MIXED_COLOR_DEPTH_BITS: 726 case PIPE_CAP_FRAGMENT_SHADER_TEXTURE_LOD: 727 case PIPE_CAP_VERTEX_COLOR_UNCLAMPED: 728 case PIPE_CAP_DEPTH_CLIP_DISABLE: 729 case PIPE_CAP_MIXED_COLORBUFFER_FORMATS: 730 case PIPE_CAP_MIXED_FRAMEBUFFER_SIZES: 731 case PIPE_CAP_FRAGMENT_SHADER_DERIVATIVES: 732 case PIPE_CAP_FRAMEBUFFER_NO_ATTACHMENT: 733 case PIPE_CAP_CLIP_HALFZ: 734 return 1; 735 736 case PIPE_CAP_MAX_RENDER_TARGETS: 737 return 1; 738 739 case PIPE_CAP_MAX_DUAL_SOURCE_RENDER_TARGETS: 740 return 0; 741 742 case PIPE_CAP_OCCLUSION_QUERY: 743 case PIPE_CAP_PRIMITIVE_RESTART: 744 case PIPE_CAP_PRIMITIVE_RESTART_FIXED_INDEX: 745 return true; 746 747 case PIPE_CAP_SAMPLER_VIEW_TARGET: 748 case PIPE_CAP_TEXTURE_SWIZZLE: 749 case PIPE_CAP_BLEND_EQUATION_SEPARATE: 750 case PIPE_CAP_INDEP_BLEND_ENABLE: 751 case PIPE_CAP_INDEP_BLEND_FUNC: 752 case PIPE_CAP_ACCELERATED: 753 case PIPE_CAP_UMA: 754 case PIPE_CAP_TEXTURE_FLOAT_LINEAR: 755 case PIPE_CAP_TEXTURE_HALF_FLOAT_LINEAR: 756 case PIPE_CAP_SHADER_ARRAY_COMPONENTS: 757 case PIPE_CAP_CS_DERIVED_SYSTEM_VALUES_SUPPORTED: 758 case PIPE_CAP_PACKED_UNIFORMS: 759 return 1; 760 761 case PIPE_CAP_VS_INSTANCEID: 762 case PIPE_CAP_VERTEX_ELEMENT_INSTANCE_DIVISOR: 763 case PIPE_CAP_TEXTURE_MULTISAMPLE: 764 case PIPE_CAP_SURFACE_SAMPLE_COUNT: 765 case PIPE_CAP_SAMPLE_SHADING: 766 return is_deqp; 767 768 case PIPE_CAP_COPY_BETWEEN_COMPRESSED_AND_PLAIN_FORMATS: 769 return 0; 770 771 case PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS: 772 return is_deqp ? PIPE_MAX_SO_BUFFERS : 0; 773 774 case PIPE_CAP_MAX_STREAM_OUTPUT_SEPARATE_COMPONENTS: 775 case PIPE_CAP_MAX_STREAM_OUTPUT_INTERLEAVED_COMPONENTS: 776 return is_deqp ? PIPE_MAX_SO_OUTPUTS : 0; 777 778 case PIPE_CAP_STREAM_OUTPUT_PAUSE_RESUME: 779 case PIPE_CAP_STREAM_OUTPUT_INTERLEAVE_BUFFERS: 780 return is_deqp ? 1 : 0; 781 782 case PIPE_CAP_MAX_TEXTURE_ARRAY_LAYERS: 783 return 256; 784 785 case PIPE_CAP_GLSL_FEATURE_LEVEL: 786 case PIPE_CAP_GLSL_FEATURE_LEVEL_COMPATIBILITY: 787 return is_deqp ? 330 : 130; 788 case PIPE_CAP_ESSL_FEATURE_LEVEL: 789 return is_deqp ? 320 : 120; 790 791 case PIPE_CAP_CONSTANT_BUFFER_OFFSET_ALIGNMENT: 792 return 16; 793 794 case PIPE_CAP_MAX_TEXEL_BUFFER_ELEMENTS_UINT: 795 return 65536; 796 797 case PIPE_CAP_TEXTURE_BUFFER_OFFSET_ALIGNMENT: 798 return 64; 799 800 case PIPE_CAP_VERTEX_BUFFER_STRIDE_4BYTE_ALIGNED_ONLY: 801 return 1; 802 803 case PIPE_CAP_MAX_TEXTURE_2D_SIZE: 804 return 16384; 805 case PIPE_CAP_MAX_TEXTURE_3D_LEVELS: 806 case PIPE_CAP_MAX_TEXTURE_CUBE_LEVELS: 807 return 13; 808 809 case PIPE_CAP_FS_COORD_ORIGIN_LOWER_LEFT: 810 return 0; 811 812 case PIPE_CAP_FS_COORD_ORIGIN_UPPER_LEFT: 813 case PIPE_CAP_FS_COORD_PIXEL_CENTER_HALF_INTEGER: 814 case PIPE_CAP_FS_COORD_PIXEL_CENTER_INTEGER: 815 case PIPE_CAP_TGSI_TEXCOORD: 816 case PIPE_CAP_FS_FACE_IS_INTEGER_SYSVAL: 817 case PIPE_CAP_FS_POSITION_IS_SYSVAL: 818 case PIPE_CAP_SEAMLESS_CUBE_MAP: 819 case PIPE_CAP_SEAMLESS_CUBE_MAP_PER_TEXTURE: 820 return true; 821 case PIPE_CAP_POINT_COORD_ORIGIN_UPPER_LEFT: 822 case PIPE_CAP_FS_POINT_IS_SYSVAL: 823 return false; 824 825 case PIPE_CAP_MAX_VERTEX_ELEMENT_SRC_OFFSET: 826 return 0xffff; 827 828 case PIPE_CAP_TEXTURE_TRANSFER_MODES: 829 return 0; 830 831 case PIPE_CAP_ENDIANNESS: 832 return PIPE_ENDIAN_LITTLE; 833 834 case PIPE_CAP_VIDEO_MEMORY: { 835 uint64_t system_memory; 836 837 if (!os_get_total_physical_memory(&system_memory)) 838 return 0; 839 840 return (int)(system_memory >> 20); 841 } 842 843 case PIPE_CAP_SHADER_BUFFER_OFFSET_ALIGNMENT: 844 return 4; 845 846 case PIPE_CAP_MAX_VARYINGS: 847 return 16; 848 849 case PIPE_CAP_FLATSHADE: 850 case PIPE_CAP_TWO_SIDED_COLOR: 851 case PIPE_CAP_ALPHA_TEST: 852 case PIPE_CAP_CLIP_PLANES: 853 case PIPE_CAP_NIR_IMAGES_AS_DEREF: 854 return 0; 855 856 case PIPE_CAP_SHAREABLE_SHADERS: 857 return 1; 858 859 default: 860 return u_pipe_screen_get_param_defaults(pscreen, param); 861 } 862} 863 864static float 865agx_get_paramf(struct pipe_screen* pscreen, 866 enum pipe_capf param) 867{ 868 switch (param) { 869 case PIPE_CAPF_MIN_LINE_WIDTH: 870 case PIPE_CAPF_MIN_LINE_WIDTH_AA: 871 case PIPE_CAPF_MIN_POINT_SIZE: 872 case PIPE_CAPF_MIN_POINT_SIZE_AA: 873 return 1; 874 875 case PIPE_CAPF_POINT_SIZE_GRANULARITY: 876 case PIPE_CAPF_LINE_WIDTH_GRANULARITY: 877 return 0.1; 878 879 case PIPE_CAPF_MAX_LINE_WIDTH: 880 case PIPE_CAPF_MAX_LINE_WIDTH_AA: 881 return 16.0; /* Off-by-one fixed point 4:4 encoding */ 882 883 case PIPE_CAPF_MAX_POINT_SIZE: 884 case PIPE_CAPF_MAX_POINT_SIZE_AA: 885 return 511.95f; 886 887 case PIPE_CAPF_MAX_TEXTURE_ANISOTROPY: 888 return 16.0; 889 890 case PIPE_CAPF_MAX_TEXTURE_LOD_BIAS: 891 return 16.0; /* arbitrary */ 892 893 case PIPE_CAPF_MIN_CONSERVATIVE_RASTER_DILATE: 894 case PIPE_CAPF_MAX_CONSERVATIVE_RASTER_DILATE: 895 case PIPE_CAPF_CONSERVATIVE_RASTER_DILATE_GRANULARITY: 896 return 0.0f; 897 898 default: 899 debug_printf("Unexpected PIPE_CAPF %d query\n", param); 900 return 0.0; 901 } 902} 903 904static int 905agx_get_shader_param(struct pipe_screen* pscreen, 906 enum pipe_shader_type shader, 907 enum pipe_shader_cap param) 908{ 909 bool is_deqp = agx_device(pscreen)->debug & AGX_DBG_DEQP; 910 bool is_no16 = agx_device(pscreen)->debug & AGX_DBG_NO16; 911 912 if (shader != PIPE_SHADER_VERTEX && 913 shader != PIPE_SHADER_FRAGMENT) 914 return 0; 915 916 /* this is probably not totally correct.. but it's a start: */ 917 switch (param) { 918 case PIPE_SHADER_CAP_MAX_INSTRUCTIONS: 919 case PIPE_SHADER_CAP_MAX_ALU_INSTRUCTIONS: 920 case PIPE_SHADER_CAP_MAX_TEX_INSTRUCTIONS: 921 case PIPE_SHADER_CAP_MAX_TEX_INDIRECTIONS: 922 return 16384; 923 924 case PIPE_SHADER_CAP_MAX_CONTROL_FLOW_DEPTH: 925 return 1024; 926 927 case PIPE_SHADER_CAP_MAX_INPUTS: 928 return 16; 929 930 case PIPE_SHADER_CAP_MAX_OUTPUTS: 931 return shader == PIPE_SHADER_FRAGMENT ? 4 : 16; 932 933 case PIPE_SHADER_CAP_MAX_TEMPS: 934 return 256; /* GL_MAX_PROGRAM_TEMPORARIES_ARB */ 935 936 case PIPE_SHADER_CAP_MAX_CONST_BUFFER0_SIZE: 937 return 16 * 1024 * sizeof(float); 938 939 case PIPE_SHADER_CAP_MAX_CONST_BUFFERS: 940 return 16; 941 942 case PIPE_SHADER_CAP_CONT_SUPPORTED: 943 return 0; 944 945 case PIPE_SHADER_CAP_INDIRECT_INPUT_ADDR: 946 case PIPE_SHADER_CAP_INDIRECT_OUTPUT_ADDR: 947 case PIPE_SHADER_CAP_INDIRECT_TEMP_ADDR: 948 case PIPE_SHADER_CAP_SUBROUTINES: 949 case PIPE_SHADER_CAP_TGSI_SQRT_SUPPORTED: 950 return 0; 951 952 case PIPE_SHADER_CAP_INDIRECT_CONST_ADDR: 953 return is_deqp; 954 955 case PIPE_SHADER_CAP_INTEGERS: 956 return true; 957 958 case PIPE_SHADER_CAP_FP16: 959 case PIPE_SHADER_CAP_GLSL_16BIT_CONSTS: 960 case PIPE_SHADER_CAP_FP16_DERIVATIVES: 961 case PIPE_SHADER_CAP_FP16_CONST_BUFFERS: 962 return !is_no16; 963 case PIPE_SHADER_CAP_INT16: 964 /* GLSL compiler is broken. Flip this on when Panfrost does. */ 965 return false; 966 967 case PIPE_SHADER_CAP_INT64_ATOMICS: 968 case PIPE_SHADER_CAP_DROUND_SUPPORTED: 969 case PIPE_SHADER_CAP_DFRACEXP_DLDEXP_SUPPORTED: 970 case PIPE_SHADER_CAP_LDEXP_SUPPORTED: 971 case PIPE_SHADER_CAP_TGSI_ANY_INOUT_DECL_RANGE: 972 return 0; 973 974 case PIPE_SHADER_CAP_MAX_TEXTURE_SAMPLERS: 975 case PIPE_SHADER_CAP_MAX_SAMPLER_VIEWS: 976 return 16; /* XXX: How many? */ 977 978 case PIPE_SHADER_CAP_PREFERRED_IR: 979 return PIPE_SHADER_IR_NIR; 980 981 case PIPE_SHADER_CAP_SUPPORTED_IRS: 982 return (1 << PIPE_SHADER_IR_NIR) | (1 << PIPE_SHADER_IR_NIR_SERIALIZED); 983 984 case PIPE_SHADER_CAP_MAX_SHADER_BUFFERS: 985 case PIPE_SHADER_CAP_MAX_SHADER_IMAGES: 986 case PIPE_SHADER_CAP_MAX_HW_ATOMIC_COUNTERS: 987 case PIPE_SHADER_CAP_MAX_HW_ATOMIC_COUNTER_BUFFERS: 988 return 0; 989 990 default: 991 /* Other params are unknown */ 992 return 0; 993 } 994 995 return 0; 996} 997 998static int 999agx_get_compute_param(struct pipe_screen *pscreen, 1000 enum pipe_shader_ir ir_type, 1001 enum pipe_compute_cap param, 1002 void *ret) 1003{ 1004 return 0; 1005} 1006 1007static bool 1008agx_is_format_supported(struct pipe_screen* pscreen, 1009 enum pipe_format format, 1010 enum pipe_texture_target target, 1011 unsigned sample_count, 1012 unsigned storage_sample_count, 1013 unsigned usage) 1014{ 1015 assert(target == PIPE_BUFFER || 1016 target == PIPE_TEXTURE_1D || 1017 target == PIPE_TEXTURE_1D_ARRAY || 1018 target == PIPE_TEXTURE_2D || 1019 target == PIPE_TEXTURE_2D_ARRAY || 1020 target == PIPE_TEXTURE_RECT || 1021 target == PIPE_TEXTURE_3D || 1022 target == PIPE_TEXTURE_CUBE || 1023 target == PIPE_TEXTURE_CUBE_ARRAY); 1024 1025 if (sample_count > 1) 1026 return false; 1027 1028 if (MAX2(sample_count, 1) != MAX2(storage_sample_count, 1)) 1029 return false; 1030 1031 if (usage & (PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW)) { 1032 struct agx_pixel_format_entry ent = agx_pixel_format[format]; 1033 1034 if (!agx_is_valid_pixel_format(format)) 1035 return false; 1036 1037 if ((usage & PIPE_BIND_RENDER_TARGET) && !ent.renderable) 1038 return false; 1039 } 1040 1041 /* TODO: formats */ 1042 if (usage & PIPE_BIND_VERTEX_BUFFER) { 1043 switch (format) { 1044 case PIPE_FORMAT_R16_FLOAT: 1045 case PIPE_FORMAT_R16G16_FLOAT: 1046 case PIPE_FORMAT_R16G16B16_FLOAT: 1047 case PIPE_FORMAT_R16G16B16A16_FLOAT: 1048 case PIPE_FORMAT_R32_FLOAT: 1049 case PIPE_FORMAT_R32G32_FLOAT: 1050 case PIPE_FORMAT_R32G32B32_FLOAT: 1051 case PIPE_FORMAT_R32G32B32A32_FLOAT: 1052 return true; 1053 default: 1054 return false; 1055 } 1056 } 1057 1058 if (usage & PIPE_BIND_DEPTH_STENCIL) { 1059 switch (format) { 1060 /* natively supported 1061 * TODO: we could also support Z16_UNORM */ 1062 case PIPE_FORMAT_Z32_FLOAT: 1063 case PIPE_FORMAT_S8_UINT: 1064 1065 /* lowered by u_transfer_helper to one of the above */ 1066 case PIPE_FORMAT_Z24X8_UNORM: 1067 case PIPE_FORMAT_Z24_UNORM_S8_UINT: 1068 case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: 1069 return true; 1070 1071 default: 1072 return false; 1073 } 1074 } 1075 1076 /* TODO */ 1077 return true; 1078} 1079 1080static uint64_t 1081agx_get_timestamp(struct pipe_screen *pscreen) 1082{ 1083 return 0; 1084} 1085 1086static void 1087agx_destroy_screen(struct pipe_screen *screen) 1088{ 1089 u_transfer_helper_destroy(screen->transfer_helper); 1090 agx_close_device(agx_device(screen)); 1091 ralloc_free(screen); 1092} 1093 1094static void 1095agx_fence_reference(struct pipe_screen *screen, 1096 struct pipe_fence_handle **ptr, 1097 struct pipe_fence_handle *fence) 1098{ 1099} 1100 1101static bool 1102agx_fence_finish(struct pipe_screen *screen, 1103 struct pipe_context *ctx, 1104 struct pipe_fence_handle *fence, 1105 uint64_t timeout) 1106{ 1107 return true; 1108} 1109 1110static const void * 1111agx_get_compiler_options(struct pipe_screen *pscreen, 1112 enum pipe_shader_ir ir, 1113 enum pipe_shader_type shader) 1114{ 1115 return &agx_nir_options; 1116} 1117 1118static void 1119agx_resource_set_stencil(struct pipe_resource *prsrc, 1120 struct pipe_resource *stencil) 1121{ 1122 agx_resource(prsrc)->separate_stencil = agx_resource(stencil); 1123} 1124 1125static struct pipe_resource * 1126agx_resource_get_stencil(struct pipe_resource *prsrc) 1127{ 1128 return (struct pipe_resource *) agx_resource(prsrc)->separate_stencil; 1129} 1130 1131static enum pipe_format 1132agx_resource_get_internal_format(struct pipe_resource *prsrc) 1133{ 1134 return agx_resource(prsrc)->internal_format; 1135} 1136 1137static const struct u_transfer_vtbl transfer_vtbl = { 1138 .resource_create = agx_resource_create, 1139 .resource_destroy = agx_resource_destroy, 1140 .transfer_map = agx_transfer_map, 1141 .transfer_unmap = agx_transfer_unmap, 1142 .transfer_flush_region = agx_transfer_flush_region, 1143 .get_internal_format = agx_resource_get_internal_format, 1144 .set_stencil = agx_resource_set_stencil, 1145 .get_stencil = agx_resource_get_stencil, 1146}; 1147 1148struct pipe_screen * 1149agx_screen_create(struct sw_winsys *winsys) 1150{ 1151 struct agx_screen *agx_screen; 1152 struct pipe_screen *screen; 1153 1154 agx_screen = rzalloc(NULL, struct agx_screen); 1155 if (!agx_screen) 1156 return NULL; 1157 1158 screen = &agx_screen->pscreen; 1159 agx_screen->winsys = winsys; 1160 1161 /* Set debug before opening */ 1162 agx_screen->dev.debug = 1163 debug_get_flags_option("ASAHI_MESA_DEBUG", agx_debug_options, 0); 1164 1165 /* Try to open an AGX device */ 1166 if (!agx_open_device(screen, &agx_screen->dev)) { 1167 ralloc_free(agx_screen); 1168 return NULL; 1169 } 1170 1171 if (agx_screen->dev.debug & AGX_DBG_DEQP) { 1172 /* You're on your own. */ 1173 static bool warned_about_hacks = false; 1174 1175 if (!warned_about_hacks) { 1176 fprintf(stderr, "\n------------------\n" 1177 "Unsupported debug parameter set. Expect breakage.\n" 1178 "Do not report bugs.\n" 1179 "------------------\n\n"); 1180 warned_about_hacks = true; 1181 } 1182 } 1183 1184 screen->destroy = agx_destroy_screen; 1185 screen->get_name = agx_get_name; 1186 screen->get_vendor = agx_get_vendor; 1187 screen->get_device_vendor = agx_get_device_vendor; 1188 screen->get_param = agx_get_param; 1189 screen->get_shader_param = agx_get_shader_param; 1190 screen->get_compute_param = agx_get_compute_param; 1191 screen->get_paramf = agx_get_paramf; 1192 screen->is_format_supported = agx_is_format_supported; 1193 screen->context_create = agx_create_context; 1194 screen->resource_from_handle = agx_resource_from_handle; 1195 screen->resource_get_handle = agx_resource_get_handle; 1196 screen->flush_frontbuffer = agx_flush_frontbuffer; 1197 screen->get_timestamp = agx_get_timestamp; 1198 screen->fence_reference = agx_fence_reference; 1199 screen->fence_finish = agx_fence_finish; 1200 screen->get_compiler_options = agx_get_compiler_options; 1201 1202 screen->resource_create = u_transfer_helper_resource_create; 1203 screen->resource_destroy = u_transfer_helper_resource_destroy; 1204 screen->transfer_helper = u_transfer_helper_create(&transfer_vtbl, 1205 true, true, false, true, 1206 true); 1207 1208 agx_internal_shaders(&agx_screen->dev); 1209 1210 return screen; 1211} 1212