/* * Copyright 2012 Red Hat Inc. * * 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 #include #include #include #include #include #include "replayx.h" #include "xf86drm.h" #include "radeon_drm.h" #include "radeon_family.h" int ctx_bo(struct ctx *ctx, struct ctx_bo *bo, void *data) { struct drm_radeon_gem_create args; int r; args.size = bo->size; args.alignment = bo->alignment; args.initial_domain = RADEON_GEM_DOMAIN_CPU; args.flags = bo->flags; args.handle = 0; r = drmCommandWriteRead(ctx->fd, DRM_RADEON_GEM_CREATE, &args, sizeof(args)); bo->handle = args.handle; if (r) { fprintf(stderr, "Failed to allocate :\n"); fprintf(stderr, " size : %d bytes\n", bo->size); fprintf(stderr, " alignment : %d bytes\n", bo->alignment); } if (data) { r = ctx_bo_map(ctx, bo); if (r) { return r; } memcpy(bo->data, data, bo->size); } return r; } int ctx_bo_map(struct ctx *ctx, struct ctx_bo *bo) { struct drm_radeon_gem_mmap args; void *ptr; int r; if (bo->mapcount++ != 0) { return 0; } /* Zero out args to make valgrind happy */ memset(&args, 0, sizeof(args)); args.handle = bo->handle; args.offset = 0; args.size = (uint64_t)bo->size; r = drmCommandWriteRead(ctx->fd, DRM_RADEON_GEM_MMAP, &args, sizeof(args)); if (r) { fprintf(stderr, "error mapping %p 0x%08X (error = %d)\n", bo, bo->handle, r); return r; } ptr = mmap(0, args.size, PROT_READ|PROT_WRITE, MAP_SHARED, ctx->fd, args.addr_ptr); if (ptr == MAP_FAILED) { fprintf(stderr, "%s failed to map bo\n", __func__); return -errno; } bo->data = ptr; return 0; } void ctx_bo_unmap(struct ctx_bo *bo) { if (--bo->mapcount > 0) { return; } munmap(bo->data, bo->size); bo->data = NULL; } void ctx_bo_free(struct ctx *ctx, struct ctx_bo *bo) { struct drm_gem_close args; if (bo == NULL) { return; } if (bo->data) { munmap(bo->data, bo->size); } memset(&args, 0, sizeof(args)); args.handle = bo->handle; drmIoctl(ctx->fd, DRM_IOCTL_GEM_CLOSE, &args); memset(bo, 0, sizeof(struct ctx_bo)); } int ctx_bo_wait(struct ctx *ctx, struct ctx_bo *bo) { struct drm_radeon_gem_wait_idle args; int ret; /* Zero out args to make valgrind happy */ memset(&args, 0, sizeof(args)); args.handle = bo->handle; do { ret = drmCommandWriteRead(ctx->fd, DRM_RADEON_GEM_WAIT_IDLE, &args, sizeof(args)); } while (ret == -EBUSY); return ret; } int ctx_rati_load(struct ctx *ctx, const char *filename) { unsigned i; int r; r = rati_file_read(&ctx->rfile, filename); if (r) { fprintf(stderr, "failed reading %s\n", filename); return r; } ctx->ntarget = 0; ctx->nbos = ctx->rfile.header.ndata_buffers; ctx->bos = calloc(1, sizeof(*ctx->bos) * ctx->nbos); ctx->relocs = calloc(1, sizeof(*ctx->relocs) * ctx->nbos); ctx->target = calloc(1, sizeof(void*) * ctx->nbos); if (ctx->bos == NULL || ctx->relocs == NULL || ctx->target == NULL) { free(ctx->bos); free(ctx->relocs); return -ENOMEM; } for (i = 0; i < ctx->nbos; ++i) { ctx->bos[i].size = ctx->rfile.data_buffer[i].size; ctx->bos[i].alignment = ctx->rfile.data_buffer[i].alignment; r = ctx_bo(ctx, &ctx->bos[i], ctx->rfile.data_buffer_ptr[i]); if (r) { return r; } ctx->relocs[i].handle = ctx->bos[i].handle; ctx->relocs[i].read_domain = RADEON_GEM_DOMAIN_VRAM | RADEON_GEM_DOMAIN_GTT; ctx->relocs[i].write_domain = RADEON_GEM_DOMAIN_VRAM | RADEON_GEM_DOMAIN_GTT; ctx->relocs[i].flags = 0; } return 0; } int ctx_cs(struct ctx *ctx, void *cs, unsigned ndw, void *relocs, unsigned nrelocs) { struct drm_radeon_cs drmib; struct drm_radeon_cs_chunk chunks[2]; uint64_t chunk_array[2]; int r; drmib.num_chunks = 2; drmib.chunks = (uint64_t)(uintptr_t)chunk_array; chunks[0].chunk_id = RADEON_CHUNK_ID_IB; chunks[0].length_dw = ndw; chunks[0].chunk_data = (uintptr_t)cs; chunks[1].chunk_id = RADEON_CHUNK_ID_RELOCS; chunks[1].length_dw = nrelocs * 4; chunks[1].chunk_data = (uintptr_t)relocs; chunk_array[0] = (uintptr_t)&chunks[0]; chunk_array[1] = (uintptr_t)&chunks[1]; #if 1 r = drmCommandWriteRead(ctx->fd, DRM_RADEON_CS, &drmib, sizeof(struct drm_radeon_cs)); #endif return r; } int ctx_cs_rati(struct ctx *ctx) { return ctx_cs(ctx, ctx->rfile.cmd_buffer_ptr[0], ctx->rfile.cmd_buffer[0].ndw, ctx->relocs, ctx->nbos); } static int ctx_get_drm_value(struct ctx *ctx, unsigned request, uint32_t *out) { struct drm_radeon_info info; memset(&info, 0, sizeof(info)); info.value = (unsigned long)out; info.request = request; return drmCommandWriteRead(ctx->fd, DRM_RADEON_INFO, &info, sizeof(info)); } int ctx_drv_init(struct ctx *ctx) { const struct radeon_chipinfo *chipinfo; int r; r = ctx_get_drm_value(ctx, RADEON_INFO_DEVICE_ID, &ctx->pciid); if (r) { return r; } ctx->pciid |= 0x10020000; chipinfo = radeon_chipinfo_from_pciid(ctx->pciid); if (chipinfo == NULL) { fprintf(stderr, "%s unknown gpu 0x%08x\n", __func__, ctx->pciid); return -EINVAL; } ctx->family = chipinfo->family; switch (ctx->family) { case CHIP_R600: case CHIP_RV610: case CHIP_RV630: case CHIP_RV670: case CHIP_RV620: case CHIP_RV635: case CHIP_RS780: case CHIP_RS880: ctx->drv = _r6xx_drv; break; case CHIP_RV770: case CHIP_RV730: case CHIP_RV710: case CHIP_RV740: case CHIP_R100: case CHIP_RV100: case CHIP_RS100: case CHIP_RV200: case CHIP_RS200: case CHIP_R200: case CHIP_RV250: case CHIP_RS300: case CHIP_RV280: case CHIP_R300: case CHIP_R350: case CHIP_RV350: case CHIP_RV380: case CHIP_R420: case CHIP_R423: case CHIP_RV410: case CHIP_RS400: case CHIP_RS480: case CHIP_RS600: case CHIP_RS690: case CHIP_RS740: case CHIP_RV515: case CHIP_R520: case CHIP_RV530: case CHIP_RV560: case CHIP_RV570: case CHIP_R580: case CHIP_CEDAR: case CHIP_REDWOOD: case CHIP_JUNIPER: case CHIP_CYPRESS: case CHIP_HEMLOCK: case CHIP_PALM: case CHIP_SUMO: case CHIP_SUMO2: case CHIP_BARTS: case CHIP_TURKS: case CHIP_CAICOS: case CHIP_CAYMAN: case CHIP_ARUBA: case CHIP_TAHITI: case CHIP_PITCAIRN: case CHIP_VERDE: default: fprintf(stderr, "%s unsupported gpu %s 0x%08x\n", __func__, chipinfo->name, ctx->pciid); return -EINVAL; } r = ctx->drv.compatible(ctx); if (r) { return r; } return ctx->drv.blit_init(ctx); } void ctx_drv_fini(struct ctx *ctx) { ctx->drv.blit_fini(ctx); }