#include <stdint.h>
#include <stdio.h>
+#include <util/u_double_list.h>
+#include <pipe/p_compiler.h>
#define RADEON_CTX_MAX_PM4 (64 * 1024 / 4)
unsigned *offset_block_id;
};
+/*
+ * relocation
+ */
#pragma pack(1)
struct r600_reloc {
uint32_t handle;
};
#pragma pack()
-struct radeon_bo;
+/*
+ * query
+ */
+struct r600_query {
+ u64 result;
+ /* The kind of query. Currently only OQ is supported. */
+ unsigned type;
+ /* How many results have been written, in dwords. It's incremented
+ * after end_query and flush. */
+ unsigned num_results;
+ /* if we've flushed the query */
+ unsigned state;
+ /* The buffer where query results are stored. */
+ struct radeon_ws_bo *buffer;
+ unsigned buffer_size;
+ /* linked list of queries */
+ struct list_head list;
+};
+
+#define R600_QUERY_STATE_STARTED (1 << 0)
+#define R600_QUERY_STATE_ENDED (1 << 1)
+#define R600_QUERY_STATE_SUSPENDED (1 << 2)
+
struct r600_context {
struct radeon *radeon;
struct r600_reloc *reloc;
struct radeon_bo **bo;
u32 *pm4;
+ struct list_head query_list;
};
struct r600_draw {
void r600_context_dump_bof(struct r600_context *ctx, const char *file);
void r600_context_draw(struct r600_context *ctx, const struct r600_draw *draw);
+struct r600_query *r600_context_query_create(struct r600_context *ctx, unsigned query_type);
+void r600_context_query_destroy(struct r600_context *ctx, struct r600_query *query);
+boolean r600_context_query_result(struct r600_context *ctx,
+ struct r600_query *query,
+ boolean wait, void *vresult);
+void r600_query_begin(struct r600_context *ctx, struct r600_query *query);
+void r600_query_end(struct r600_context *ctx, struct r600_query *query);
+
#endif
r600_context_pipe_state_set(&rctx->ctx, rstate);
}
+static struct pipe_query *r600_create_query(struct pipe_context *ctx, unsigned query_type)
+{
+ struct r600_pipe_context *rctx = (struct r600_pipe_context *)ctx;
+
+ return (struct pipe_query*)r600_context_query_create(&rctx->ctx, query_type);
+}
+
+static void r600_destroy_query(struct pipe_context *ctx, struct pipe_query *query)
+{
+ struct r600_pipe_context *rctx = (struct r600_pipe_context *)ctx;
+
+ r600_context_query_destroy(&rctx->ctx, (struct r600_query *)query);
+}
+
+static void r600_begin_query(struct pipe_context *ctx, struct pipe_query *query)
+{
+ struct r600_pipe_context *rctx = (struct r600_pipe_context *)ctx;
+
+ r600_query_begin(&rctx->ctx, (struct r600_query *)query);
+}
+
+static void r600_end_query(struct pipe_context *ctx, struct pipe_query *query)
+{
+ struct r600_pipe_context *rctx = (struct r600_pipe_context *)ctx;
+
+ r600_query_end(&rctx->ctx, (struct r600_query *)query);
+}
+
+static boolean r600_get_query_result(struct pipe_context *ctx,
+ struct pipe_query *query,
+ boolean wait, void *vresult)
+{
+ struct r600_pipe_context *rctx = (struct r600_pipe_context *)ctx;
+
+ return r600_context_query_result(&rctx->ctx, (struct r600_query *)query, wait, vresult);
+}
+
+static void r600_init_query_functions2(struct r600_pipe_context *rctx)
+{
+ rctx->context.create_query = r600_create_query;
+ rctx->context.destroy_query = r600_destroy_query;
+ rctx->context.begin_query = r600_begin_query;
+ rctx->context.end_query = r600_end_query;
+ rctx->context.get_query_result = r600_get_query_result;
+}
+
static struct pipe_context *r600_create_context2(struct pipe_screen *screen, void *priv)
{
struct r600_pipe_context *rctx = CALLOC_STRUCT(r600_pipe_context);
rctx->radeon = rscreen->radeon;
r600_init_blit_functions2(rctx);
+ r600_init_query_functions2(rctx);
r600_init_state_functions2(rctx);
r600_init_context_resource_functions2(rctx);
unsigned radeon_ws_bo_get_handle(struct radeon_ws_bo *pb_bo);
+/* queries */
+static void r600_context_queries_suspend(struct r600_context *ctx);
+static void r600_context_queries_resume(struct r600_context *ctx);
+
static int r600_group_id_register_offset(unsigned offset)
{
if (offset >= R600_CONFIG_REG_OFFSET && offset < R600_CONFIG_REG_END) {
memset(ctx, 0, sizeof(struct r600_context));
ctx->radeon = radeon;
+ LIST_INITHEAD(&ctx->query_list);
/* initialize groups */
r = r600_group_init(&ctx->groups[R600_GROUP_CONFIG], R600_CONFIG_REG_OFFSET, R600_CONFIG_REG_END);
if (r) {
R600_ERR("context is too big to be scheduled\n");
return;
}
- /* Ok we enough room to copy packet */
+ /* enough room to copy packet */
r600_context_group_emit_dirty(ctx, &ctx->groups[R600_GROUP_CONFIG], PKT3_SET_CONFIG_REG);
r600_context_group_emit_dirty(ctx, &ctx->groups[R600_GROUP_CONTEXT], PKT3_SET_CONTEXT_REG);
r600_context_group_emit_dirty(ctx, &ctx->groups[R600_GROUP_ALU_CONST], PKT3_SET_ALU_CONST);
}
ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_EVENT_WRITE, 0);
ctx->pm4[ctx->pm4_cdwords++] = EVENT_TYPE_CACHE_FLUSH_AND_INV_EVENT;
+ /* all dirty state have been scheduled in current cs */
+ ctx->pm4_dirty_cdwords = 0;
}
void r600_context_flush(struct r600_context *ctx)
if (!ctx->pm4_cdwords)
return;
+ /* suspend queries */
+ r600_context_queries_suspend(ctx);
+
#if 1
/* emit cs */
drmib.num_chunks = 2;
ctx->creloc = 0;
ctx->pm4_dirty_cdwords = 0;
ctx->pm4_cdwords = 0;
+
+ /* resume queries */
+ r600_context_queries_resume(ctx);
+
+ /* set all valid group as dirty so they get reemited on
+ * next draw command
+ */
for (int i = 0; i < ctx->ngroups; i++) {
for (int j = 0; j < ctx->groups[i].nblocks; j++) {
/* mark enabled block as dirty */
bof_decref(device_id);
bof_decref(root);
}
+
+static void r600_query_result(struct r600_context *ctx, struct r600_query *query)
+{
+ u64 start, end;
+ u32 *results;
+ int i;
+
+ results = radeon_ws_bo_map(ctx->radeon, query->buffer, 0, NULL);
+ for (i = 0; i < query->num_results; i += 4) {
+ start = (u64)results[i] | (u64)results[i + 1] << 32;
+ end = (u64)results[i + 2] | (u64)results[i + 3] << 32;
+ if ((start & 0x8000000000000000UL) && (end & 0x8000000000000000UL)) {
+ query->result += end - start;
+ }
+ }
+ radeon_ws_bo_unmap(ctx->radeon, query->buffer);
+ query->num_results = 0;
+}
+
+void r600_query_begin(struct r600_context *ctx, struct r600_query *query)
+{
+ /* query request needs 6 dwords for begin + 6 dwords for end */
+ if ((12 + ctx->pm4_cdwords) > ctx->pm4_ndwords) {
+ /* need to flush */
+ r600_context_flush(ctx);
+ }
+
+ /* if query buffer is full force a flush */
+ if (query->num_results >= ((query->buffer_size >> 2) - 2)) {
+ r600_context_flush(ctx);
+ r600_query_result(ctx, query);
+ }
+
+ /* emit begin query */
+ ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_EVENT_WRITE, 2);
+ ctx->pm4[ctx->pm4_cdwords++] = EVENT_TYPE_ZPASS_DONE;
+ ctx->pm4[ctx->pm4_cdwords++] = query->num_results;
+ ctx->pm4[ctx->pm4_cdwords++] = 0;
+ ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_NOP, 0);
+ ctx->pm4[ctx->pm4_cdwords++] = 0;
+ r600_context_bo_reloc(ctx, &ctx->pm4[ctx->pm4_cdwords - 1], radeon_bo_pb_get_bo(query->buffer->pb));
+
+ query->state |= R600_QUERY_STATE_STARTED;
+ query->state ^= R600_QUERY_STATE_ENDED;
+}
+
+void r600_query_end(struct r600_context *ctx, struct r600_query *query)
+{
+ /* emit begin query */
+ ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_EVENT_WRITE, 2);
+ ctx->pm4[ctx->pm4_cdwords++] = EVENT_TYPE_ZPASS_DONE;
+ ctx->pm4[ctx->pm4_cdwords++] = query->num_results + 8;
+ ctx->pm4[ctx->pm4_cdwords++] = 0;
+ ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_NOP, 0);
+ ctx->pm4[ctx->pm4_cdwords++] = 0;
+ r600_context_bo_reloc(ctx, &ctx->pm4[ctx->pm4_cdwords - 1], radeon_bo_pb_get_bo(query->buffer->pb));
+
+ query->num_results += 16;
+ query->state ^= R600_QUERY_STATE_STARTED;
+ query->state |= R600_QUERY_STATE_ENDED;
+}
+
+struct r600_query *r600_context_query_create(struct r600_context *ctx, unsigned query_type)
+{
+ struct r600_query *query;
+
+ if (query_type != PIPE_QUERY_OCCLUSION_COUNTER)
+ return NULL;
+
+ query = calloc(1, sizeof(struct r600_query));
+ if (query == NULL)
+ return NULL;
+
+ query->type = query_type;
+ query->buffer_size = 4096;
+
+ query->buffer = radeon_ws_bo(ctx->radeon, query->buffer_size, 1, 0);
+ if (!query->buffer) {
+ free(query);
+ return NULL;
+ }
+
+ LIST_ADDTAIL(&query->list, &ctx->query_list);
+
+ return query;
+}
+
+void r600_context_query_destroy(struct r600_context *ctx, struct r600_query *query)
+{
+ radeon_ws_bo_reference(ctx->radeon, &query->buffer, NULL);
+ LIST_DEL(&query->list);
+ free(query);
+}
+
+boolean r600_context_query_result(struct r600_context *ctx,
+ struct r600_query *query,
+ boolean wait, void *vresult)
+{
+ uint64_t *result = (uint64_t*)vresult;
+
+ if (query->num_results) {
+ r600_context_flush(ctx);
+ }
+ r600_query_result(ctx, query);
+ *result = query->result;
+ query->result = 0;
+ return TRUE;
+}
+
+static void r600_context_queries_suspend(struct r600_context *ctx)
+{
+ struct r600_query *query;
+
+ LIST_FOR_EACH_ENTRY(query, &ctx->query_list, list) {
+ if (query->state & R600_QUERY_STATE_STARTED) {
+ r600_query_end(ctx, query);
+ query->state |= R600_QUERY_STATE_SUSPENDED;
+ }
+ }
+}
+
+static void r600_context_queries_resume(struct r600_context *ctx)
+{
+ struct r600_query *query;
+
+ LIST_FOR_EACH_ENTRY(query, &ctx->query_list, list) {
+ if (query->state & R600_QUERY_STATE_SUSPENDED) {
+ r600_query_begin(ctx, query);
+ query->state ^= R600_QUERY_STATE_SUSPENDED;
+ }
+ }
+}