radeon_queryobj.c revision cefee4e327c92daa2f01b6de650a43eddd348063
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#include "radeon_debug.h" 30 31#include "main/imports.h" 32#include "main/simple_list.h" 33 34static void radeonQueryGetResult(GLcontext *ctx, struct gl_query_object *q) 35{ 36 radeonContextPtr radeon = RADEON_CONTEXT(ctx); 37 struct radeon_query_object *query = (struct radeon_query_object *)q; 38 uint32_t *result; 39 int i; 40 41 radeon_print(RADEON_STATE, RADEON_VERBOSE, 42 "%s: query id %d, result %d\n", 43 __FUNCTION__, query->Base.Id, (int) query->Base.Result); 44 45 radeon_bo_map(query->bo, GL_FALSE); 46 result = query->bo->ptr; 47 48 query->Base.Result = 0; 49 if (IS_R600_CLASS(radeon->radeonScreen)) { 50 /* ZPASS EVENT writes alternating qwords 51 * At query start we set the start offset to 0 and 52 * hw writes zpass start counts to qwords 0, 2, 4, 6. 53 * At query end we set the start offset to 8 and 54 * hw writes zpass end counts to qwords 1, 3, 5, 7. 55 * then we substract. MSB is the valid bit. 56 */ 57 for (i = 0; i < 16; i += 4) { 58 uint64_t start = (uint64_t)LE32_TO_CPU(result[i]) | 59 (uint64_t)LE32_TO_CPU(result[i + 1]) << 32; 60 uint64_t end = (uint64_t)LE32_TO_CPU(result[i + 2]) | 61 (uint64_t)LE32_TO_CPU(result[i + 3]) << 32; 62 if ((start & 0x8000000000000000) && (end & 0x8000000000000000)) { 63 uint64_t query_count = end - start; 64 query->Base.Result += query_count; 65 66 } 67 radeon_print(RADEON_STATE, RADEON_TRACE, 68 "%d start: %lx, end: %lx %ld\n", i, start, end, end - start); 69 } 70 } else { 71 for (i = 0; i < query->curr_offset/sizeof(uint32_t); ++i) { 72 query->Base.Result += LE32_TO_CPU(result[i]); 73 radeon_print(RADEON_STATE, RADEON_TRACE, "result[%d] = %d\n", i, LE32_TO_CPU(result[i])); 74 } 75 } 76 77 radeon_bo_unmap(query->bo); 78} 79 80static struct gl_query_object * radeonNewQueryObject(GLcontext *ctx, GLuint id) 81{ 82 struct radeon_query_object *query; 83 84 query = _mesa_calloc(sizeof(struct radeon_query_object)); 85 86 query->Base.Id = id; 87 query->Base.Result = 0; 88 query->Base.Active = GL_FALSE; 89 query->Base.Ready = GL_TRUE; 90 91 radeon_print(RADEON_STATE, RADEON_VERBOSE,"%s: query id %d\n", __FUNCTION__, query->Base.Id); 92 93 return &query->Base; 94} 95 96static void radeonDeleteQuery(GLcontext *ctx, struct gl_query_object *q) 97{ 98 struct radeon_query_object *query = (struct radeon_query_object *)q; 99 100 radeon_print(RADEON_STATE, RADEON_NORMAL, "%s: query id %d\n", __FUNCTION__, q->Id); 101 102 if (query->bo) { 103 radeon_bo_unref(query->bo); 104 } 105 106 _mesa_free(query); 107} 108 109static void radeonWaitQuery(GLcontext *ctx, struct gl_query_object *q) 110{ 111 radeonContextPtr radeon = RADEON_CONTEXT(ctx); 112 struct radeon_query_object *query = (struct radeon_query_object *)q; 113 114 /* If the cmdbuf with packets for this query hasn't been flushed yet, do it now */ 115 if (radeon_bo_is_referenced_by_cs(query->bo, radeon->cmdbuf.cs)) 116 ctx->Driver.Flush(ctx); 117 118 radeon_print(RADEON_STATE, RADEON_VERBOSE, "%s: query id %d, bo %p, offset %d\n", __FUNCTION__, q->Id, query->bo, query->curr_offset); 119 120 radeonQueryGetResult(ctx, q); 121 122 query->Base.Ready = GL_TRUE; 123} 124 125 126static void radeonBeginQuery(GLcontext *ctx, struct gl_query_object *q) 127{ 128 radeonContextPtr radeon = RADEON_CONTEXT(ctx); 129 struct radeon_query_object *query = (struct radeon_query_object *)q; 130 131 radeon_print(RADEON_STATE, RADEON_NORMAL, "%s: query id %d\n", __FUNCTION__, q->Id); 132 133 assert(radeon->query.current == NULL); 134 135 if (radeon->dma.flush) 136 radeon->dma.flush(radeon->glCtx); 137 138 if (!query->bo) { 139 query->bo = radeon_bo_open(radeon->radeonScreen->bom, 0, RADEON_QUERY_PAGE_SIZE, RADEON_QUERY_PAGE_SIZE, RADEON_GEM_DOMAIN_GTT, 0); 140 } 141 query->curr_offset = 0; 142 143 radeon->query.current = query; 144 145 radeon->query.queryobj.dirty = GL_TRUE; 146 radeon->hw.is_dirty = GL_TRUE; 147} 148 149void radeonEmitQueryEnd(GLcontext *ctx) 150{ 151 radeonContextPtr radeon = RADEON_CONTEXT(ctx); 152 struct radeon_query_object *query = radeon->query.current; 153 154 if (!query) 155 return; 156 157 if (query->emitted_begin == GL_FALSE) 158 return; 159 160 radeon_print(RADEON_STATE, RADEON_NORMAL, "%s: query id %d, bo %p, offset %d\n", __FUNCTION__, query->Base.Id, query->bo, query->curr_offset); 161 162 radeon_cs_space_check_with_bo(radeon->cmdbuf.cs, 163 query->bo, 164 0, RADEON_GEM_DOMAIN_GTT); 165 166 radeon->vtbl.emit_query_finish(radeon); 167} 168 169static void radeonEndQuery(GLcontext *ctx, struct gl_query_object *q) 170{ 171 radeonContextPtr radeon = RADEON_CONTEXT(ctx); 172 173 radeon_print(RADEON_STATE, RADEON_NORMAL, "%s: query id %d\n", __FUNCTION__, q->Id); 174 175 if (radeon->dma.flush) 176 radeon->dma.flush(radeon->glCtx); 177 radeonEmitQueryEnd(ctx); 178 179 radeon->query.current = NULL; 180} 181 182static void radeonCheckQuery(GLcontext *ctx, struct gl_query_object *q) 183{ 184 radeon_print(RADEON_STATE, RADEON_TRACE, "%s: query id %d\n", __FUNCTION__, q->Id); 185 186#ifdef DRM_RADEON_GEM_BUSY 187 radeonContextPtr radeon = RADEON_CONTEXT(ctx); 188 189 if (radeon->radeonScreen->kernel_mm) { 190 struct radeon_query_object *query = (struct radeon_query_object *)q; 191 uint32_t domain; 192 193 /* Need to perform a flush, as per ARB_occlusion_query spec */ 194 if (radeon_bo_is_referenced_by_cs(query->bo, radeon->cmdbuf.cs)) { 195 ctx->Driver.Flush(ctx); 196 } 197 198 if (radeon_bo_is_busy(query->bo, &domain) == 0) { 199 radeonQueryGetResult(ctx, q); 200 query->Base.Ready = GL_TRUE; 201 } 202 } else { 203 radeonWaitQuery(ctx, q); 204 } 205#else 206 radeonWaitQuery(ctx, q); 207#endif 208} 209 210void radeonInitQueryObjFunctions(struct dd_function_table *functions) 211{ 212 functions->NewQueryObject = radeonNewQueryObject; 213 functions->DeleteQuery = radeonDeleteQuery; 214 functions->BeginQuery = radeonBeginQuery; 215 functions->EndQuery = radeonEndQuery; 216 functions->CheckQuery = radeonCheckQuery; 217 functions->WaitQuery = radeonWaitQuery; 218} 219 220int radeon_check_query_active(GLcontext *ctx, struct radeon_state_atom *atom) 221{ 222 radeonContextPtr radeon = RADEON_CONTEXT(ctx); 223 struct radeon_query_object *query = radeon->query.current; 224 225 if (!query || query->emitted_begin) 226 return 0; 227 return atom->cmd_size; 228} 229 230void radeon_emit_queryobj(GLcontext *ctx, struct radeon_state_atom *atom) 231{ 232 radeonContextPtr radeon = RADEON_CONTEXT(ctx); 233 BATCH_LOCALS(radeon); 234 int dwords; 235 236 dwords = (*atom->check) (ctx, atom); 237 238 BEGIN_BATCH_NO_AUTOSTATE(dwords); 239 OUT_BATCH_TABLE(atom->cmd, dwords); 240 END_BATCH(); 241 242 radeon->query.current->emitted_begin = GL_TRUE; 243} 244