radeon_queryobj.c revision 9ad76e9479c9c3cb8b2947d5144de33bb31197b8
1/*
2 * Copyright © 2008-2009 Maciej Cencora <m.cencora@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 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 * Authors:
24 *    Maciej Cencora <m.cencora@gmail.com>
25 *
26 */
27#include "radeon_common.h"
28#include "radeon_queryobj.h"
29
30#include "main/imports.h"
31#include "main/simple_list.h"
32
33#define DDEBUG 0
34
35#define PAGE_SIZE 4096
36
37static void radeonQueryGetResult(GLcontext *ctx, struct gl_query_object *q)
38{
39	struct radeon_query_object *query = (struct radeon_query_object *)q;
40	uint32_t *result;
41	int i;
42
43	if (DDEBUG) fprintf(stderr, "%s: query id %d, result %d\n", __FUNCTION__, query->Base.Id, (int) query->Base.Result);
44
45	radeon_bo_map(query->bo, GL_FALSE);
46
47	result = query->bo->ptr;
48
49	query->Base.Result = 0;
50	for (i = 0; i < query->curr_offset/sizeof(uint32_t); ++i) {
51		query->Base.Result += result[i];
52		if (DDEBUG) fprintf(stderr, "result[%d] = %d\n", i, result[i]);
53	}
54
55	radeon_bo_unmap(query->bo);
56}
57
58static struct gl_query_object * radeonNewQueryObject(GLcontext *ctx, GLuint id)
59{
60	struct radeon_query_object *query;
61
62	query = _mesa_calloc(sizeof(struct radeon_query_object));
63
64	query->Base.Id = id;
65	query->Base.Result = 0;
66	query->Base.Active = GL_FALSE;
67	query->Base.Ready = GL_TRUE;
68
69	if (DDEBUG) fprintf(stderr, "%s: query id %d\n", __FUNCTION__, query->Base.Id);
70
71	return &query->Base;
72}
73
74static void radeonDeleteQuery(GLcontext *ctx, struct gl_query_object *q)
75{
76	struct radeon_query_object *query = (struct radeon_query_object *)q;
77
78	if (DDEBUG) fprintf(stderr, "%s: query id %d\n", __FUNCTION__, q->Id);
79
80	if (query->bo) {
81		radeon_bo_unref(query->bo);
82	}
83
84	_mesa_free(query);
85}
86
87static void radeonWaitQuery(GLcontext *ctx, struct gl_query_object *q)
88{
89	radeonContextPtr radeon = RADEON_CONTEXT(ctx);
90	struct radeon_query_object *tmp, *query = (struct radeon_query_object *)q;
91
92	/* If the cmdbuf with packets for this query hasn't been flushed yet, do it now */
93	{
94		GLboolean found = GL_FALSE;
95		foreach(tmp, &radeon->query.not_flushed_head) {
96			if (tmp == query) {
97				found = GL_TRUE;
98				break;
99			}
100		}
101
102		if (found)
103			ctx->Driver.Flush(ctx);
104	}
105
106	if (DDEBUG) fprintf(stderr, "%s: query id %d, bo %p, offset %d\n", __FUNCTION__, q->Id, query->bo, query->curr_offset);
107
108	radeonQueryGetResult(ctx, q);
109
110	query->Base.Ready = GL_TRUE;
111}
112
113
114static void radeonBeginQuery(GLcontext *ctx, struct gl_query_object *q)
115{
116	radeonContextPtr radeon = RADEON_CONTEXT(ctx);
117	struct radeon_query_object *query = (struct radeon_query_object *)q;
118
119	if (DDEBUG) fprintf(stderr, "%s: query id %d\n", __FUNCTION__, q->Id);
120
121	assert(radeon->query.current == NULL);
122
123	if (radeon->dma.flush)
124		radeon->dma.flush(radeon->glCtx);
125
126	if (!query->bo) {
127		query->bo = radeon_bo_open(radeon->radeonScreen->bom, 0, PAGE_SIZE, PAGE_SIZE, RADEON_GEM_DOMAIN_GTT, 0);
128	}
129	query->curr_offset = 0;
130
131	radeon->query.current = query;
132
133	radeon->query.queryobj.dirty = GL_TRUE;
134	insert_at_tail(&radeon->query.not_flushed_head, query);
135
136}
137
138void radeonEmitQueryEnd(GLcontext *ctx)
139{
140	radeonContextPtr radeon = RADEON_CONTEXT(ctx);
141	struct radeon_query_object *query = radeon->query.current;
142
143	if (!query)
144		return;
145
146	if (query->emitted_begin == GL_FALSE)
147		return;
148
149	if (DDEBUG) fprintf(stderr, "%s: query id %d, bo %p, offset %d\n", __FUNCTION__, query->Base.Id, query->bo, query->curr_offset);
150
151	radeon_cs_space_check_with_bo(radeon->cmdbuf.cs,
152				      query->bo,
153				      0, RADEON_GEM_DOMAIN_GTT);
154
155	radeon->vtbl.emit_query_finish(radeon);
156}
157
158static void radeonEndQuery(GLcontext *ctx, struct gl_query_object *q)
159{
160	radeonContextPtr radeon = RADEON_CONTEXT(ctx);
161
162	if (DDEBUG) fprintf(stderr, "%s: query id %d\n", __FUNCTION__, q->Id);
163
164	if (radeon->dma.flush)
165		radeon->dma.flush(radeon->glCtx);
166	radeonEmitQueryEnd(ctx);
167
168	radeon->query.current = NULL;
169}
170
171/**
172 * TODO:
173 * should check if bo is idle, bo there's no interface to do it
174 * just wait for result now
175 */
176static void radeonCheckQuery(GLcontext *ctx, struct gl_query_object *q)
177{
178	if (DDEBUG) fprintf(stderr, "%s: query id %d\n", __FUNCTION__, q->Id);
179
180	radeonWaitQuery(ctx, q);
181}
182
183void radeonInitQueryObjFunctions(struct dd_function_table *functions)
184{
185	functions->NewQueryObject = radeonNewQueryObject;
186	functions->DeleteQuery = radeonDeleteQuery;
187	functions->BeginQuery = radeonBeginQuery;
188	functions->EndQuery = radeonEndQuery;
189	functions->CheckQuery = radeonCheckQuery;
190	functions->WaitQuery = radeonWaitQuery;
191}
192
193int radeon_check_query_active(GLcontext *ctx, struct radeon_state_atom *atom)
194{
195	radeonContextPtr radeon = RADEON_CONTEXT(ctx);
196	struct radeon_query_object *query = radeon->query.current;
197
198	if (!query || query->emitted_begin)
199		return 0;
200	return atom->cmd_size;
201}
202
203void radeon_emit_queryobj(GLcontext *ctx, struct radeon_state_atom *atom)
204{
205	radeonContextPtr radeon = RADEON_CONTEXT(ctx);
206	BATCH_LOCALS(radeon);
207	int dwords;
208
209	dwords = (*atom->check) (ctx, atom);
210
211	BEGIN_BATCH_NO_AUTOSTATE(dwords);
212	OUT_BATCH_TABLE(atom->cmd, dwords);
213	END_BATCH();
214
215	radeon->query.current->emitted_begin = GL_TRUE;
216}
217