#include "pipe/p_config.h"
#if defined(PIPE_OS_UNIX)
+# include <time.h> /* timeval */
# include <sys/time.h> /* timeval */
#elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
# include <windows.h>
}
+uint64_t
+os_time_get_nano(void)
+{
+#if defined(PIPE_OS_UNIX)
+ struct timespec tv;
+ clock_gettime(CLOCK_REALTIME, &tv);
+ return tv.tv_nsec + tv.tv_sec * 1000000000LL;
+
+#elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
+ return os_time_get() * 1000;
+#endif
+}
+
+
#if defined(PIPE_SUBSYSTEM_WINDOWS_USER)
void
os_time_get(void);
+/*
+ * Get the current time in nanoseconds from an unknown base.
+ */
+uint64_t
+os_time_get_nano(void);
+
+
/*
* Sleep.
*/
unsigned dirty; /**< Mask of LP_NEW_x flags */
- int active_query_count;
+ unsigned active_occlusion_query;
/** Mapped vertex buffers */
ubyte *mapped_vbuffer[PIPE_MAX_ATTRIBS];
#include "draw/draw_context.h"
#include "pipe/p_defines.h"
#include "util/u_memory.h"
+#include "os/os_time.h"
#include "lp_context.h"
#include "lp_flush.h"
#include "lp_fence.h"
{
struct llvmpipe_query *pq;
- assert(type == PIPE_QUERY_OCCLUSION_COUNTER);
+ assert(type < PIPE_QUERY_TYPES);
pq = CALLOC_STRUCT( llvmpipe_query );
+ if (pq) {
+ pq->type = type;
+ }
+
return (struct pipe_query *) pq;
}
if (!lp_fence_signalled(pq->fence)) {
if (!lp_fence_issued(pq->fence))
llvmpipe_flush(pipe, NULL, __FUNCTION__);
-
+
if (!wait)
return FALSE;
/* Sum the results from each of the threads:
*/
*result = 0;
- for (i = 0; i < LP_MAX_THREADS; i++) {
- *result += pq->count[i];
+
+ switch (pq->type) {
+ case PIPE_QUERY_OCCLUSION_COUNTER:
+ for (i = 0; i < LP_MAX_THREADS; i++) {
+ *result += pq->count[i];
+ }
+ break;
+ case PIPE_QUERY_TIME_ELAPSED:
+ for (i = 0; i < LP_MAX_THREADS; i++) {
+ if (pq->count[i] > *result) {
+ *result = pq->count[i];
+ }
+ }
+ break;
+ case PIPE_QUERY_TIMESTAMP:
+ for (i = 0; i < LP_MAX_THREADS; i++) {
+ if (pq->count[i] > *result) {
+ *result = pq->count[i];
+ }
+ if (*result == 0)
+ *result = os_time_get_nano();
+ }
+ break;
+ default:
+ assert(0);
+ break;
}
return TRUE;
memset(pq->count, 0, sizeof(pq->count));
lp_setup_begin_query(llvmpipe->setup, pq);
- llvmpipe->active_query_count++;
- llvmpipe->dirty |= LP_NEW_QUERY;
+ if (pq->type == PIPE_QUERY_OCCLUSION_COUNTER) {
+ llvmpipe->active_occlusion_query = TRUE;
+ llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;
+ }
}
lp_setup_end_query(llvmpipe->setup, pq);
- assert(llvmpipe->active_query_count);
- llvmpipe->active_query_count--;
- llvmpipe->dirty |= LP_NEW_QUERY;
+ if (pq->type == PIPE_QUERY_OCCLUSION_COUNTER) {
+ assert(llvmpipe->active_occlusion_query);
+ llvmpipe->active_occlusion_query = FALSE;
+ llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;
+ }
}
boolean
struct llvmpipe_query {
- uint64_t count[LP_MAX_THREADS]; /**< a counter for each thread */
- struct lp_fence *fence; /* fence from last scene this was binned in */
+ uint64_t count[LP_MAX_THREADS]; /* a counter for each thread */
+ struct lp_fence *fence; /* fence from last scene this was binned in */
+ unsigned type; /* PIPE_QUERY_* */
};
#include "util/u_surface.h"
#include "util/u_pack_color.h"
+#include "os/os_time.h"
+
#include "lp_scene_queue.h"
#include "lp_debug.h"
#include "lp_fence.h"
{
struct llvmpipe_query *pq = arg.query_obj;
- assert(task->query == NULL);
- task->vis_counter = 0;
- task->query = pq;
+ assert(task->query[pq->type] == NULL);
+
+ switch (pq->type) {
+ case PIPE_QUERY_OCCLUSION_COUNTER:
+ task->vis_counter = 0;
+ break;
+ case PIPE_QUERY_TIME_ELAPSED:
+ task->query_start = os_time_get_nano();
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ task->query[pq->type] = pq;
}
lp_rast_end_query(struct lp_rasterizer_task *task,
const union lp_rast_cmd_arg arg)
{
- assert(task->query);
- if (task->query) {
- task->query->count[task->thread_index] += task->vis_counter;
- task->query = NULL;
+ struct llvmpipe_query *pq = arg.query_obj;
+ assert(task->query[pq->type] == pq || pq->type == PIPE_QUERY_TIMESTAMP);
+
+ switch (pq->type) {
+ case PIPE_QUERY_OCCLUSION_COUNTER:
+ pq->count[task->thread_index] += task->vis_counter;
+ break;
+ case PIPE_QUERY_TIME_ELAPSED:
+ pq->count[task->thread_index] = os_time_get_nano() - task->query_start;
+ break;
+ case PIPE_QUERY_TIMESTAMP:
+ pq->count[task->thread_index] = os_time_get_nano();
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ if (task->query[pq->type] == pq) {
+ task->query[pq->type] = NULL;
}
}
static void
lp_rast_tile_end(struct lp_rasterizer_task *task)
{
- if (task->query) {
- union lp_rast_cmd_arg dummy = {0};
- lp_rast_end_query(task, dummy);
+ unsigned i;
+
+ for (i = 0; i < PIPE_QUERY_TYPES; ++i) {
+ if (task->query[i]) {
+ lp_rast_end_query(task, lp_rast_arg_query(task->query[i]));
+ }
}
/* debug */
/* occlude counter for visiable pixels */
uint32_t vis_counter;
- struct llvmpipe_query *query;
+ uint64_t query_start;
+ struct llvmpipe_query *query[PIPE_QUERY_TYPES];
pipe_semaphore work_ready;
pipe_semaphore work_done;
#include "draw/draw_context.h"
#include "gallivm/lp_bld_type.h"
+#include "os/os_time.h"
#include "lp_texture.h"
#include "lp_fence.h"
#include "lp_jit.h"
case PIPE_CAP_OCCLUSION_QUERY:
return 1;
case PIPE_CAP_TIMER_QUERY:
- return 0;
+ case PIPE_CAP_QUERY_TIMESTAMP:
+ return 1;
case PIPE_CAP_TEXTURE_MIRROR_CLAMP:
return 1;
case PIPE_CAP_TEXTURE_SHADOW_MAP:
case PIPE_CAP_CONSTANT_BUFFER_OFFSET_ALIGNMENT:
return 16;
case PIPE_CAP_START_INSTANCE:
- case PIPE_CAP_QUERY_TIMESTAMP:
case PIPE_CAP_TEXTURE_MULTISAMPLE:
case PIPE_CAP_MIN_MAP_BUFFER_ALIGNMENT:
case PIPE_CAP_CUBE_MAP_ARRAY:
return TRUE;
}
-
+static uint64_t
+llvmpipe_get_timestamp(struct pipe_screen *_screen)
+{
+ return os_time_get_nano();
+}
/**
* Create a new pipe_screen object
screen->base.fence_signalled = llvmpipe_fence_signalled;
screen->base.fence_finish = llvmpipe_fence_finish;
+ screen->base.get_timestamp = llvmpipe_get_timestamp;
+
llvmpipe_init_screen_resource_funcs(&screen->base);
lp_jit_screen_init(screen);
}
}
- if (setup->active_query) {
- ok = lp_scene_bin_everywhere( scene,
- LP_RAST_OP_BEGIN_QUERY,
- lp_rast_arg_query(setup->active_query) );
- if (!ok)
- return FALSE;
+ for (i = 0; i < PIPE_QUERY_TYPES; ++i) {
+ if (setup->active_query[i]) {
+ ok = lp_scene_bin_everywhere( scene,
+ LP_RAST_OP_BEGIN_QUERY,
+ lp_rast_arg_query(setup->active_query[i]) );
+ if (!ok)
+ return FALSE;
+ }
}
setup->clear.flags = 0;
struct llvmpipe_query *pq)
{
/* init the query to its beginning state */
- assert(setup->active_query == NULL);
+ assert(setup->active_query[pq->type] == NULL);
set_scene_state(setup, SETUP_ACTIVE, "begin_query");
- setup->active_query = pq;
+ setup->active_query[pq->type] = pq;
+
+ /* XXX: It is possible that a query is created before the scene
+ * has been created. This means that setup->scene == NULL resulting
+ * in the query not being binned and thus is ignored.
+ */
if (setup->scene) {
if (!lp_scene_bin_everywhere(setup->scene,
void
lp_setup_end_query(struct lp_setup_context *setup, struct llvmpipe_query *pq)
{
- union lp_rast_cmd_arg dummy = { 0 };
-
set_scene_state(setup, SETUP_ACTIVE, "end_query");
- assert(setup->active_query == pq);
- setup->active_query = NULL;
+ if (pq->type != PIPE_QUERY_TIMESTAMP) {
+ assert(setup->active_query[pq->type] == pq);
+ setup->active_query[pq->type] = NULL;
+ }
/* Setup will automatically re-issue any query which carried over a
* scene boundary, and the rasterizer automatically "ends" queries
if (!lp_scene_bin_everywhere(setup->scene,
LP_RAST_OP_END_QUERY,
- dummy)) {
+ lp_rast_arg_query(pq))) {
lp_setup_flush(setup, NULL, __FUNCTION__);
}
}
struct lp_scene *scene; /**< current scene being built */
struct lp_fence *last_fence;
- struct llvmpipe_query *active_query;
+ struct llvmpipe_query *active_query[PIPE_QUERY_TYPES];
boolean flatshade_first;
boolean ccw_is_frontface;
#define LP_NEW_SAMPLER_VIEW 0x800
#define LP_NEW_VERTEX 0x1000
#define LP_NEW_VS 0x2000
-#define LP_NEW_QUERY 0x4000
+#define LP_NEW_OCCLUSION_QUERY 0x4000
#define LP_NEW_BLEND_COLOR 0x8000
#define LP_NEW_GS 0x10000
#define LP_NEW_SO 0x20000
LP_NEW_RASTERIZER |
LP_NEW_SAMPLER |
LP_NEW_SAMPLER_VIEW |
- LP_NEW_QUERY))
+ LP_NEW_OCCLUSION_QUERY))
llvmpipe_update_fs( llvmpipe );
if (llvmpipe->dirty & (LP_NEW_FS |
/* alpha.ref_value is passed in jit_context */
key->flatshade = lp->rasterizer->flatshade;
- if (lp->active_query_count) {
+ if (lp->active_occlusion_query) {
key->occlusion_count = TRUE;
}