/*
* 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 "main/simple_list.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",
__FUNCTION__, 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", __FUNCTION__, 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", __FUNCTION__, 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", __FUNCTION__, 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", __FUNCTION__, 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", __FUNCTION__, 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", __FUNCTION__, 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", __FUNCTION__, 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_NO_AUTOSTATE(dwords);
OUT_BATCH_TABLE(atom->cmd, dwords);
END_BATCH();
radeon->query.current->emitted_begin = GL_TRUE;
}