nv50: occlusion queries
authorBen Skeggs <skeggsb@gmail.com>
Tue, 13 Jan 2009 00:44:52 +0000 (10:44 +1000)
committerBen Skeggs <skeggsb@gmail.com>
Tue, 13 Jan 2009 03:57:22 +0000 (13:57 +1000)
Not quite working, but the general idea is right I think.

src/gallium/drivers/nv50/nv50_query.c
src/gallium/drivers/nv50/nv50_screen.c

index 777e77906d5a380996dca49f174596b13460d8cb..b923c820ebafab4f9d8217f1eb340de77e028cf7 100644 (file)
  */
 
 #include "pipe/p_context.h"
+#include "pipe/p_inlines.h"
 
 #include "nv50_context.h"
 
+struct nv50_query {
+       struct pipe_buffer *buffer;
+       unsigned type;
+       boolean ready;
+       uint64_t result;
+};
+
+static INLINE struct nv50_query *
+nv50_query(struct pipe_query *pipe)
+{
+       return (struct nv50_query *)pipe;
+}
+
 static struct pipe_query *
 nv50_query_create(struct pipe_context *pipe, unsigned type)
 {
-       NOUVEAU_ERR("unimplemented\n");
-       return NULL;
+       struct pipe_winsys *ws = pipe->winsys;
+       struct nv50_query *q = CALLOC_STRUCT(nv50_query);
+
+       assert (q->type == PIPE_QUERY_OCCLUSION_COUNTER);
+       q->type = type;
+
+       q->buffer = ws->buffer_create(ws, 256, 0, 16);
+       if (!q->buffer) {
+               FREE(q);
+               return NULL;
+       }
+
+       return (struct pipe_query *)q;
 }
 
 static void
-nv50_query_destroy(struct pipe_context *pipe, struct pipe_query *q)
+nv50_query_destroy(struct pipe_context *pipe, struct pipe_query *pq)
 {
-       NOUVEAU_ERR("unimplemented\n");
+       struct nv50_query *q = nv50_query(pq);
+
+       if (q) {
+               pipe_buffer_reference(pipe, &q->buffer, NULL);
+               FREE(q);
+       }
 }
 
 static void
-nv50_query_begin(struct pipe_context *pipe, struct pipe_query *q)
+nv50_query_begin(struct pipe_context *pipe, struct pipe_query *pq)
 {
-       NOUVEAU_ERR("unimplemented\n");
+       struct nv50_context *nv50 = nv50_context(pipe);
+       struct nv50_query *q = nv50_query(pq);
+
+       BEGIN_RING(tesla, 0x1530, 1);
+       OUT_RING  (1);
+       BEGIN_RING(tesla, 0x1514, 1);
+       OUT_RING  (1);
+
+       q->ready = FALSE;
 }
 
 static void
-nv50_query_end(struct pipe_context *pipe, struct pipe_query *q)
+nv50_query_end(struct pipe_context *pipe, struct pipe_query *pq)
 {
-       NOUVEAU_ERR("unimplemented\n");
+       struct nv50_context *nv50 = nv50_context(pipe);
+       struct nv50_query *q = nv50_query(pq);
+
+       BEGIN_RING(tesla, 0x1b00, 4);
+       OUT_RELOCh(q->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
+       OUT_RELOCl(q->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
+       OUT_RING  (0x00000000);
+       OUT_RING  (0x0100f002);
+       FIRE_RING (NULL);
 }
 
 static boolean
-nv50_query_result(struct pipe_context *pipe, struct pipe_query *q,
+nv50_query_result(struct pipe_context *pipe, struct pipe_query *pq,
                  boolean wait, uint64_t *result)
 {
-       NOUVEAU_ERR("unimplemented\n");
-       *result = 0xdeadcafe;
-       return TRUE;
+       struct pipe_winsys *ws = pipe->winsys;
+       struct nv50_query *q = nv50_query(pq);
+
+       /*XXX: Want to be able to return FALSE here instead of blocking
+        *     until the result is available..
+        */
+
+       if (!q->ready) {
+               uint32_t *map = ws->buffer_map(ws, q->buffer,
+                                              PIPE_BUFFER_USAGE_CPU_READ);
+               q->result = map[1];
+               q->ready = TRUE;
+               ws->buffer_unmap(ws, q->buffer);
+       }
+
+       *result = q->result;
+       return q->ready;
 }
 
 void
index e2071103fba152f516a5f8d567e0c76d359acbd6..b46619d78612352b858c2514b63e6fd9b5e402b1 100644 (file)
@@ -104,7 +104,7 @@ nv50_screen_get_param(struct pipe_screen *pscreen, int param)
        case PIPE_CAP_MAX_RENDER_TARGETS:
                return 8;
        case PIPE_CAP_OCCLUSION_QUERY:
-               return 0;
+               return 1;
        case PIPE_CAP_TEXTURE_SHADOW_MAP:
                return 0;
        case PIPE_CAP_MAX_TEXTURE_2D_LEVELS: