/* This happens rather often with DTD9/st. */ void nvc0_cb_push(struct nouveau_context *nv, struct nouveau_bo *bo, unsigned domain, unsigned base, unsigned size, unsigned offset, unsigned words, const uint32_t *data) { struct nouveau_pushbuf *push = nv->pushbuf; NOUVEAU_DRV_STAT(nv->screen, constbuf_upload_count, 1); NOUVEAU_DRV_STAT(nv->screen, constbuf_upload_bytes, words * 4); assert(!(offset & 3)); size = align(size, 0x100); BEGIN_NVC0(push, NVC0_3D(CB_SIZE), 3); PUSH_DATA (push, size); PUSH_DATAh(push, bo->offset + base); PUSH_DATA (push, bo->offset + base); while (words) { unsigned nr = PUSH_AVAIL(push); nr = MIN2(nr, words); nr = MIN2(nr, NV04_PFIFO_MAX_PACKET_LEN - 1); PUSH_SPACE(push, nr + 2); PUSH_REFN (push, bo, NOUVEAU_BO_WR | domain); BEGIN_1IC0(push, NVC0_3D(CB_POS), nr + 1); PUSH_DATA (push, offset); PUSH_DATAp(push, data, nr); words -= nr; data += nr; offset += nr * 4; } }
static void nvc0_render_condition(struct pipe_context *pipe, struct pipe_query *pq, boolean condition, uint mode) { struct nvc0_context *nvc0 = nvc0_context(pipe); struct nouveau_pushbuf *push = nvc0->base.pushbuf; struct nvc0_query *q; uint32_t cond; boolean negated = FALSE; boolean wait = mode != PIPE_RENDER_COND_NO_WAIT && mode != PIPE_RENDER_COND_BY_REGION_NO_WAIT; nvc0->cond_query = pq; nvc0->cond_cond = condition; nvc0->cond_mode = mode; if (!pq) { PUSH_SPACE(push, 1); IMMED_NVC0(push, NVC0_3D(COND_MODE), NVC0_3D_COND_MODE_ALWAYS); return; } q = nvc0_query(pq); /* NOTE: comparison of 2 queries only works if both have completed */ switch (q->type) { case PIPE_QUERY_SO_OVERFLOW_PREDICATE: cond = negated ? NVC0_3D_COND_MODE_EQUAL : NVC0_3D_COND_MODE_NOT_EQUAL; wait = TRUE; break; case PIPE_QUERY_OCCLUSION_COUNTER: case PIPE_QUERY_OCCLUSION_PREDICATE: if (likely(!negated)) { if (unlikely(q->nesting)) cond = wait ? NVC0_3D_COND_MODE_NOT_EQUAL : NVC0_3D_COND_MODE_ALWAYS; else cond = NVC0_3D_COND_MODE_RES_NON_ZERO; } else { cond = wait ? NVC0_3D_COND_MODE_EQUAL : NVC0_3D_COND_MODE_ALWAYS; } break; default: assert(!"render condition query not a predicate"); mode = NVC0_3D_COND_MODE_ALWAYS; break; } if (wait) nvc0_query_fifo_wait(push, pq); PUSH_SPACE(push, 4); PUSH_REFN (push, q->bo, NOUVEAU_BO_GART | NOUVEAU_BO_RD); BEGIN_NVC0(push, NVC0_3D(COND_ADDRESS_HIGH), 3); PUSH_DATAh(push, q->bo->offset + q->offset); PUSH_DATA (push, q->bo->offset + q->offset); PUSH_DATA (push, cond); }
void nv50_query_pushbuf_submit(struct nouveau_pushbuf *push, struct pipe_query *pq, unsigned result_offset) { struct nv50_query *q = nv50_query(pq); /* XXX: does this exist ? */ #define NV50_IB_ENTRY_1_NO_PREFETCH (0 << (31 - 8)) PUSH_REFN(push, q->bo, NOUVEAU_BO_RD | NOUVEAU_BO_GART); nouveau_pushbuf_space(push, 0, 0, 1); nouveau_pushbuf_data(push, q->bo, q->offset + result_offset, 4 | NV50_IB_ENTRY_1_NO_PREFETCH); }
void nv84_query_fifo_wait(struct nouveau_pushbuf *push, struct pipe_query *pq) { struct nv50_query *q = nv50_query(pq); unsigned offset = q->offset; PUSH_SPACE(push, 5); PUSH_REFN (push, q->bo, NOUVEAU_BO_GART | NOUVEAU_BO_RD); BEGIN_NV04(push, SUBC_3D(NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH), 4); PUSH_DATAh(push, q->bo->offset + offset); PUSH_DATA (push, q->bo->offset + offset); PUSH_DATA (push, q->sequence); PUSH_DATA (push, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL); }
static void nv50_query_get(struct nouveau_pushbuf *push, struct nv50_query *q, unsigned offset, uint32_t get) { offset += q->offset; PUSH_SPACE(push, 5); PUSH_REFN (push, q->bo, NOUVEAU_BO_GART | NOUVEAU_BO_WR); BEGIN_NV04(push, NV50_3D(QUERY_ADDRESS_HIGH), 4); PUSH_DATAh(push, q->bo->offset + offset); PUSH_DATA (push, q->bo->offset + offset); PUSH_DATA (push, q->sequence); PUSH_DATA (push, get); }
static void nvc0_clear_render_target(struct pipe_context *pipe, struct pipe_surface *dst, const union pipe_color_union *color, unsigned dstx, unsigned dsty, unsigned width, unsigned height) { struct nvc0_context *nvc0 = nvc0_context(pipe); struct nouveau_pushbuf *push = nvc0->base.pushbuf; struct nv50_surface *sf = nv50_surface(dst); struct nv04_resource *res = nv04_resource(sf->base.texture); unsigned z; if (!PUSH_SPACE(push, 32 + sf->depth)) return; PUSH_REFN (push, res->bo, res->domain | NOUVEAU_BO_WR); BEGIN_NVC0(push, NVC0_3D(CLEAR_COLOR(0)), 4); PUSH_DATAf(push, color->f[0]); PUSH_DATAf(push, color->f[1]); PUSH_DATAf(push, color->f[2]); PUSH_DATAf(push, color->f[3]); BEGIN_NVC0(push, NVC0_3D(SCREEN_SCISSOR_HORIZ), 2); PUSH_DATA (push, ( width << 16) | dstx); PUSH_DATA (push, (height << 16) | dsty); BEGIN_NVC0(push, NVC0_3D(RT_CONTROL), 1); PUSH_DATA (push, 1); BEGIN_NVC0(push, NVC0_3D(RT_ADDRESS_HIGH(0)), 9); PUSH_DATAh(push, res->address + sf->offset); PUSH_DATA (push, res->address + sf->offset); if (likely(nouveau_bo_memtype(res->bo))) { struct nv50_miptree *mt = nv50_miptree(dst->texture); PUSH_DATA(push, sf->width); PUSH_DATA(push, sf->height); PUSH_DATA(push, nvc0_format_table[dst->format].rt); PUSH_DATA(push, (mt->layout_3d << 16) | mt->level[sf->base.u.tex.level].tile_mode); PUSH_DATA(push, dst->u.tex.first_layer + sf->depth); PUSH_DATA(push, mt->layer_stride >> 2); PUSH_DATA(push, dst->u.tex.first_layer); } else { if (res->base.target == PIPE_BUFFER) {
void nvc0_query_fifo_wait(struct nouveau_pushbuf *push, struct pipe_query *pq) { struct nvc0_query *q = nvc0_query(pq); unsigned offset = q->offset; if (q->type == PIPE_QUERY_SO_OVERFLOW_PREDICATE) offset += 0x20; PUSH_SPACE(push, 5); PUSH_REFN (push, q->bo, NOUVEAU_BO_GART | NOUVEAU_BO_RD); BEGIN_NVC0(push, SUBC_3D(NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH), 4); PUSH_DATAh(push, q->bo->offset + offset); PUSH_DATA (push, q->bo->offset + offset); PUSH_DATA (push, q->sequence); PUSH_DATA (push, (1 << 12) | NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL); }
static void nv50_render_condition(struct pipe_context *pipe, struct pipe_query *pq, boolean condition, uint mode) { struct nv50_context *nv50 = nv50_context(pipe); struct nouveau_pushbuf *push = nv50->base.pushbuf; struct nv50_query *q; uint32_t cond; boolean wait = mode != PIPE_RENDER_COND_NO_WAIT && mode != PIPE_RENDER_COND_BY_REGION_NO_WAIT; if (!pq) { cond = NV50_3D_COND_MODE_ALWAYS; } else { q = nv50_query(pq); /* NOTE: comparison of 2 queries only works if both have completed */ switch (q->type) { case PIPE_QUERY_SO_OVERFLOW_PREDICATE: cond = condition ? NV50_3D_COND_MODE_EQUAL : NV50_3D_COND_MODE_NOT_EQUAL; wait = TRUE; break; case PIPE_QUERY_OCCLUSION_COUNTER: case PIPE_QUERY_OCCLUSION_PREDICATE: if (likely(!condition)) { /* XXX: Placeholder, handle nesting here if available */ if (unlikely(false)) cond = wait ? NV50_3D_COND_MODE_NOT_EQUAL : NV50_3D_COND_MODE_ALWAYS; else cond = NV50_3D_COND_MODE_RES_NON_ZERO; } else { cond = wait ? NV50_3D_COND_MODE_EQUAL : NV50_3D_COND_MODE_ALWAYS; } break; default: assert(!"render condition query not a predicate"); cond = NV50_3D_COND_MODE_ALWAYS; break; } } nv50->cond_query = pq; nv50->cond_cond = condition; nv50->cond_condmode = cond; nv50->cond_mode = mode; if (!pq) { PUSH_SPACE(push, 2); BEGIN_NV04(push, NV50_3D(COND_MODE), 1); PUSH_DATA (push, cond); return; } PUSH_SPACE(push, 9); if (wait) { BEGIN_NV04(push, SUBC_3D(NV50_GRAPH_SERIALIZE), 1); PUSH_DATA (push, 0); } PUSH_REFN (push, q->bo, NOUVEAU_BO_GART | NOUVEAU_BO_RD); BEGIN_NV04(push, NV50_3D(COND_ADDRESS_HIGH), 3); PUSH_DATAh(push, q->bo->offset + q->offset); PUSH_DATA (push, q->bo->offset + q->offset); PUSH_DATA (push, cond); BEGIN_NV04(push, NV50_2D(COND_ADDRESS_HIGH), 2); PUSH_DATAh(push, q->bo->offset + q->offset); PUSH_DATA (push, q->bo->offset + q->offset); }
void nvc0_launch_grid(struct pipe_context *pipe, const struct pipe_grid_info *info) { struct nvc0_context *nvc0 = nvc0_context(pipe); struct nouveau_pushbuf *push = nvc0->base.pushbuf; struct nvc0_program *cp = nvc0->compprog; int ret; ret = !nvc0_state_validate_cp(nvc0, ~0); if (ret) { NOUVEAU_ERR("Failed to launch grid !\n"); return; } nvc0_compute_upload_input(nvc0, info); BEGIN_NVC0(push, NVC0_CP(CP_START_ID), 1); PUSH_DATA (push, nvc0_program_symbol_offset(cp, info->pc)); BEGIN_NVC0(push, NVC0_CP(LOCAL_POS_ALLOC), 3); PUSH_DATA (push, (cp->hdr[1] & 0xfffff0) + align(cp->cp.lmem_size, 0x10)); PUSH_DATA (push, 0); PUSH_DATA (push, 0x800); /* WARP_CSTACK_SIZE */ BEGIN_NVC0(push, NVC0_CP(SHARED_SIZE), 3); PUSH_DATA (push, align(cp->cp.smem_size, 0x100)); PUSH_DATA (push, info->block[0] * info->block[1] * info->block[2]); PUSH_DATA (push, cp->num_barriers); BEGIN_NVC0(push, NVC0_CP(CP_GPR_ALLOC), 1); PUSH_DATA (push, cp->num_gprs); /* launch preliminary setup */ BEGIN_NVC0(push, NVC0_CP(GRIDID), 1); PUSH_DATA (push, 0x1); BEGIN_NVC0(push, SUBC_CP(0x036c), 1); PUSH_DATA (push, 0); BEGIN_NVC0(push, NVC0_CP(FLUSH), 1); PUSH_DATA (push, NVC0_COMPUTE_FLUSH_GLOBAL | NVC0_COMPUTE_FLUSH_UNK8); /* block setup */ BEGIN_NVC0(push, NVC0_CP(BLOCKDIM_YX), 2); PUSH_DATA (push, (info->block[1] << 16) | info->block[0]); PUSH_DATA (push, info->block[2]); if (unlikely(info->indirect)) { struct nv04_resource *res = nv04_resource(info->indirect); uint32_t offset = res->offset + info->indirect_offset; unsigned macro = NVC0_CP_MACRO_LAUNCH_GRID_INDIRECT; nouveau_pushbuf_space(push, 16, 0, 1); PUSH_REFN(push, res->bo, NOUVEAU_BO_RD | res->domain); PUSH_DATA(push, NVC0_FIFO_PKHDR_1I(1, macro, 3)); nouveau_pushbuf_data(push, res->bo, offset, NVC0_IB_ENTRY_1_NO_PREFETCH | 3 * 4); } else { /* grid setup */ BEGIN_NVC0(push, NVC0_CP(GRIDDIM_YX), 2); PUSH_DATA (push, (info->grid[1] << 16) | info->grid[0]); PUSH_DATA (push, info->grid[2]); /* kernel launching */ BEGIN_NVC0(push, NVC0_CP(COMPUTE_BEGIN), 1); PUSH_DATA (push, 0); BEGIN_NVC0(push, SUBC_CP(0x0a08), 1); PUSH_DATA (push, 0); BEGIN_NVC0(push, NVC0_CP(LAUNCH), 1); PUSH_DATA (push, 0x1000); BEGIN_NVC0(push, NVC0_CP(COMPUTE_END), 1); PUSH_DATA (push, 0); BEGIN_NVC0(push, SUBC_CP(0x0360), 1); PUSH_DATA (push, 0x1); } /* TODO: Not sure if this is really necessary. */ nvc0_compute_invalidate_surfaces(nvc0, 5); nouveau_bufctx_reset(nvc0->bufctx_cp, NVC0_BIND_CP_SUF); nvc0->dirty_cp |= NVC0_NEW_CP_SURFACES; nvc0->images_dirty[5] |= nvc0->images_valid[5]; }
struct pipe_video_decoder * nvc0_create_decoder(struct pipe_context *context, enum pipe_video_profile profile, enum pipe_video_entrypoint entrypoint, enum pipe_video_chroma_format chroma_format, unsigned width, unsigned height, unsigned max_references, bool chunked_decode) { struct nouveau_screen *screen = &((struct nvc0_context *)context)->screen->base; struct nvc0_decoder *dec; struct nouveau_pushbuf **push; union nouveau_bo_config cfg; bool kepler = screen->device->chipset >= 0xe0; cfg.nvc0.tile_mode = 0x10; cfg.nvc0.memtype = 0xfe; int ret, i; uint32_t codec = 1, ppp_codec = 3; uint32_t timeout; u32 tmp_size = 0; if (getenv("XVMC_VL")) return vl_create_decoder(context, profile, entrypoint, chroma_format, width, height, max_references, chunked_decode); if (entrypoint != PIPE_VIDEO_ENTRYPOINT_BITSTREAM) { debug_printf("%x\n", entrypoint); return NULL; } dec = CALLOC_STRUCT(nvc0_decoder); if (!dec) return NULL; dec->client = screen->client; if (!kepler) { dec->bsp_idx = 5; dec->vp_idx = 6; dec->ppp_idx = 7; } else { dec->bsp_idx = 2; dec->vp_idx = 2; dec->ppp_idx = 2; } for (i = 0; i < 3; ++i) if (i && !kepler) { dec->channel[i] = dec->channel[0]; dec->pushbuf[i] = dec->pushbuf[0]; } else { void *data; u32 size; struct nvc0_fifo nvc0_args = {}; struct nve0_fifo nve0_args = {}; if (!kepler) { size = sizeof(nvc0_args); data = &nvc0_args; } else { unsigned engine[] = { NVE0_FIFO_ENGINE_BSP, NVE0_FIFO_ENGINE_VP, NVE0_FIFO_ENGINE_PPP }; nve0_args.engine = engine[i]; size = sizeof(nve0_args); data = &nve0_args; } ret = nouveau_object_new(&screen->device->object, 0, NOUVEAU_FIFO_CHANNEL_CLASS, data, size, &dec->channel[i]); if (!ret) ret = nouveau_pushbuf_new(screen->client, dec->channel[i], 4, 32 * 1024, true, &dec->pushbuf[i]); if (ret) break; } push = dec->pushbuf; if (!kepler) { if (!ret) ret = nouveau_object_new(dec->channel[0], 0x390b1, 0x90b1, NULL, 0, &dec->bsp); if (!ret) ret = nouveau_object_new(dec->channel[1], 0x190b2, 0x90b2, NULL, 0, &dec->vp); if (!ret) ret = nouveau_object_new(dec->channel[2], 0x290b3, 0x90b3, NULL, 0, &dec->ppp); } else { if (!ret) ret = nouveau_object_new(dec->channel[0], 0x95b1, 0x95b1, NULL, 0, &dec->bsp); if (!ret) ret = nouveau_object_new(dec->channel[1], 0x95b2, 0x95b2, NULL, 0, &dec->vp); if (!ret) ret = nouveau_object_new(dec->channel[2], 0x90b3, 0x90b3, NULL, 0, &dec->ppp); } if (ret) goto fail; BEGIN_NVC0(push[0], SUBC_BSP(NV01_SUBCHAN_OBJECT), 1); PUSH_DATA (push[0], dec->bsp->handle); BEGIN_NVC0(push[1], SUBC_VP(NV01_SUBCHAN_OBJECT), 1); PUSH_DATA (push[1], dec->vp->handle); BEGIN_NVC0(push[2], SUBC_PPP(NV01_SUBCHAN_OBJECT), 1); PUSH_DATA (push[2], dec->ppp->handle); dec->base.context = context; dec->base.profile = profile; dec->base.entrypoint = entrypoint; dec->base.chroma_format = chroma_format; dec->base.width = width; dec->base.height = height; dec->base.max_references = max_references; dec->base.destroy = nvc0_decoder_destroy; dec->base.flush = nvc0_decoder_flush; dec->base.decode_bitstream = nvc0_decoder_decode_bitstream; dec->base.begin_frame = nvc0_decoder_begin_frame; dec->base.end_frame = nvc0_decoder_end_frame; for (i = 0; i < NVC0_VIDEO_QDEPTH && !ret; ++i) ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM, 0, 1 << 20, &cfg, &dec->bsp_bo[i]); if (!ret) ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM, 0x100, 4 << 20, &cfg, &dec->inter_bo[0]); if (!ret) { if (!kepler) nouveau_bo_ref(dec->inter_bo[0], &dec->inter_bo[1]); else ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM, 0x100, dec->inter_bo[0]->size, &cfg, &dec->inter_bo[1]); } if (ret) goto fail; switch (u_reduce_video_profile(profile)) { case PIPE_VIDEO_CODEC_MPEG12: { codec = 1; assert(max_references <= 2); break; } case PIPE_VIDEO_CODEC_MPEG4: { codec = 4; tmp_size = mb(height)*16 * mb(width)*16; assert(max_references <= 2); break; } case PIPE_VIDEO_CODEC_VC1: { ppp_codec = codec = 2; tmp_size = mb(height)*16 * mb(width)*16; assert(max_references <= 2); break; } case PIPE_VIDEO_CODEC_MPEG4_AVC: { codec = 3; dec->tmp_stride = 16 * mb_half(width) * nvc0_video_align(height) * 3 / 2; tmp_size = dec->tmp_stride * (max_references + 1); assert(max_references <= 16); break; } default: fprintf(stderr, "invalid codec\n"); goto fail; } if (screen->device->chipset < 0xd0) { int fd; char path[PATH_MAX]; ssize_t r; uint32_t *end, endval; ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM, 0, 0x4000, &cfg, &dec->fw_bo); if (!ret) ret = nouveau_bo_map(dec->fw_bo, NOUVEAU_BO_WR, dec->client); if (ret) goto fail; nvc0_video_getpath(profile, path); fd = open(path, O_RDONLY | O_CLOEXEC); if (fd < 0) { fprintf(stderr, "opening firmware file %s failed: %m\n", path); goto fw_fail; } r = read(fd, dec->fw_bo->map, 0x4000); close(fd); if (r < 0) { fprintf(stderr, "reading firmware file %s failed: %m\n", path); goto fw_fail; } if (r == 0x4000) { fprintf(stderr, "firmware file %s too large!\n", path); goto fw_fail; } if (r & 0xff) { fprintf(stderr, "firmware file %s wrong size!\n", path); goto fw_fail; } end = dec->fw_bo->map + r - 4; endval = *end; while (endval == *end) end--; r = (intptr_t)end - (intptr_t)dec->fw_bo->map + 4; switch (u_reduce_video_profile(profile)) { case PIPE_VIDEO_CODEC_MPEG12: { assert((r & 0xff) == 0xe0); dec->fw_sizes = (0x2e0<<16) | (r - 0x2e0); break; } case PIPE_VIDEO_CODEC_MPEG4: { assert((r & 0xff) == 0xe0); dec->fw_sizes = (0x2e0<<16) | (r - 0x2e0); break; } case PIPE_VIDEO_CODEC_VC1: { assert((r & 0xff) == 0xac); dec->fw_sizes = (0x3ac<<16) | (r - 0x3ac); break; } case PIPE_VIDEO_CODEC_MPEG4_AVC: { assert((r & 0xff) == 0x70); dec->fw_sizes = (0x370<<16) | (r - 0x370); break; } default: goto fw_fail; } munmap(dec->fw_bo->map, dec->fw_bo->size); dec->fw_bo->map = NULL; } if (codec != 3) { ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM, 0, 0x400, &cfg, &dec->bitplane_bo); if (ret) goto fail; } dec->ref_stride = mb(width)*16 * (mb_half(height)*32 + nvc0_video_align(height)/2); ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM, 0, dec->ref_stride * (max_references+2) + tmp_size, &cfg, &dec->ref_bo); if (ret) goto fail; timeout = 0; BEGIN_NVC0(push[0], SUBC_BSP(0x200), 2); PUSH_DATA (push[0], codec); PUSH_DATA (push[0], timeout); BEGIN_NVC0(push[1], SUBC_VP(0x200), 2); PUSH_DATA (push[1], codec); PUSH_DATA (push[1], timeout); BEGIN_NVC0(push[2], SUBC_PPP(0x200), 2); PUSH_DATA (push[2], ppp_codec); PUSH_DATA (push[2], timeout); ++dec->fence_seq; #if NVC0_DEBUG_FENCE ret = nouveau_bo_new(screen->device, NOUVEAU_BO_GART|NOUVEAU_BO_MAP, 0, 0x1000, NULL, &dec->fence_bo); if (ret) goto fail; nouveau_bo_map(dec->fence_bo, NOUVEAU_BO_RDWR, screen->client); dec->fence_map = dec->fence_bo->map; dec->fence_map[0] = dec->fence_map[4] = dec->fence_map[8] = 0; dec->comm = (struct comm *)(dec->fence_map + (COMM_OFFSET/sizeof(*dec->fence_map))); /* So lets test if the fence is working? */ nouveau_pushbuf_space(push[0], 6, 1, 0); PUSH_REFN (push[0], dec->fence_bo, NOUVEAU_BO_GART|NOUVEAU_BO_RDWR); BEGIN_NVC0(push[0], SUBC_BSP(0x240), 3); PUSH_DATAh(push[0], dec->fence_bo->offset); PUSH_DATA (push[0], dec->fence_bo->offset); PUSH_DATA (push[0], dec->fence_seq); BEGIN_NVC0(push[0], SUBC_BSP(0x304), 1); PUSH_DATA (push[0], 0); PUSH_KICK (push[0]); nouveau_pushbuf_space(push[1], 6, 1, 0); PUSH_REFN (push[1], dec->fence_bo, NOUVEAU_BO_GART|NOUVEAU_BO_RDWR); BEGIN_NVC0(push[1], SUBC_VP(0x240), 3); PUSH_DATAh(push[1], (dec->fence_bo->offset + 0x10)); PUSH_DATA (push[1], (dec->fence_bo->offset + 0x10)); PUSH_DATA (push[1], dec->fence_seq); BEGIN_NVC0(push[1], SUBC_VP(0x304), 1); PUSH_DATA (push[1], 0); PUSH_KICK (push[1]); nouveau_pushbuf_space(push[2], 6, 1, 0); PUSH_REFN (push[2], dec->fence_bo, NOUVEAU_BO_GART|NOUVEAU_BO_RDWR); BEGIN_NVC0(push[2], SUBC_PPP(0x240), 3); PUSH_DATAh(push[2], (dec->fence_bo->offset + 0x20)); PUSH_DATA (push[2], (dec->fence_bo->offset + 0x20)); PUSH_DATA (push[2], dec->fence_seq); BEGIN_NVC0(push[2], SUBC_PPP(0x304), 1); PUSH_DATA (push[2], 0); PUSH_KICK (push[2]); usleep(100); while (dec->fence_seq > dec->fence_map[0] || dec->fence_seq > dec->fence_map[4] || dec->fence_seq > dec->fence_map[8]) { debug_printf("%u: %u %u %u\n", dec->fence_seq, dec->fence_map[0], dec->fence_map[4], dec->fence_map[8]); usleep(100); } debug_printf("%u: %u %u %u\n", dec->fence_seq, dec->fence_map[0], dec->fence_map[4], dec->fence_map[8]); #endif return &dec->base; fw_fail: debug_printf("Cannot create decoder without firmware..\n"); nvc0_decoder_destroy(&dec->base); return NULL; fail: debug_printf("Creation failed: %s (%i)\n", strerror(-ret), ret); nvc0_decoder_destroy(&dec->base); return NULL; }
static void nv50_render_condition(struct pipe_context *pipe, struct pipe_query *pq, boolean condition, enum pipe_render_cond_flag mode) { struct nv50_context *nv50 = nv50_context(pipe); struct nouveau_pushbuf *push = nv50->base.pushbuf; struct nv50_query *q = nv50_query(pq); struct nv50_hw_query *hq = nv50_hw_query(q); uint32_t cond; bool wait = mode != PIPE_RENDER_COND_NO_WAIT && mode != PIPE_RENDER_COND_BY_REGION_NO_WAIT; if (!pq) { cond = NV50_3D_COND_MODE_ALWAYS; } else { /* NOTE: comparison of 2 queries only works if both have completed */ switch (q->type) { case PIPE_QUERY_SO_OVERFLOW_PREDICATE: cond = condition ? NV50_3D_COND_MODE_EQUAL : NV50_3D_COND_MODE_NOT_EQUAL; wait = true; break; case PIPE_QUERY_OCCLUSION_COUNTER: case PIPE_QUERY_OCCLUSION_PREDICATE: case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: if (hq->state == NV50_HW_QUERY_STATE_READY) wait = true; if (likely(!condition)) { cond = wait ? NV50_3D_COND_MODE_NOT_EQUAL : NV50_3D_COND_MODE_ALWAYS; } else { cond = wait ? NV50_3D_COND_MODE_EQUAL : NV50_3D_COND_MODE_ALWAYS; } break; default: assert(!"render condition query not a predicate"); cond = NV50_3D_COND_MODE_ALWAYS; break; } } nv50->cond_query = pq; nv50->cond_cond = condition; nv50->cond_condmode = cond; nv50->cond_mode = mode; if (!pq) { PUSH_SPACE(push, 2); BEGIN_NV04(push, NV50_3D(COND_MODE), 1); PUSH_DATA (push, cond); return; } PUSH_SPACE(push, 9); if (wait && hq->state != NV50_HW_QUERY_STATE_READY) { BEGIN_NV04(push, SUBC_3D(NV50_GRAPH_SERIALIZE), 1); PUSH_DATA (push, 0); } PUSH_REFN (push, hq->bo, NOUVEAU_BO_GART | NOUVEAU_BO_RD); BEGIN_NV04(push, NV50_3D(COND_ADDRESS_HIGH), 3); PUSH_DATAh(push, hq->bo->offset + hq->offset); PUSH_DATA (push, hq->bo->offset + hq->offset); PUSH_DATA (push, cond); BEGIN_NV04(push, NV50_2D(COND_ADDRESS_HIGH), 2); PUSH_DATAh(push, hq->bo->offset + hq->offset); PUSH_DATA (push, hq->bo->offset + hq->offset); }
struct pipe_video_codec * nvc0_create_decoder(struct pipe_context *context, const struct pipe_video_codec *templ) { struct nouveau_screen *screen = &((struct nvc0_context *)context)->screen->base; struct nouveau_vp3_decoder *dec; struct nouveau_pushbuf **push; union nouveau_bo_config cfg; bool kepler = screen->device->chipset >= 0xe0; cfg.nvc0.tile_mode = 0x10; cfg.nvc0.memtype = 0xfe; int ret, i; uint32_t codec = 1, ppp_codec = 3; uint32_t timeout; u32 tmp_size = 0; if (getenv("XVMC_VL")) return vl_create_decoder(context, templ); if (templ->entrypoint != PIPE_VIDEO_ENTRYPOINT_BITSTREAM) { debug_printf("%x\n", templ->entrypoint); return NULL; } dec = CALLOC_STRUCT(nouveau_vp3_decoder); if (!dec) return NULL; dec->client = screen->client; dec->base = *templ; nouveau_vp3_decoder_init_common(&dec->base); if (!kepler) { dec->bsp_idx = 5; dec->vp_idx = 6; dec->ppp_idx = 7; } else { dec->bsp_idx = 2; dec->vp_idx = 2; dec->ppp_idx = 2; } for (i = 0; i < 3; ++i) if (i && !kepler) { dec->channel[i] = dec->channel[0]; dec->pushbuf[i] = dec->pushbuf[0]; } else { void *data; u32 size; struct nvc0_fifo nvc0_args = {}; struct nve0_fifo nve0_args = {}; if (!kepler) { size = sizeof(nvc0_args); data = &nvc0_args; } else { unsigned engine[] = { NVE0_FIFO_ENGINE_BSP, NVE0_FIFO_ENGINE_VP, NVE0_FIFO_ENGINE_PPP }; nve0_args.engine = engine[i]; size = sizeof(nve0_args); data = &nve0_args; } ret = nouveau_object_new(&screen->device->object, 0, NOUVEAU_FIFO_CHANNEL_CLASS, data, size, &dec->channel[i]); if (!ret) ret = nouveau_pushbuf_new(screen->client, dec->channel[i], 4, 32 * 1024, true, &dec->pushbuf[i]); if (ret) break; } push = dec->pushbuf; if (!kepler) { if (!ret) ret = nouveau_object_new(dec->channel[0], 0x390b1, 0x90b1, NULL, 0, &dec->bsp); if (!ret) ret = nouveau_object_new(dec->channel[1], 0x190b2, 0x90b2, NULL, 0, &dec->vp); if (!ret) ret = nouveau_object_new(dec->channel[2], 0x290b3, 0x90b3, NULL, 0, &dec->ppp); } else { if (!ret) ret = nouveau_object_new(dec->channel[0], 0x95b1, 0x95b1, NULL, 0, &dec->bsp); if (!ret) ret = nouveau_object_new(dec->channel[1], 0x95b2, 0x95b2, NULL, 0, &dec->vp); if (!ret) ret = nouveau_object_new(dec->channel[2], 0x90b3, 0x90b3, NULL, 0, &dec->ppp); } if (ret) goto fail; BEGIN_NVC0(push[0], SUBC_BSP(NV01_SUBCHAN_OBJECT), 1); PUSH_DATA (push[0], dec->bsp->handle); BEGIN_NVC0(push[1], SUBC_VP(NV01_SUBCHAN_OBJECT), 1); PUSH_DATA (push[1], dec->vp->handle); BEGIN_NVC0(push[2], SUBC_PPP(NV01_SUBCHAN_OBJECT), 1); PUSH_DATA (push[2], dec->ppp->handle); dec->base.context = context; dec->base.decode_bitstream = nvc0_decoder_decode_bitstream; for (i = 0; i < NOUVEAU_VP3_VIDEO_QDEPTH && !ret; ++i) ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM, 0, 1 << 20, &cfg, &dec->bsp_bo[i]); if (!ret) ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM, 0x100, 4 << 20, &cfg, &dec->inter_bo[0]); if (!ret) { ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM, 0x100, dec->inter_bo[0]->size, &cfg, &dec->inter_bo[1]); } if (ret) goto fail; switch (u_reduce_video_profile(templ->profile)) { case PIPE_VIDEO_FORMAT_MPEG12: { codec = 1; assert(templ->max_references <= 2); break; } case PIPE_VIDEO_FORMAT_MPEG4: { codec = 4; tmp_size = mb(templ->height)*16 * mb(templ->width)*16; assert(templ->max_references <= 2); break; } case PIPE_VIDEO_FORMAT_VC1: { ppp_codec = codec = 2; tmp_size = mb(templ->height)*16 * mb(templ->width)*16; assert(templ->max_references <= 2); break; } case PIPE_VIDEO_FORMAT_MPEG4_AVC: { codec = 3; dec->tmp_stride = 16 * mb_half(templ->width) * nouveau_vp3_video_align(templ->height) * 3 / 2; tmp_size = dec->tmp_stride * (templ->max_references + 1); assert(templ->max_references <= 16); break; } default: fprintf(stderr, "invalid codec\n"); goto fail; } if (screen->device->chipset < 0xd0) { ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM, 0, 0x4000, &cfg, &dec->fw_bo); if (ret) goto fail; ret = nouveau_vp3_load_firmware(dec, templ->profile, screen->device->chipset); if (ret) goto fw_fail; } if (codec != 3) { ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM, 0, 0x400, &cfg, &dec->bitplane_bo); if (ret) goto fail; } dec->ref_stride = mb(templ->width)*16 * (mb_half(templ->height)*32 + nouveau_vp3_video_align(templ->height)/2); ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM, 0, dec->ref_stride * (templ->max_references+2) + tmp_size, &cfg, &dec->ref_bo); if (ret) goto fail; timeout = 0; BEGIN_NVC0(push[0], SUBC_BSP(0x200), 2); PUSH_DATA (push[0], codec); PUSH_DATA (push[0], timeout); BEGIN_NVC0(push[1], SUBC_VP(0x200), 2); PUSH_DATA (push[1], codec); PUSH_DATA (push[1], timeout); BEGIN_NVC0(push[2], SUBC_PPP(0x200), 2); PUSH_DATA (push[2], ppp_codec); PUSH_DATA (push[2], timeout); ++dec->fence_seq; #if NOUVEAU_VP3_DEBUG_FENCE ret = nouveau_bo_new(screen->device, NOUVEAU_BO_GART|NOUVEAU_BO_MAP, 0, 0x1000, NULL, &dec->fence_bo); if (ret) goto fail; nouveau_bo_map(dec->fence_bo, NOUVEAU_BO_RDWR, screen->client); dec->fence_map = dec->fence_bo->map; dec->fence_map[0] = dec->fence_map[4] = dec->fence_map[8] = 0; dec->comm = (struct comm *)(dec->fence_map + (COMM_OFFSET/sizeof(*dec->fence_map))); /* So lets test if the fence is working? */ nouveau_pushbuf_space(push[0], 6, 1, 0); PUSH_REFN (push[0], dec->fence_bo, NOUVEAU_BO_GART|NOUVEAU_BO_RDWR); BEGIN_NVC0(push[0], SUBC_BSP(0x240), 3); PUSH_DATAh(push[0], dec->fence_bo->offset); PUSH_DATA (push[0], dec->fence_bo->offset); PUSH_DATA (push[0], dec->fence_seq); BEGIN_NVC0(push[0], SUBC_BSP(0x304), 1); PUSH_DATA (push[0], 0); PUSH_KICK (push[0]); nouveau_pushbuf_space(push[1], 6, 1, 0); PUSH_REFN (push[1], dec->fence_bo, NOUVEAU_BO_GART|NOUVEAU_BO_RDWR); BEGIN_NVC0(push[1], SUBC_VP(0x240), 3); PUSH_DATAh(push[1], (dec->fence_bo->offset + 0x10)); PUSH_DATA (push[1], (dec->fence_bo->offset + 0x10)); PUSH_DATA (push[1], dec->fence_seq); BEGIN_NVC0(push[1], SUBC_VP(0x304), 1); PUSH_DATA (push[1], 0); PUSH_KICK (push[1]); nouveau_pushbuf_space(push[2], 6, 1, 0); PUSH_REFN (push[2], dec->fence_bo, NOUVEAU_BO_GART|NOUVEAU_BO_RDWR); BEGIN_NVC0(push[2], SUBC_PPP(0x240), 3); PUSH_DATAh(push[2], (dec->fence_bo->offset + 0x20)); PUSH_DATA (push[2], (dec->fence_bo->offset + 0x20)); PUSH_DATA (push[2], dec->fence_seq); BEGIN_NVC0(push[2], SUBC_PPP(0x304), 1); PUSH_DATA (push[2], 0); PUSH_KICK (push[2]); usleep(100); while (dec->fence_seq > dec->fence_map[0] || dec->fence_seq > dec->fence_map[4] || dec->fence_seq > dec->fence_map[8]) { debug_printf("%u: %u %u %u\n", dec->fence_seq, dec->fence_map[0], dec->fence_map[4], dec->fence_map[8]); usleep(100); } debug_printf("%u: %u %u %u\n", dec->fence_seq, dec->fence_map[0], dec->fence_map[4], dec->fence_map[8]); #endif return &dec->base; fw_fail: debug_printf("Cannot create decoder without firmware..\n"); dec->base.destroy(&dec->base); return NULL; fail: debug_printf("Creation failed: %s (%i)\n", strerror(-ret), ret); dec->base.destroy(&dec->base); return NULL; }