| #include "pipe/p_context.h" |
| |
| #include "nv40_context.h" |
| |
| struct nv40_query { |
| struct nouveau_resource *object; |
| unsigned type; |
| boolean ready; |
| uint64_t result; |
| }; |
| |
| static INLINE struct nv40_query * |
| nv40_query(struct pipe_query *pipe) |
| { |
| return (struct nv40_query *)pipe; |
| } |
| |
| static struct pipe_query * |
| nv40_query_create(struct pipe_context *pipe, unsigned query_type) |
| { |
| struct nv40_query *q; |
| |
| q = CALLOC(1, sizeof(struct nv40_query)); |
| q->type = query_type; |
| |
| return (struct pipe_query *)q; |
| } |
| |
| static void |
| nv40_query_destroy(struct pipe_context *pipe, struct pipe_query *pq) |
| { |
| struct nv40_query *q = nv40_query(pq); |
| |
| if (q->object) |
| nouveau_resource_free(&q->object); |
| FREE(q); |
| } |
| |
| static void |
| nv40_query_begin(struct pipe_context *pipe, struct pipe_query *pq) |
| { |
| struct nv40_context *nv40 = nv40_context(pipe); |
| struct nv40_query *q = nv40_query(pq); |
| |
| assert(q->type == PIPE_QUERY_OCCLUSION_COUNTER); |
| |
| /* Happens when end_query() is called, then another begin_query() |
| * without querying the result in-between. For now we'll wait for |
| * the existing query to notify completion, but it could be better. |
| */ |
| if (q->object) { |
| uint64_t tmp; |
| pipe->get_query_result(pipe, pq, 1, &tmp); |
| } |
| |
| if (nouveau_resource_alloc(nv40->screen->query_heap, 1, NULL, &q->object)) |
| assert(0); |
| nouveau_notifier_reset(nv40->screen->query, q->object->start); |
| |
| BEGIN_RING(curie, NV40TCL_QUERY_RESET, 1); |
| OUT_RING (1); |
| BEGIN_RING(curie, NV40TCL_QUERY_UNK17CC, 1); |
| OUT_RING (1); |
| |
| q->ready = FALSE; |
| } |
| |
| static void |
| nv40_query_end(struct pipe_context *pipe, struct pipe_query *pq) |
| { |
| struct nv40_context *nv40 = nv40_context(pipe); |
| struct nv40_query *q = nv40_query(pq); |
| |
| BEGIN_RING(curie, NV40TCL_QUERY_GET, 1); |
| OUT_RING ((0x01 << NV40TCL_QUERY_GET_UNK24_SHIFT) | |
| ((q->object->start * 32) << NV40TCL_QUERY_GET_OFFSET_SHIFT)); |
| FIRE_RING(NULL); |
| } |
| |
| static boolean |
| nv40_query_result(struct pipe_context *pipe, struct pipe_query *pq, |
| boolean wait, uint64_t *result) |
| { |
| struct nv40_context *nv40 = nv40_context(pipe); |
| struct nv40_query *q = nv40_query(pq); |
| |
| assert(q->object && q->type == PIPE_QUERY_OCCLUSION_COUNTER); |
| |
| if (!q->ready) { |
| unsigned status; |
| |
| status = nouveau_notifier_status(nv40->screen->query, |
| q->object->start); |
| if (status != NV_NOTIFY_STATE_STATUS_COMPLETED) { |
| if (wait == FALSE) |
| return FALSE; |
| nouveau_notifier_wait_status(nv40->screen->query, |
| q->object->start, |
| NV_NOTIFY_STATE_STATUS_COMPLETED, |
| 0); |
| } |
| |
| q->result = nouveau_notifier_return_val(nv40->screen->query, |
| q->object->start); |
| q->ready = TRUE; |
| nouveau_resource_free(&q->object); |
| } |
| |
| *result = q->result; |
| return TRUE; |
| } |
| |
| void |
| nv40_init_query_functions(struct nv40_context *nv40) |
| { |
| nv40->pipe.create_query = nv40_query_create; |
| nv40->pipe.destroy_query = nv40_query_destroy; |
| nv40->pipe.begin_query = nv40_query_begin; |
| nv40->pipe.end_query = nv40_query_end; |
| nv40->pipe.get_query_result = nv40_query_result; |
| } |