[Nouveau] [PATCH] nv30-nv40: support unlimited queries (v2)
Luca Barbieri
luca at luca-barbieri.com
Mon Jan 18 10:05:56 PST 2010
Currently on NV30/NV40 an assert will be triggered once 32 queries are
outstanding.
This violates the OpenGL/Gallium interface, which requires support for
an unlimited number of fences.
This patch fixes the problem by putting queries in a linked list and
waiting on the oldest one if allocation fails.
nVidia seems to use a similar strategy, but with 1024 instead of 32 fences.
The next patch will improve this.
Fixed indentation and added header for query_list.
---
src/gallium/drivers/nv30/nv30_query.c | 26 ++++++++++++++++++--------
src/gallium/drivers/nv30/nv30_screen.c | 2 ++
src/gallium/drivers/nv30/nv30_screen.h | 2 ++
src/gallium/drivers/nv40/nv40_query.c | 26 ++++++++++++++++++--------
src/gallium/drivers/nv40/nv40_screen.c | 2 ++
src/gallium/drivers/nv40/nv40_screen.h | 2 ++
6 files changed, 44 insertions(+), 16 deletions(-)
diff --git a/src/gallium/drivers/nv30/nv30_query.c b/src/gallium/drivers/nv30/nv30_query.c
index e27e9cc..eeab223 100644
--- a/src/gallium/drivers/nv30/nv30_query.c
+++ b/src/gallium/drivers/nv30/nv30_query.c
@@ -3,6 +3,7 @@
#include "nv30_context.h"
struct nv30_query {
+ struct list_head list;
struct nouveau_resource *object;
unsigned type;
boolean ready;
@@ -23,6 +24,8 @@ nv30_query_create(struct pipe_context *pipe, unsigned query_type)
q = CALLOC(1, sizeof(struct nv30_query));
q->type = query_type;
+ assert(q->type == PIPE_QUERY_OCCLUSION_COUNTER);
+
return (struct pipe_query *)q;
}
@@ -32,7 +35,10 @@ nv30_query_destroy(struct pipe_context *pipe, struct pipe_query *pq)
struct nv30_query *q = nv30_query(pq);
if (q->object)
+ {
nouveau_resource_free(&q->object);
+ LIST_DEL(&q->list);
+ }
FREE(q);
}
@@ -44,20 +50,25 @@ nv30_query_begin(struct pipe_context *pipe, struct pipe_query *pq)
struct nv30_screen *screen = nv30->screen;
struct nouveau_channel *chan = screen->base.channel;
struct nouveau_grobj *rankine = screen->rankine;
-
- assert(q->type == PIPE_QUERY_OCCLUSION_COUNTER);
+ uint64_t tmp;
/* 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;
+ if (q->object)
pipe->get_query_result(pipe, pq, 1, &tmp);
+
+ while (nouveau_resource_alloc(nv30->screen->query_heap, 1, NULL, &q->object))
+ {
+ struct nv30_query* oldestq;
+ assert(!LIST_IS_EMPTY(&nv30->screen->query_list));
+ oldestq = LIST_ENTRY(struct nv30_query, nv30->screen->query_list.next, list);
+ pipe->get_query_result(pipe, (struct pipe_query*)oldestq, 1, &tmp);
}
- if (nouveau_resource_alloc(nv30->screen->query_heap, 1, NULL, &q->object))
- assert(0);
+ LIST_ADDTAIL(&q->list, &nv30->screen->query_list);
+
nouveau_notifier_reset(nv30->screen->query, q->object->start);
BEGIN_RING(chan, rankine, NV34TCL_QUERY_RESET, 1);
@@ -90,8 +101,6 @@ nv30_query_result(struct pipe_context *pipe, struct pipe_query *pq,
struct nv30_context *nv30 = nv30_context(pipe);
struct nv30_query *q = nv30_query(pq);
- assert(q->object && q->type == PIPE_QUERY_OCCLUSION_COUNTER);
-
if (!q->ready) {
unsigned status;
@@ -110,6 +119,7 @@ nv30_query_result(struct pipe_context *pipe, struct pipe_query *pq,
q->object->start);
q->ready = TRUE;
nouveau_resource_free(&q->object);
+ LIST_DEL(&q->list);
}
*result = q->result;
diff --git a/src/gallium/drivers/nv30/nv30_screen.c b/src/gallium/drivers/nv30/nv30_screen.c
index 9ed4817..755db43 100644
--- a/src/gallium/drivers/nv30/nv30_screen.c
+++ b/src/gallium/drivers/nv30/nv30_screen.c
@@ -261,6 +261,8 @@ nv30_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
return NULL;
}
+ LIST_INITHEAD(&screen->query_list);
+
/* Vtxprog resources */
if (nouveau_resource_init(&screen->vp_exec_heap, 0, 256) ||
nouveau_resource_init(&screen->vp_data_heap, 0, 256)) {
diff --git a/src/gallium/drivers/nv30/nv30_screen.h b/src/gallium/drivers/nv30/nv30_screen.h
index 5fbd998..4e8b55c 100644
--- a/src/gallium/drivers/nv30/nv30_screen.h
+++ b/src/gallium/drivers/nv30/nv30_screen.h
@@ -1,6 +1,7 @@
#ifndef __NV30_SCREEN_H__
#define __NV30_SCREEN_H__
+#include <util/u_double_list.h>
#include "nouveau/nouveau_screen.h"
#include "nv04/nv04_surface_2d.h"
@@ -20,6 +21,7 @@ struct nv30_screen {
/* Query object resources */
struct nouveau_notifier *query;
struct nouveau_resource *query_heap;
+ struct list_head query_list;
/* Vtxprog resources */
struct nouveau_resource *vp_exec_heap;
diff --git a/src/gallium/drivers/nv40/nv40_query.c b/src/gallium/drivers/nv40/nv40_query.c
index 8ed4a67..7cea56c 100644
--- a/src/gallium/drivers/nv40/nv40_query.c
+++ b/src/gallium/drivers/nv40/nv40_query.c
@@ -3,6 +3,7 @@
#include "nv40_context.h"
struct nv40_query {
+ struct list_head list;
struct nouveau_resource *object;
unsigned type;
boolean ready;
@@ -23,6 +24,8 @@ nv40_query_create(struct pipe_context *pipe, unsigned query_type)
q = CALLOC(1, sizeof(struct nv40_query));
q->type = query_type;
+ assert(q->type == PIPE_QUERY_OCCLUSION_COUNTER);
+
return (struct pipe_query *)q;
}
@@ -32,7 +35,10 @@ 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);
+ LIST_DEL(&q->list);
+ }
FREE(q);
}
@@ -44,20 +50,25 @@ nv40_query_begin(struct pipe_context *pipe, struct pipe_query *pq)
struct nv40_screen *screen = nv40->screen;
struct nouveau_channel *chan = screen->base.channel;
struct nouveau_grobj *curie = screen->curie;
-
- assert(q->type == PIPE_QUERY_OCCLUSION_COUNTER);
+ uint64_t tmp;
/* 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;
+ if (q->object)
pipe->get_query_result(pipe, pq, 1, &tmp);
+
+ while (nouveau_resource_alloc(nv40->screen->query_heap, 1, NULL, &q->object))
+ {
+ struct nv40_query* oldestq;
+ assert(!LIST_IS_EMPTY(&nv40->screen->query_list));
+ oldestq = LIST_ENTRY(struct nv40_query, nv40->screen->query_list.next, list);
+ pipe->get_query_result(pipe, (struct pipe_query*)oldestq, 1, &tmp);
}
- if (nouveau_resource_alloc(nv40->screen->query_heap, 1, NULL, &q->object))
- assert(0);
+ LIST_ADDTAIL(&q->list, &nv40->screen->query_list);
+
nouveau_notifier_reset(nv40->screen->query, q->object->start);
BEGIN_RING(chan, curie, NV40TCL_QUERY_RESET, 1);
@@ -90,8 +101,6 @@ nv40_query_result(struct pipe_context *pipe, struct pipe_query *pq,
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;
@@ -110,6 +119,7 @@ nv40_query_result(struct pipe_context *pipe, struct pipe_query *pq,
q->object->start);
q->ready = TRUE;
nouveau_resource_free(&q->object);
+ LIST_DEL(&q->list);
}
*result = q->result;
diff --git a/src/gallium/drivers/nv40/nv40_screen.c b/src/gallium/drivers/nv40/nv40_screen.c
index 9e55e5a..0fd50f6 100644
--- a/src/gallium/drivers/nv40/nv40_screen.c
+++ b/src/gallium/drivers/nv40/nv40_screen.c
@@ -243,6 +243,8 @@ nv40_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
return NULL;
}
+ LIST_INITHEAD(&screen->query_list);
+
/* Vtxprog resources */
if (nouveau_resource_init(&screen->vp_exec_heap, 0, 512) ||
nouveau_resource_init(&screen->vp_data_heap, 0, 256)) {
diff --git a/src/gallium/drivers/nv40/nv40_screen.h b/src/gallium/drivers/nv40/nv40_screen.h
index 57b4c8f..50b7573 100644
--- a/src/gallium/drivers/nv40/nv40_screen.h
+++ b/src/gallium/drivers/nv40/nv40_screen.h
@@ -1,6 +1,7 @@
#ifndef __NV40_SCREEN_H__
#define __NV40_SCREEN_H__
+#include <util/u_double_list.h>
#include "nouveau/nouveau_screen.h"
#include "nv04/nv04_surface_2d.h"
@@ -19,6 +20,7 @@ struct nv40_screen {
/* Query object resources */
struct nouveau_notifier *query;
struct nouveau_resource *query_heap;
+ struct list_head query_list;
/* Vtxprog resources */
struct nouveau_resource *vp_exec_heap;
--
1.6.3.3
More information about the Nouveau
mailing list