static bool nv50_hw_query_allocate(struct nv50_context *nv50, struct nv50_query *q, int size) { struct nv50_screen *screen = nv50->screen; struct nv50_hw_query *hq = nv50_hw_query(q); int ret; if (hq->bo) { nouveau_bo_ref(NULL, &hq->bo); if (hq->mm) { if (hq->state == NV50_HW_QUERY_STATE_READY) nouveau_mm_free(hq->mm); else nouveau_fence_work(screen->base.fence.current, nouveau_mm_free_work, hq->mm); } } if (size) { hq->mm = nouveau_mm_allocate(screen->base.mm_GART, size, &hq->bo, &hq->base_offset); if (!hq->bo) return false; hq->offset = hq->base_offset; ret = nouveau_bo_map(hq->bo, 0, screen->base.client); if (ret) { nv50_hw_query_allocate(nv50, q, 0); return false; } hq->data = (uint32_t *)((uint8_t *)hq->bo->map + hq->base_offset); } return true; }
struct nv50_hw_query * nv50_hw_sm_create_query(struct nv50_context *nv50, unsigned type) { struct nv50_hw_sm_query *hsq; struct nv50_hw_query *hq; unsigned space; if (type < NV50_HW_SM_QUERY(0) || type > NV50_HW_SM_QUERY_LAST) return NULL; hsq = CALLOC_STRUCT(nv50_hw_sm_query); if (!hsq) return NULL; hq = &hsq->base; hq->funcs = &hw_sm_query_funcs; hq->base.type = type; /* * for each MP: * [00] = MP.C0 * [04] = MP.C1 * [08] = MP.C2 * [0c] = MP.C3 * [10] = MP.sequence */ space = (4 + 1) * nv50->screen->MPsInTP * sizeof(uint32_t); if (!nv50_hw_query_allocate(nv50, &hq->base, space)) { FREE(hq); return NULL; } return hq; }
static void nv50_hw_destroy_query(struct nv50_context *nv50, struct nv50_query *q) { struct nv50_hw_query *hq = nv50_hw_query(q); nv50_hw_query_allocate(nv50, q, 0); nouveau_fence_ref(NULL, &hq->fence); FREE(hq); }
static void nv50_hw_destroy_query(struct nv50_context *nv50, struct nv50_query *q) { struct nv50_hw_query *hq = nv50_hw_query(q); if (hq->funcs && hq->funcs->destroy_query) { hq->funcs->destroy_query(nv50, hq); return; } nv50_hw_query_allocate(nv50, q, 0); nouveau_fence_ref(NULL, &hq->fence); FREE(hq); }
struct nv50_query * nv50_hw_create_query(struct nv50_context *nv50, unsigned type, unsigned index) { struct nv50_hw_query *hq; struct nv50_query *q; hq = CALLOC_STRUCT(nv50_hw_query); if (!hq) return NULL; q = &hq->base; q->funcs = &hw_query_funcs; q->type = type; switch (q->type) { case PIPE_QUERY_OCCLUSION_COUNTER: hq->rotate = 32; break; case PIPE_QUERY_PRIMITIVES_GENERATED: case PIPE_QUERY_PRIMITIVES_EMITTED: case PIPE_QUERY_SO_STATISTICS: case PIPE_QUERY_PIPELINE_STATISTICS: hq->is64bit = true; break; case PIPE_QUERY_TIME_ELAPSED: case PIPE_QUERY_TIMESTAMP: case PIPE_QUERY_TIMESTAMP_DISJOINT: case PIPE_QUERY_GPU_FINISHED: case NVA0_HW_QUERY_STREAM_OUTPUT_BUFFER_OFFSET: break; default: debug_printf("invalid query type: %u\n", type); FREE(q); return NULL; } if (!nv50_hw_query_allocate(nv50, q, NV50_HW_QUERY_ALLOC_SPACE)) { FREE(hq); return NULL; } if (hq->rotate) { /* we advance before query_begin ! */ hq->offset -= hq->rotate; hq->data -= hq->rotate / sizeof(*hq->data); } return q; }
static boolean nv50_hw_begin_query(struct nv50_context *nv50, struct nv50_query *q) { struct nouveau_pushbuf *push = nv50->base.pushbuf; struct nv50_hw_query *hq = nv50_hw_query(q); /* For occlusion queries we have to change the storage, because a previous * query might set the initial render condition to false even *after* we re- * initialized it to true. */ if (hq->rotate) { hq->offset += hq->rotate; hq->data += hq->rotate / sizeof(*hq->data); if (hq->offset - hq->base_offset == NV50_HW_QUERY_ALLOC_SPACE) nv50_hw_query_allocate(nv50, q, NV50_HW_QUERY_ALLOC_SPACE); /* XXX: can we do this with the GPU, and sync with respect to a previous * query ? */ hq->data[0] = hq->sequence; /* initialize sequence */ hq->data[1] = 1; /* initial render condition = true */ hq->data[4] = hq->sequence + 1; /* for comparison COND_MODE */ hq->data[5] = 0; } if (!hq->is64bit) hq->data[0] = hq->sequence++; /* the previously used one */ switch (q->type) { case PIPE_QUERY_OCCLUSION_COUNTER: hq->nesting = nv50->screen->num_occlusion_queries_active++; if (hq->nesting) { nv50_hw_query_get(push, q, 0x10, 0x0100f002); } else { PUSH_SPACE(push, 4); BEGIN_NV04(push, NV50_3D(COUNTER_RESET), 1); PUSH_DATA (push, NV50_3D_COUNTER_RESET_SAMPLECNT); BEGIN_NV04(push, NV50_3D(SAMPLECNT_ENABLE), 1); PUSH_DATA (push, 1); } break; case PIPE_QUERY_PRIMITIVES_GENERATED: nv50_hw_query_get(push, q, 0x10, 0x06805002); break; case PIPE_QUERY_PRIMITIVES_EMITTED: nv50_hw_query_get(push, q, 0x10, 0x05805002); break; case PIPE_QUERY_SO_STATISTICS: nv50_hw_query_get(push, q, 0x20, 0x05805002); nv50_hw_query_get(push, q, 0x30, 0x06805002); break; case PIPE_QUERY_PIPELINE_STATISTICS: nv50_hw_query_get(push, q, 0x80, 0x00801002); /* VFETCH, VERTICES */ nv50_hw_query_get(push, q, 0x90, 0x01801002); /* VFETCH, PRIMS */ nv50_hw_query_get(push, q, 0xa0, 0x02802002); /* VP, LAUNCHES */ nv50_hw_query_get(push, q, 0xb0, 0x03806002); /* GP, LAUNCHES */ nv50_hw_query_get(push, q, 0xc0, 0x04806002); /* GP, PRIMS_OUT */ nv50_hw_query_get(push, q, 0xd0, 0x07804002); /* RAST, PRIMS_IN */ nv50_hw_query_get(push, q, 0xe0, 0x08804002); /* RAST, PRIMS_OUT */ nv50_hw_query_get(push, q, 0xf0, 0x0980a002); /* ROP, PIXELS */ break; case PIPE_QUERY_TIME_ELAPSED: nv50_hw_query_get(push, q, 0x10, 0x00005002); break; default: assert(0); return false; } hq->state = NV50_HW_QUERY_STATE_ACTIVE; return true; }