bc40fcfb5ba3cf6e408ee98ed82eb04354063a82
[profile/ivi/mesa.git] / src / gallium / drivers / r300 / r300_query.c
1 /*
2  * Copyright 2009 Corbin Simpson <MostAwesomeDude@gmail.com>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * on the rights to use, copy, modify, merge, publish, distribute, sub
8  * license, and/or sell copies of the Software, and to permit persons to whom
9  * the Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21  * USE OR OTHER DEALINGS IN THE SOFTWARE. */
22
23 #include "util/u_memory.h"
24 #include "util/u_simple_list.h"
25
26 #include "r300_context.h"
27 #include "r300_screen.h"
28 #include "r300_cs.h"
29 #include "r300_emit.h"
30 #include "r300_query.h"
31 #include "r300_reg.h"
32
33 #include <stdio.h>
34
35 static struct pipe_query *r300_create_query(struct pipe_context *pipe,
36                                             unsigned query_type)
37 {
38     struct r300_context *r300 = r300_context(pipe);
39     struct r300_screen *r300screen = r300->screen;
40     unsigned query_size;
41     struct r300_query *q, *qptr;
42
43     q = CALLOC_STRUCT(r300_query);
44
45     q->type = query_type;
46     assert(q->type == PIPE_QUERY_OCCLUSION_COUNTER);
47
48     q->active = FALSE;
49
50     if (r300screen->caps.family == CHIP_FAMILY_RV530)
51         query_size = r300screen->caps.num_z_pipes * sizeof(uint32_t);
52     else
53         query_size = r300screen->caps.num_frag_pipes * sizeof(uint32_t);
54
55     if (!is_empty_list(&r300->query_list)) {
56         qptr = last_elem(&r300->query_list);
57         q->offset = qptr->offset + query_size;
58     }
59     insert_at_tail(&r300->query_list, q);
60
61     /* XXX */
62     if (q->offset >= 4096) {
63         q->offset = 0;
64     }
65
66     return (struct pipe_query*)q;
67 }
68
69 static void r300_destroy_query(struct pipe_context* pipe,
70                                struct pipe_query* query)
71 {
72     struct r300_query* q = (struct r300_query*)query;
73
74     remove_from_list(q);
75     FREE(query);
76 }
77
78 static void r300_begin_query(struct pipe_context* pipe,
79                              struct pipe_query* query)
80 {
81     uint32_t* map;
82     struct r300_context* r300 = r300_context(pipe);
83     struct r300_query* q = (struct r300_query*)query;
84
85     assert(r300->query_current == NULL);
86
87     map = pipe->screen->buffer_map(pipe->screen, r300->oqbo,
88             PIPE_BUFFER_USAGE_CPU_WRITE);
89     map += q->offset / 4;
90     *map = ~0U;
91     pipe->screen->buffer_unmap(pipe->screen, r300->oqbo);
92
93     q->flushed = FALSE;
94     r300->query_current = q;
95     r300->dirty_state |= R300_NEW_QUERY;
96 }
97
98 static void r300_end_query(struct pipe_context* pipe,
99                            struct pipe_query* query)
100 {
101     struct r300_context* r300 = r300_context(pipe);
102     struct r300_query* q = (struct r300_query*)query;
103
104     r300_emit_query_end(r300);
105     q->begin_emitted = false;
106     r300->query_current = NULL;
107 }
108
109 static boolean r300_get_query_result(struct pipe_context* pipe,
110                                      struct pipe_query* query,
111                                      boolean wait,
112                                      uint64_t* result)
113 {
114     struct r300_context* r300 = r300_context(pipe);
115     struct r300_screen* r300screen = r300->screen;
116     struct r300_query *q = (struct r300_query*)query;
117     unsigned flags = PIPE_BUFFER_USAGE_CPU_READ;
118     uint32_t* map;
119     uint32_t temp = 0;
120     unsigned i, num_results;
121
122     if (q->flushed == FALSE)
123         pipe->flush(pipe, 0, NULL);
124     if (!wait) {
125         flags |= PIPE_BUFFER_USAGE_DONTBLOCK;
126     }
127
128     map = pipe->screen->buffer_map(pipe->screen, r300->oqbo, flags);
129     if (!map)
130         return FALSE;
131     map += q->offset / 4;
132
133     if (r300screen->caps.family == CHIP_FAMILY_RV530)
134         num_results = r300screen->caps.num_z_pipes;
135     else
136         num_results = r300screen->caps.num_frag_pipes;
137
138     for (i = 0; i < num_results; i++) {
139         if (*map == ~0U) {
140             /* Looks like our results aren't ready yet. */
141             if (wait) {
142                 fprintf(stderr, "r300: Despite waiting, OQ results haven't "
143                                 "come in yet.\n");
144             }
145             temp = ~0U;
146             break;
147         }
148         temp += *map;
149         map++;
150     }
151     pipe->screen->buffer_unmap(pipe->screen, r300->oqbo);
152
153     if (temp == ~0U) {
154         /* Our results haven't been written yet... */
155         return FALSE;
156     }
157
158     *result = temp;
159     return TRUE;
160 }
161
162 static void r300_render_condition(struct pipe_context *pipe,
163                                   struct pipe_query *query,
164                                   uint mode)
165 {
166     struct r300_context *r300 = r300_context(pipe);
167     uint64_t result;
168     boolean wait;
169
170     if (query) {
171         wait = mode == PIPE_RENDER_COND_WAIT ||
172                mode == PIPE_RENDER_COND_BY_REGION_WAIT;
173
174         if (!r300_get_query_result(pipe, query, wait, &result)) {
175             r300->skip_rendering = FALSE;
176         }
177
178         r300->skip_rendering = result == 0;
179     } else {
180         r300->skip_rendering = FALSE;
181     }
182 }
183
184 void r300_init_query_functions(struct r300_context* r300) {
185     r300->context.create_query = r300_create_query;
186     r300->context.destroy_query = r300_destroy_query;
187     r300->context.begin_query = r300_begin_query;
188     r300->context.end_query = r300_end_query;
189     r300->context.get_query_result = r300_get_query_result;
190     r300->context.render_condition = r300_render_condition;
191 }