/* * Copyright 2009 Advanced Micro Devices, Inc. * 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: * Alex Deucher * Jerome Glisse */ #include #include #include #include #include "replayx.h" #include "xf86drm.h" #include "radeon_drm.h" #include "radeon_family.h" #include "r6xx.h" #include "r6xxd.h" static int r6xx_blit_init(struct ctx *ctx) { struct r6xx_blit *blit = &ctx->blit.r6xx; int r; blit->ctx = ctx; blit->vs_offset = 512; blit->ps_offset = 1024; blit->vbo_offset = 0; r = r6xx_sq_conf(blit); if (r) { return r; } blit->cdw = 0; blit->cs = malloc(16 << 10); if (blit->cs == NULL) { return -ENOMEM; } blit->ctx = ctx; blit->shader_bo.size = 4096; blit->shader_bo.alignment = 4096; blit->shader_bo.flags = 0; r = ctx_bo(ctx, &blit->shader_bo, NULL); if (r) { return r; } r = ctx_bo_map(ctx, &blit->shader_bo); if (r) { return r; } blit->vs_size = r6xx_copy_vs(blit->shader_bo.data + blit->vs_offset); blit->ps_size = r6xx_copy_ps(blit->shader_bo.data + blit->ps_offset); blit->relocs[0].handle = 0; blit->relocs[0].read_domain = 0; blit->relocs[0].write_domain = RADEON_GEM_DOMAIN_VRAM | RADEON_GEM_DOMAIN_GTT; blit->relocs[0].flags = 0; blit->relocs[1].handle = blit->shader_bo.handle; blit->relocs[1].read_domain = RADEON_GEM_DOMAIN_VRAM | RADEON_GEM_DOMAIN_GTT; blit->relocs[1].write_domain = 0; blit->relocs[1].flags = 0; blit->relocs[2].handle = 0; blit->relocs[2].read_domain = RADEON_GEM_DOMAIN_VRAM | RADEON_GEM_DOMAIN_GTT; blit->relocs[2].write_domain = 0; blit->relocs[2].flags = 0; return 0; } static void r6xx_blit_fini(struct ctx *ctx) { struct r6xx_blit *blit = &ctx->blit.r6xx; ctx_bo_free(blit->ctx, &blit->shader_bo); } static int r6xx_blit(struct ctx *ctx, struct ctx_bo *bo) { struct r6xx_blit *blit = &ctx->blit.r6xx; unsigned x0, y0, x1, y1; float *vtx; struct r6xx_vbo vbo; struct r6xx_draw draw; ctx->front.hw_format = COLOR_8_8_8_8; ctx->front.hw_tile = ARRAY_1D_TILED_THIN1; blit->relocs[0].handle = ctx->front.handle; blit->relocs[2].handle = bo->handle; blit->cdw = 0; blit->ctx = ctx; r6xx_set_default_state(blit); r6xx_disable_depth(blit); r6xx_set_render_target(blit, &ctx->front); /* vbo */ vbo.bo = &blit->shader_bo; vbo.offset = blit->vbo_offset; vbo.stride = 4 * 4; vbo.num_format_all = SQ_NUM_FORMAT_NORM; vbo.data_format = FMT_32_32_32_32_FLOAT; vbo.srf_mode_all = 0; vbo.format_comp_all = 0; vbo.endian_swap = SQ_ENDIAN_NONE; vbo.ndw = 4 * 4; vbo.mem_request_size = 1; vtx = blit->shader_bo.data + blit->vbo_offset; x0 = 0; y0 = 0; x1 = bo->w; y1 = bo->h; vtx[ 0] = x0; vtx[ 1] = y0; vtx[ 2] = 0.0; vtx[ 3] = 0.0; vtx[ 4] = x0; vtx[ 5] = y1; vtx[ 6] = 0.0; vtx[ 7] = bo->h; vtx[ 8] = x1; vtx[ 9] = y1; vtx[10] = bo->w; vtx[11] = bo->h; r6xx_fs_setup(blit, &blit->shader_bo, blit->vs_offset, 0, 0); r6xx_vs_setup(blit, &blit->shader_bo, blit->vs_offset, 2, 0, 0); r6xx_ps_setup(blit, &blit->shader_bo, blit->ps_offset, 1, 0, 2, 1); r6xx_set_tex_resource(blit, 0, bo); r6xx_set_default_sampler(blit, 0); r6xx_set_vtx_resource(blit, 160, &vbo); r6xx_surface_sync(blit, NULL, CP_COHER_CNTL__SH_ACTION_ENA(1) | CP_COHER_CNTL__TC_ACTION_ENA(1) | CP_COHER_CNTL__VC_ACTION_ENA(1)); draw.primitive_type = DI_PT_RECTLIST; draw.num_indices = 3; draw.num_instances = 1; draw.index_type = DI_INDEX_SIZE_16_BIT; draw.vgt_draw_initiator = VGT_DRAW_INITIATOR__SOURCE_SELECT(DI_SRC_SEL_AUTO_INDEX); r6xx_draw_auto(blit, &draw); r6xx_event(blit, VGT_EVENT_INITIATOR__EVENT_TYPE(CACHE_FLUSH_AND_INV_EVENT)); return ctx_cs(ctx, blit->cs, blit->cdw, blit->relocs, 3); } struct r6xx_target { unsigned w; unsigned h; unsigned hw_format; unsigned hw_tile; unsigned pitch; int reloc_id; }; static int r6xx_next_reloc_id(uint32_t *pm4, unsigned *next_idx, int *reloc_id) { unsigned type, it, count; type = PKTx_TYPE(pm4[*next_idx]); count = PKTx_COUNT(pm4[*next_idx]); it = PKT3_IT(pm4[*next_idx]); if (type != 3 || it != IT_NOP) { /* missing relocation */ return -EINVAL; } *reloc_id = pm4[(*next_idx) + 1] / 4; *next_idx += count + 1; return 0; } static int r6xx_reg_target(uint32_t *pm4, unsigned reg, unsigned value, struct r6xx_target *target, unsigned *next_idx) { unsigned idx; int r; switch (reg) { case CB_COLOR0_BASE: case CB_COLOR1_BASE: case CB_COLOR2_BASE: case CB_COLOR3_BASE: case CB_COLOR4_BASE: case CB_COLOR5_BASE: case CB_COLOR6_BASE: case CB_COLOR7_BASE: idx = (reg - CB_COLOR0_BASE) / 4; r = r6xx_next_reloc_id(pm4, next_idx, &target[idx].reloc_id); if (r) { return r; } break; case CB_COLOR0_INFO: case CB_COLOR1_INFO: case CB_COLOR2_INFO: case CB_COLOR3_INFO: case CB_COLOR4_INFO: case CB_COLOR5_INFO: case CB_COLOR6_INFO: case CB_COLOR7_INFO: idx = (reg - CB_COLOR0_INFO) / 4; target[idx].hw_format = (value >> 2) & 0x3f; target[idx].hw_tile = (value >> 8) & 0xf; break; case CB_COLOR0_SIZE: case CB_COLOR1_SIZE: case CB_COLOR2_SIZE: case CB_COLOR3_SIZE: case CB_COLOR4_SIZE: case CB_COLOR5_SIZE: case CB_COLOR6_SIZE: case CB_COLOR7_SIZE: idx = (reg - CB_COLOR0_SIZE) / 4; target[idx].pitch = (((value >> 0) & 0x3ff) + 1) * 8; target[idx].w = target[idx].pitch; target[idx].h = (((value >> 10) & 0x000fffff) + 1) * 64; target[idx].h = target[idx].h / target[idx].pitch; break; default: break; } return 0; } static int r6xx_cmd_buffer_target(struct ctx *ctx, unsigned idx) { uint32_t *pm4 = ctx->rfile.cmd_buffer_ptr[idx]; unsigned i, j, header, count, next_idx, reg, it; struct r6xx_target target[8]; int r; for (i = 0; i < 8; i++) { target[i].reloc_id = -1; } ctx->ntarget = 0; ctx->ctarget = 0; for (i = 0; i < ctx->rfile.cmd_buffer[idx].ndw;) { header = pm4[i]; count = PKTx_COUNT(header); switch (PKTx_TYPE(header)) { case 0: reg = PKT0_REG(header); next_idx = i + count + 1; for (j = 0, i++; j < count; j++, reg += 4, i++) { r = r6xx_reg_target(pm4, reg, pm4[i], target, &next_idx); if (r) { return r; } } break; case 1: case 2: break; case 3: next_idx = i + count + 1; it = PKT3_IT(pm4[i]); switch (it) { case IT_SET_CONFIG_REG: reg = (pm4[++i] << 2) + SET_CONFIG_REG__OFFSET; for (j = 0, i++; j < (count - 1); j++, reg += 4, i++) { r = r6xx_reg_target(pm4, reg, pm4[i], target, &next_idx); if (r) { return r; } } break; case IT_SET_CONTEXT_REG: reg = (pm4[++i] << 2) + SET_CONTEXT_REG__OFFSET; for (j = 0, i++; j < (count - 1); j++, reg += 4, i++) { r = r6xx_reg_target(pm4, reg, pm4[i], target, &next_idx); if (r) { return r; } } break; case IT_DRAW_INDEX: case IT_DRAW_INDEX_AUTO: case IT_DRAW_INDEX_IMMD: for (i = 0; i < 8; i++) { if (target[i].reloc_id != 1 && target[i].reloc_id < ctx->rfile.header.ndata_buffers) { ctx->target[ctx->ntarget] = &ctx->bos[target[i].reloc_id]; ctx->target[ctx->ntarget]->w = target[i].w; ctx->target[ctx->ntarget]->h = target[i].h; ctx->target[ctx->ntarget]->pitch = target[i].pitch; ctx->target[ctx->ntarget]->hw_format = target[i].hw_format; ctx->target[ctx->ntarget]->hw_tile = target[i].hw_tile; ctx->ntarget++; } target[i].reloc_id = -1; } break; default: break; } } i = next_idx; } return 0; } static int r6xx_target(struct ctx *ctx) { unsigned i; int r; for (i = 0; i < ctx->rfile.header.ncmd_buffers; i++) { r = r6xx_cmd_buffer_target(ctx, i); if (r) { return r; } } return 0; } static int r6xx_compatible(struct ctx *ctx) { const struct radeon_chipinfo *info; unsigned family; unsigned i; int r; /* check we can replay */ info = radeon_chipinfo_from_pciid(ctx->rfile.header.pciid); if (info == NULL) { fprintf(stderr, "%s unknown gpu pci id 0x%08x\n", __func__, ctx->rfile.header.pciid); return -EINVAL; } family = info->family; if (family < CHIP_R600 || family > CHIP_RS880) { fprintf(stderr, "%s can't replay 0x%02x trace on 0x%02x hw\n", __func__, family, ctx->family); return -EINVAL; } /* set front format & tile */ ctx->front.hw_format = COLOR_8_8_8_8; ctx->front.hw_tile = ARRAY_1D_TILED_THIN1; for (i = 0; i < ctx->nbos; i++) { printf("bo[%d] %dkb\n", i, ctx->bos[i].size >> 10); } r = r6xx_rfile_clear_offset(&ctx->rfile); if (r) { return r; } return r6xx_target(ctx); } const struct ctx_drv _r6xx_drv = { r6xx_compatible, r6xx_blit_init, r6xx_blit_fini, r6xx_blit, };