Based on initial patch from Stephan Schmid <stephan_2303@gmx.de>.
Basic idea is to dump the zpass count at the start and end of the query
and subtract to get the total number of visible fragments. HW writes
alternating qwords for up to 4 DBs. On the first pass, we start at
buffer address + 0; on the second pass, we start at buffer address + 8
(bytes). The resulting buffer at the end of the query looks like:
qw[0]: db0 start
qw[1]: db0 end
...
qw[6]: db3 start
qw[7]: db3 end
The MSB of each qword is the valid bit and the lower 63 bits are
the zpass count for that DB.
OQ on RV740 is disabled at the moment as it only seems to report
results for half of its DBs. This needs further investigation.
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
#include "r600_cmdbuf.h"
#include "r600_emit.h"
#include "radeon_bocs_wrapper.h"
+#include "radeon_queryobj.h"
#include "r700_state.h"
#include "r700_ioctl.h"
#include "utils.h"
#include "xmlpool.h" /* for symbolic values of enum-type options */
-/* hw_tcl_on derives from future_hw_tcl_on when its safe to change it. */
-int future_hw_tcl_on = 1;
-int hw_tcl_on = 1;
-
#define need_GL_VERSION_2_0
+#define need_GL_ARB_occlusion_query
#define need_GL_ARB_point_parameters
#define need_GL_ARB_vertex_program
#define need_GL_EXT_blend_equation_separate
/* *INDENT-OFF* */
{"GL_ARB_depth_texture", NULL},
{"GL_ARB_fragment_program", NULL},
+ {"GL_ARB_occlusion_query", GL_ARB_occlusion_query_functions},
{"GL_ARB_multitexture", NULL},
{"GL_ARB_point_parameters", GL_ARB_point_parameters_functions},
{"GL_ARB_shadow", NULL},
context->radeon.Fallback &= ~bit;
}
+static void r600_emit_query_finish(radeonContextPtr radeon)
+{
+ context_t *context = (context_t*) radeon;
+ BATCH_LOCALS(&context->radeon);
+
+ struct radeon_query_object *query = radeon->query.current;
+
+ BEGIN_BATCH_NO_AUTOSTATE(4 + 2);
+ R600_OUT_BATCH(CP_PACKET3(R600_IT_EVENT_WRITE, 2));
+ R600_OUT_BATCH(ZPASS_DONE);
+ R600_OUT_BATCH(query->curr_offset + 8); /* hw writes qwords */
+ R600_OUT_BATCH(0x00000000);
+ R600_OUT_BATCH_RELOC(VGT_EVENT_INITIATOR, query->bo, 0, 0, RADEON_GEM_DOMAIN_GTT, 0);
+ END_BATCH();
+ assert(query->curr_offset < RADEON_QUERY_PAGE_SIZE);
+ query->emitted_begin = GL_FALSE;
+}
+
static void r600_init_vtbl(radeonContextPtr radeon)
{
radeon->vtbl.get_lock = r600_get_lock;
radeon->vtbl.swtcl_flush = NULL;
radeon->vtbl.pre_emit_atoms = r600_vtbl_pre_emit_atoms;
radeon->vtbl.fallback = r600_fallback;
+ radeon->vtbl.emit_query_finish = r600_emit_query_finish;
}
static void r600InitConstValues(GLcontext *ctx, radeonScreenPtr screen)
{
_mesa_enable_extension(ctx, "GL_EXT_texture_compression_s3tc");
}
+
+ /* XXX: RV740 only seems to report results from half of its DBs */
+ if (r600->radeon.radeonScreen->chip_family == CHIP_FAMILY_RV740)
+ _mesa_disable_extension(ctx, "GL_ARB_occlusion_query");
}
/* Create the device specific rendering context.
r700InitStateFuncs(&functions);
r600InitTextureFuncs(&functions);
r700InitShaderFuncs(&functions);
+ radeonInitQueryObjFunctions(&functions);
r700InitIoctlFuncs(&functions);
radeonInitBufferObjectFuncs(&functions);
COMMIT_BATCH();
}
+static void r700SendQueryBegin(GLcontext *ctx, struct radeon_state_atom *atom)
+{
+ radeonContextPtr radeon = RADEON_CONTEXT(ctx);
+ struct radeon_query_object *query = radeon->query.current;
+ BATCH_LOCALS(radeon);
+ radeon_print(RADEON_STATE, RADEON_VERBOSE, "%s\n", __func__);
+
+ /* clear the buffer */
+ radeon_bo_map(query->bo, GL_FALSE);
+ memset(query->bo->ptr, 0, 4 * 2 * sizeof(uint64_t)); /* 4 DBs, 2 qwords each */
+ radeon_bo_unmap(query->bo);
+
+ radeon_cs_space_check_with_bo(radeon->cmdbuf.cs,
+ query->bo,
+ 0, RADEON_GEM_DOMAIN_GTT);
+
+ BEGIN_BATCH_NO_AUTOSTATE(4 + 2);
+ R600_OUT_BATCH(CP_PACKET3(R600_IT_EVENT_WRITE, 2));
+ R600_OUT_BATCH(ZPASS_DONE);
+ R600_OUT_BATCH(query->curr_offset); /* hw writes qwords */
+ R600_OUT_BATCH(0x00000000);
+ R600_OUT_BATCH_RELOC(VGT_EVENT_INITIATOR, query->bo, 0, 0, RADEON_GEM_DOMAIN_GTT, 0);
+ END_BATCH();
+ query->emitted_begin = GL_TRUE;
+}
+
static int check_always(GLcontext *ctx, struct radeon_state_atom *atom)
{
return atom->cmd_size;
return count;
}
+static int check_queryobj(GLcontext *ctx, struct radeon_state_atom *atom)
+{
+ radeonContextPtr radeon = RADEON_CONTEXT(ctx);
+ struct radeon_query_object *query = radeon->query.current;
+ int count;
+
+ if (!query || query->emitted_begin)
+ count = 0;
+ else
+ count = atom->cmd_size;
+ radeon_print(RADEON_STATE, RADEON_TRACE, "%s %d\n", __func__, count);
+ return count;
+}
+
#define ALLOC_STATE( ATOM, CHK, SZ, EMIT ) \
do { \
context->atoms.ATOM.cmd_size = (SZ); \
insert_at_tail(&context->radeon.hw.atomlist, &context->atoms.ATOM); \
} while (0)
+static void r600_init_query_stateobj(radeonContextPtr radeon, int SZ)
+{
+ radeon->query.queryobj.cmd_size = (SZ);
+ radeon->query.queryobj.cmd = NULL;
+ radeon->query.queryobj.name = "queryobj";
+ radeon->query.queryobj.idx = 0;
+ radeon->query.queryobj.check = check_queryobj;
+ radeon->query.queryobj.dirty = GL_FALSE;
+ radeon->query.queryobj.emit = r700SendQueryBegin;
+ radeon->hw.max_state_size += (SZ);
+ insert_at_tail(&radeon->hw.atomlist, &radeon->query.queryobj);
+}
+
void r600InitAtoms(context_t *context)
{
radeon_print(RADEON_STATE, RADEON_NORMAL, "%s %p\n", __func__, context);
ALLOC_STATE(tx, tx, (R700_TEXTURE_NUMBERUNITS * 20), r700SendTexState);
ALLOC_STATE(tx_smplr, tx, (R700_TEXTURE_NUMBERUNITS * 5), r700SendTexSamplerState);
ALLOC_STATE(tx_brdr_clr, tx, (R700_TEXTURE_NUMBERUNITS * 6), r700SendTexBorderColorState);
+ r600_init_query_stateobj(&context->radeon, 6 * 2);
context->radeon.hw.is_dirty = GL_TRUE;
context->radeon.hw.all_dirty = GL_TRUE;
SETfield(r700->DB_RENDER_OVERRIDE.u32All, FORCE_DISABLE, FORCE_HIZ_ENABLE_shift, FORCE_HIZ_ENABLE_mask);
SETfield(r700->DB_RENDER_OVERRIDE.u32All, FORCE_DISABLE, FORCE_HIS_ENABLE0_shift, FORCE_HIS_ENABLE0_mask);
SETfield(r700->DB_RENDER_OVERRIDE.u32All, FORCE_DISABLE, FORCE_HIS_ENABLE1_shift, FORCE_HIS_ENABLE1_mask);
+ SETbit(r700->DB_RENDER_OVERRIDE.u32All, NOOP_CULL_DISABLE_bit);
r700->DB_ALPHA_TO_MASK.u32All = 0;
SETfield(r700->DB_ALPHA_TO_MASK.u32All, 2, ALPHA_TO_MASK_OFFSET0_shift, ALPHA_TO_MASK_OFFSET0_mask);
static void radeonQueryGetResult(GLcontext *ctx, struct gl_query_object *q)
{
+ radeonContextPtr radeon = RADEON_CONTEXT(ctx);
struct radeon_query_object *query = (struct radeon_query_object *)q;
- uint32_t *result;
int i;
radeon_print(RADEON_STATE, RADEON_VERBOSE,
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 += result[i];
- radeon_print(RADEON_STATE, RADEON_TRACE, "result[%d] = %d\n", i, result[i]);
+ if (IS_R600_CLASS(radeon->radeonScreen)) {
+ /* ZPASS EVENT writes alternating qwords
+ * At query start we set the start offset to 0 and
+ * hw writes zpass start counts to qwords 0, 2, 4, 6.
+ * At query end we set the start offset to 8 and
+ * hw writes zpass end counts to qwords 1, 3, 5, 7.
+ * then we substract. MSB is the valid bit.
+ */
+ uint64_t *result = query->bo->ptr;
+ for (i = 0; i < 8; i += 2) {
+ uint64_t start = result[i];
+ uint64_t end = result[i + 1];
+ if ((start & 0x8000000000000000) && (end & 0x8000000000000000)) {
+ uint64_t query_count = end - start;
+ query->Base.Result += query_count;
+
+ }
+ radeon_print(RADEON_STATE, RADEON_TRACE,
+ "%d start: %lx, end: %lx %ld\n", i, start, end, end - start);
+ }
+ } else {
+ uint32_t *result = query->bo->ptr;
+ for (i = 0; i < query->curr_offset/sizeof(uint32_t); ++i) {
+ query->Base.Result += result[i];
+ radeon_print(RADEON_STATE, RADEON_TRACE, "result[%d] = %d\n", i, result[i]);
+ }
}
radeon_bo_unmap(query->bo);