| /* |
| * Copyright © 2008-2009 Maciej Cencora <m.cencora@gmail.com> |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the next |
| * paragraph) shall be included in all copies or substantial portions of the |
| * Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
| * IN THE SOFTWARE. |
| * |
| * Authors: |
| * Maciej Cencora <m.cencora@gmail.com> |
| * |
| */ |
| #include "radeon_common.h" |
| #include "radeon_queryobj.h" |
| #include "radeon_debug.h" |
| |
| #include "main/imports.h" |
| |
| #include <inttypes.h> |
| |
| static void radeonQueryGetResult(struct gl_context *ctx, struct gl_query_object *q) |
| { |
| struct radeon_query_object *query = (struct radeon_query_object *)q; |
| uint32_t *result; |
| int i; |
| |
| radeon_print(RADEON_STATE, RADEON_VERBOSE, |
| "%s: query id %d, result %d\n", |
| __func__, query->Base.Id, (int) query->Base.Result); |
| |
| radeon_bo_map(query->bo, GL_FALSE); |
| result = query->bo->ptr; |
| |
| query->Base.Result = 0; |
| for (i = 0; i < query->curr_offset/sizeof(uint32_t); ++i) { |
| query->Base.Result += LE32_TO_CPU(result[i]); |
| radeon_print(RADEON_STATE, RADEON_TRACE, "result[%d] = %d\n", i, LE32_TO_CPU(result[i])); |
| } |
| |
| radeon_bo_unmap(query->bo); |
| } |
| |
| static struct gl_query_object * radeonNewQueryObject(struct gl_context *ctx, GLuint id) |
| { |
| struct radeon_query_object *query; |
| |
| query = calloc(1, sizeof(struct radeon_query_object)); |
| |
| query->Base.Id = id; |
| query->Base.Result = 0; |
| query->Base.Active = GL_FALSE; |
| query->Base.Ready = GL_TRUE; |
| |
| radeon_print(RADEON_STATE, RADEON_VERBOSE,"%s: query id %d\n", __func__, query->Base.Id); |
| |
| return &query->Base; |
| } |
| |
| static void radeonDeleteQuery(struct gl_context *ctx, struct gl_query_object *q) |
| { |
| struct radeon_query_object *query = (struct radeon_query_object *)q; |
| |
| radeon_print(RADEON_STATE, RADEON_NORMAL, "%s: query id %d\n", __func__, q->Id); |
| |
| if (query->bo) { |
| radeon_bo_unref(query->bo); |
| } |
| |
| free(query); |
| } |
| |
| static void radeonWaitQuery(struct gl_context *ctx, struct gl_query_object *q) |
| { |
| radeonContextPtr radeon = RADEON_CONTEXT(ctx); |
| struct radeon_query_object *query = (struct radeon_query_object *)q; |
| |
| /* If the cmdbuf with packets for this query hasn't been flushed yet, do it now */ |
| if (radeon_bo_is_referenced_by_cs(query->bo, radeon->cmdbuf.cs)) |
| ctx->Driver.Flush(ctx); |
| |
| radeon_print(RADEON_STATE, RADEON_VERBOSE, "%s: query id %d, bo %p, offset %d\n", __func__, q->Id, query->bo, query->curr_offset); |
| |
| radeonQueryGetResult(ctx, q); |
| |
| query->Base.Ready = GL_TRUE; |
| } |
| |
| |
| static void radeonBeginQuery(struct gl_context *ctx, struct gl_query_object *q) |
| { |
| radeonContextPtr radeon = RADEON_CONTEXT(ctx); |
| struct radeon_query_object *query = (struct radeon_query_object *)q; |
| |
| radeon_print(RADEON_STATE, RADEON_NORMAL, "%s: query id %d\n", __func__, q->Id); |
| |
| assert(radeon->query.current == NULL); |
| |
| if (radeon->dma.flush) |
| radeon->dma.flush(&radeon->glCtx); |
| |
| if (!query->bo) { |
| query->bo = radeon_bo_open(radeon->radeonScreen->bom, 0, RADEON_QUERY_PAGE_SIZE, RADEON_QUERY_PAGE_SIZE, RADEON_GEM_DOMAIN_GTT, 0); |
| } |
| query->curr_offset = 0; |
| |
| radeon->query.current = query; |
| |
| radeon->query.queryobj.dirty = GL_TRUE; |
| radeon->hw.is_dirty = GL_TRUE; |
| } |
| |
| void radeonEmitQueryEnd(struct gl_context *ctx) |
| { |
| radeonContextPtr radeon = RADEON_CONTEXT(ctx); |
| struct radeon_query_object *query = radeon->query.current; |
| |
| if (!query) |
| return; |
| |
| if (query->emitted_begin == GL_FALSE) |
| return; |
| |
| radeon_print(RADEON_STATE, RADEON_NORMAL, "%s: query id %d, bo %p, offset %d\n", __func__, query->Base.Id, query->bo, query->curr_offset); |
| |
| radeon_cs_space_check_with_bo(radeon->cmdbuf.cs, |
| query->bo, |
| 0, RADEON_GEM_DOMAIN_GTT); |
| |
| radeon->vtbl.emit_query_finish(radeon); |
| } |
| |
| static void radeonEndQuery(struct gl_context *ctx, struct gl_query_object *q) |
| { |
| radeonContextPtr radeon = RADEON_CONTEXT(ctx); |
| |
| radeon_print(RADEON_STATE, RADEON_NORMAL, "%s: query id %d\n", __func__, q->Id); |
| |
| if (radeon->dma.flush) |
| radeon->dma.flush(&radeon->glCtx); |
| radeonEmitQueryEnd(ctx); |
| |
| radeon->query.current = NULL; |
| } |
| |
| static void radeonCheckQuery(struct gl_context *ctx, struct gl_query_object *q) |
| { |
| radeon_print(RADEON_STATE, RADEON_TRACE, "%s: query id %d\n", __func__, q->Id); |
| \ |
| #ifdef DRM_RADEON_GEM_BUSY |
| radeonContextPtr radeon = RADEON_CONTEXT(ctx); |
| |
| struct radeon_query_object *query = (struct radeon_query_object *)q; |
| uint32_t domain; |
| |
| /* Need to perform a flush, as per ARB_occlusion_query spec */ |
| if (radeon_bo_is_referenced_by_cs(query->bo, radeon->cmdbuf.cs)) { |
| ctx->Driver.Flush(ctx); |
| } |
| |
| if (radeon_bo_is_busy(query->bo, &domain) == 0) { |
| radeonQueryGetResult(ctx, q); |
| query->Base.Ready = GL_TRUE; |
| } |
| #else |
| radeonWaitQuery(ctx, q); |
| #endif |
| } |
| |
| void radeonInitQueryObjFunctions(struct dd_function_table *functions) |
| { |
| functions->NewQueryObject = radeonNewQueryObject; |
| functions->DeleteQuery = radeonDeleteQuery; |
| functions->BeginQuery = radeonBeginQuery; |
| functions->EndQuery = radeonEndQuery; |
| functions->CheckQuery = radeonCheckQuery; |
| functions->WaitQuery = radeonWaitQuery; |
| } |
| |
| int radeon_check_query_active(struct gl_context *ctx, struct radeon_state_atom *atom) |
| { |
| radeonContextPtr radeon = RADEON_CONTEXT(ctx); |
| struct radeon_query_object *query = radeon->query.current; |
| |
| if (!query || query->emitted_begin) |
| return 0; |
| return atom->cmd_size; |
| } |
| |
| void radeon_emit_queryobj(struct gl_context *ctx, struct radeon_state_atom *atom) |
| { |
| radeonContextPtr radeon = RADEON_CONTEXT(ctx); |
| BATCH_LOCALS(radeon); |
| int dwords; |
| |
| dwords = atom->check(ctx, atom); |
| |
| BEGIN_BATCH(dwords); |
| OUT_BATCH_TABLE(atom->cmd, dwords); |
| END_BATCH(); |
| |
| radeon->query.current->emitted_begin = GL_TRUE; |
| } |