/* * Copyright 2010 Jerome Glisse * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * on the rights to use, copy, modify, merge, publish, distribute, sub * license, and/or sell copies of the Software, and to permit persons to whom * the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. * * Authors: * Jerome Glisse */ #define _FILE_OFFSET_BITS 64 #include #include #include #include #include "xf86drm.h" #include "radeon.h" #include "radeon_bo.h" #include "radeon_drm.h" #include "bof.h" #pragma pack(1) struct radeon_cs_reloc { uint32_t handle; uint32_t read_domain; uint32_t write_domain; uint32_t flags; }; #pragma pack() struct ctx_bo { struct radeon_bo *bo; unsigned handle; }; struct ctx { struct radeon radeon; const char **argv; int argc; uint32_t *cs; uint32_t cs_ndw; struct ctx_bo *bos; unsigned nbos; int fd; struct radeon_cs_reloc *relocs; }; #define PKT_TYPE_G(x) (((x) >> 30) & 0x3) #define PKT_COUNT_G(x) (((x) >> 16) & 0x3FFF) void ctx_read_bof(struct ctx *ctx) { bof_t *bof, *tmp; bof = bof_load_file(ctx->argv[1]); if (!bof) { fprintf(stderr, "%s failed to load %s\n", ctx->argv[0], ctx->argv[1]); exit(-1); } tmp = bof_object_get(bof, "pm4"); if (tmp == NULL) { fprintf(stderr, "no pm4 in bof %s\n", ctx->argv[1]); exit(-1); } ctx->cs_ndw = bof_blob_size(tmp) / 4; ctx->cs = calloc(1, ctx->cs_ndw * 4); memcpy(ctx->cs, bof_blob_value(tmp), ctx->cs_ndw * 4); /* bo */ tmp = bof_object_get(bof, "bo"); if (tmp == NULL) { fprintf(stderr, "no bo in bof %s\n", ctx->argv[1]); exit(-1); } ctx->nbos = bof_array_size(tmp); ctx->bos = calloc(ctx->nbos, sizeof(struct ctx_bo)); ctx->relocs = calloc(ctx->nbos, sizeof(struct radeon_cs_reloc)); for (unsigned i = 0; i < ctx->nbos; i++) { bof_t *bo, *bo_size, *bo_handle; unsigned size; bo = bof_array_get(tmp, i); bo_size = bof_object_get(bo, "size"); if (bo_size == NULL) { fprintf(stderr, "invalid bo[%d] in bof %s\n", i, ctx->argv[1]); exit(-1); } size = bof_int32_value(bo_size); bo_handle = bof_object_get(bo, "handle"); if (bo_handle == NULL) { fprintf(stderr, "invalid bo[%d] in bof %s\n", i, ctx->argv[1]); exit(-1); } ctx->bos[i].handle = bof_int32_value(bo_handle); bo = bof_object_get(bo, "data"); ctx->bos[i].bo = radeon_bo(ctx->radeon.fd, 0, size, 4096, bof_blob_value(bo)); if (ctx->bos[i].bo == NULL) { fprintf(stderr, "failed to allocate bo[%d] from bof %s %d\n", i, ctx->argv[1], size); exit(-1); } ctx->relocs[i].handle = ctx->bos[i].bo->handle; ctx->relocs[i].read_domain = RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM; ctx->relocs[i].write_domain = RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM; ctx->relocs[i].flags = 0; } /* Update relocation packet. */ for (unsigned i = 0; i < ctx->cs_ndw;) { switch (PKT_TYPE_G(ctx->cs[i])) { case 3: if ((ctx->cs[i] & 0xffff) == 0x10) { for (unsigned j = 0; j < ctx->nbos; j++) { if (ctx->bos[j].handle == ctx->cs[i + 1]) { ctx->cs[i + 1] = ctx->bos[j].bo->handle; break; } } } i += PKT_COUNT_G(ctx->cs[i]) + 1; break; case 2: case 1: i++; break; default: i += PKT_COUNT_G(ctx->cs[i]) + 1; break; } } } int ctx_cs_submit(struct ctx *ctx) { struct drm_radeon_cs drmib; struct drm_radeon_cs_chunk chunks[2]; uint64_t chunk_array[2]; int r = 0; drmib.num_chunks = 2; drmib.chunks = (uint64_t)(uintptr_t)chunk_array; chunks[0].chunk_id = RADEON_CHUNK_ID_IB; chunks[0].length_dw = ctx->cs_ndw; chunks[0].chunk_data = (uintptr_t)ctx->cs; chunks[1].chunk_id = RADEON_CHUNK_ID_RELOCS; chunks[1].length_dw = ctx->nbos * 4; chunks[1].chunk_data = (uintptr_t)ctx->relocs; chunk_array[0] = (uintptr_t)&chunks[0]; chunk_array[1] = (uintptr_t)&chunks[1]; #if 1 r = drmCommandWriteRead(ctx->radeon.fd, DRM_RADEON_CS, &drmib, sizeof(struct drm_radeon_cs)); #endif return r; } void ctx_dump_bo(struct ctx *ctx, struct radeon_bo *bo, FILE *file) { uint32_t *ptr; radeon_bo_map(bo); ptr = bo->data; for (unsigned i = 0; i < (bo->size >> 2); ++i) { if (!(i % 7)) { fprintf(file, "\n"); } fprintf(file, " 0x%08x", ptr[i]); } fprintf(file, "\n"); radeon_bo_unmap(bo); } void ctx_dump_bos(struct ctx *ctx, FILE *file) { for (unsigned i = 0; i < ctx->nbos; i++) { fprintf(file, " bo[%4d](%8d)\n", i, ctx->bos[i].bo->size); ctx_dump_bo(ctx, ctx->bos[i].bo, file); } } int main(int argc, const char *argv[]) { FILE *file; struct ctx ctx; int r; ctx.argc = argc; ctx.argv = argv; if (radeon_init(&ctx.radeon)) { fprintf(stderr, "%s failed to init radeon\n", argv[0]); return -1; } ctx_read_bof(&ctx); file = fopen("B", "w"); fprintf(file, "BEFORE -----------------------------------------------------------------------\n"); ctx_dump_bos(&ctx, file); fclose(file); r = ctx_cs_submit(&ctx); for (unsigned i = 0; i < ctx.nbos; i++) { radeon_bo_wait(ctx.bos[i].bo); } printf("%s cs submit %s !\n", argv[0], r ? "failure" : "success"); file = fopen("A", "w"); fprintf(file, "AFTER ------------------------------------------------------------------------\n"); ctx_dump_bos(&ctx, file); fclose(file); return 0; }