Path: blob/21.2-virgl/src/gallium/drivers/freedreno/a6xx/fd6_query.c
4574 views
/*1* Copyright (C) 2017 Rob Clark <[email protected]>2* Copyright © 2018 Google, Inc.3*4* Permission is hereby granted, free of charge, to any person obtaining a5* copy of this software and associated documentation files (the "Software"),6* to deal in the Software without restriction, including without limitation7* the rights to use, copy, modify, merge, publish, distribute, sublicense,8* and/or sell copies of the Software, and to permit persons to whom the9* Software is furnished to do so, subject to the following conditions:10*11* The above copyright notice and this permission notice (including the next12* paragraph) shall be included in all copies or substantial portions of the13* Software.14*15* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR16* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,17* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL18* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER19* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,20* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE21* SOFTWARE.22*23* Authors:24* Rob Clark <[email protected]>25*/2627/* NOTE: see https://github.com/freedreno/freedreno/wiki/A5xx-Queries */2829#include "freedreno_query_acc.h"30#include "freedreno_resource.h"3132#include "fd6_context.h"33#include "fd6_emit.h"34#include "fd6_format.h"35#include "fd6_query.h"3637struct PACKED fd6_query_sample {38uint64_t start;39uint64_t result;40uint64_t stop;41};4243/* offset of a single field of an array of fd6_query_sample: */44#define query_sample_idx(aq, idx, field) \45fd_resource((aq)->prsc)->bo, \46(idx * sizeof(struct fd6_query_sample)) + \47offsetof(struct fd6_query_sample, field), \480, 04950/* offset of a single field of fd6_query_sample: */51#define query_sample(aq, field) query_sample_idx(aq, 0, field)5253/*54* Occlusion Query:55*56* OCCLUSION_COUNTER and OCCLUSION_PREDICATE differ only in how they57* interpret results58*/5960static void61occlusion_resume(struct fd_acc_query *aq, struct fd_batch *batch)62{63struct fd_ringbuffer *ring = batch->draw;6465OUT_PKT4(ring, REG_A6XX_RB_SAMPLE_COUNT_CONTROL, 1);66OUT_RING(ring, A6XX_RB_SAMPLE_COUNT_CONTROL_COPY);6768OUT_PKT4(ring, REG_A6XX_RB_SAMPLE_COUNT_ADDR, 2);69OUT_RELOC(ring, query_sample(aq, start));7071fd6_event_write(batch, ring, ZPASS_DONE, false);7273fd6_context(batch->ctx)->samples_passed_queries++;74}7576static void77occlusion_pause(struct fd_acc_query *aq, struct fd_batch *batch) assert_dt78{79struct fd_ringbuffer *ring = batch->draw;8081OUT_PKT7(ring, CP_MEM_WRITE, 4);82OUT_RELOC(ring, query_sample(aq, stop));83OUT_RING(ring, 0xffffffff);84OUT_RING(ring, 0xffffffff);8586OUT_PKT7(ring, CP_WAIT_MEM_WRITES, 0);8788OUT_PKT4(ring, REG_A6XX_RB_SAMPLE_COUNT_CONTROL, 1);89OUT_RING(ring, A6XX_RB_SAMPLE_COUNT_CONTROL_COPY);9091OUT_PKT4(ring, REG_A6XX_RB_SAMPLE_COUNT_ADDR, 2);92OUT_RELOC(ring, query_sample(aq, stop));9394fd6_event_write(batch, ring, ZPASS_DONE, false);9596/* To avoid stalling in the draw buffer, emit code the code to compute the97* counter delta in the epilogue ring.98*/99struct fd_ringbuffer *epilogue = fd_batch_get_epilogue(batch);100fd_wfi(batch, epilogue);101102/* result += stop - start: */103OUT_PKT7(epilogue, CP_MEM_TO_MEM, 9);104OUT_RING(epilogue, CP_MEM_TO_MEM_0_DOUBLE | CP_MEM_TO_MEM_0_NEG_C);105OUT_RELOC(epilogue, query_sample(aq, result)); /* dst */106OUT_RELOC(epilogue, query_sample(aq, result)); /* srcA */107OUT_RELOC(epilogue, query_sample(aq, stop)); /* srcB */108OUT_RELOC(epilogue, query_sample(aq, start)); /* srcC */109110fd6_context(batch->ctx)->samples_passed_queries--;111}112113static void114occlusion_counter_result(struct fd_acc_query *aq, void *buf,115union pipe_query_result *result)116{117struct fd6_query_sample *sp = buf;118result->u64 = sp->result;119}120121static void122occlusion_predicate_result(struct fd_acc_query *aq, void *buf,123union pipe_query_result *result)124{125struct fd6_query_sample *sp = buf;126result->b = !!sp->result;127}128129static const struct fd_acc_sample_provider occlusion_counter = {130.query_type = PIPE_QUERY_OCCLUSION_COUNTER,131.size = sizeof(struct fd6_query_sample),132.resume = occlusion_resume,133.pause = occlusion_pause,134.result = occlusion_counter_result,135};136137static const struct fd_acc_sample_provider occlusion_predicate = {138.query_type = PIPE_QUERY_OCCLUSION_PREDICATE,139.size = sizeof(struct fd6_query_sample),140.resume = occlusion_resume,141.pause = occlusion_pause,142.result = occlusion_predicate_result,143};144145static const struct fd_acc_sample_provider occlusion_predicate_conservative = {146.query_type = PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE,147.size = sizeof(struct fd6_query_sample),148.resume = occlusion_resume,149.pause = occlusion_pause,150.result = occlusion_predicate_result,151};152153/*154* Timestamp Queries:155*/156157static void158timestamp_resume(struct fd_acc_query *aq, struct fd_batch *batch)159{160struct fd_ringbuffer *ring = batch->draw;161162OUT_PKT7(ring, CP_EVENT_WRITE, 4);163OUT_RING(ring,164CP_EVENT_WRITE_0_EVENT(RB_DONE_TS) | CP_EVENT_WRITE_0_TIMESTAMP);165OUT_RELOC(ring, query_sample(aq, start));166OUT_RING(ring, 0x00000000);167168fd_reset_wfi(batch);169}170171static void172time_elapsed_pause(struct fd_acc_query *aq, struct fd_batch *batch) assert_dt173{174struct fd_ringbuffer *ring = batch->draw;175176OUT_PKT7(ring, CP_EVENT_WRITE, 4);177OUT_RING(ring,178CP_EVENT_WRITE_0_EVENT(RB_DONE_TS) | CP_EVENT_WRITE_0_TIMESTAMP);179OUT_RELOC(ring, query_sample(aq, stop));180OUT_RING(ring, 0x00000000);181182fd_reset_wfi(batch);183fd_wfi(batch, ring);184185/* result += stop - start: */186OUT_PKT7(ring, CP_MEM_TO_MEM, 9);187OUT_RING(ring, CP_MEM_TO_MEM_0_DOUBLE | CP_MEM_TO_MEM_0_NEG_C);188OUT_RELOC(ring, query_sample(aq, result)); /* dst */189OUT_RELOC(ring, query_sample(aq, result)); /* srcA */190OUT_RELOC(ring, query_sample(aq, stop)); /* srcB */191OUT_RELOC(ring, query_sample(aq, start)); /* srcC */192}193194static void195timestamp_pause(struct fd_acc_query *aq, struct fd_batch *batch)196{197/* We captured a timestamp in timestamp_resume(), nothing to do here. */198}199200/* timestamp logging for u_trace: */201static void202record_timestamp(struct fd_ringbuffer *ring, struct fd_bo *bo, unsigned offset)203{204OUT_PKT7(ring, CP_EVENT_WRITE, 4);205OUT_RING(ring,206CP_EVENT_WRITE_0_EVENT(RB_DONE_TS) | CP_EVENT_WRITE_0_TIMESTAMP);207OUT_RELOC(ring, bo, offset, 0, 0);208OUT_RING(ring, 0x00000000);209}210211static uint64_t212ticks_to_ns(uint64_t ts)213{214/* This is based on the 19.2MHz always-on rbbm timer.215*216* TODO we should probably query this value from kernel..217*/218return ts * (1000000000 / 19200000);219}220221static void222time_elapsed_accumulate_result(struct fd_acc_query *aq, void *buf,223union pipe_query_result *result)224{225struct fd6_query_sample *sp = buf;226result->u64 = ticks_to_ns(sp->result);227}228229static void230timestamp_accumulate_result(struct fd_acc_query *aq, void *buf,231union pipe_query_result *result)232{233struct fd6_query_sample *sp = buf;234result->u64 = ticks_to_ns(sp->start);235}236237static const struct fd_acc_sample_provider time_elapsed = {238.query_type = PIPE_QUERY_TIME_ELAPSED,239.always = true,240.size = sizeof(struct fd6_query_sample),241.resume = timestamp_resume,242.pause = time_elapsed_pause,243.result = time_elapsed_accumulate_result,244};245246/* NOTE: timestamp query isn't going to give terribly sensible results247* on a tiler. But it is needed by qapitrace profile heatmap. If you248* add in a binning pass, the results get even more non-sensical. So249* we just return the timestamp on the last tile and hope that is250* kind of good enough.251*/252253static const struct fd_acc_sample_provider timestamp = {254.query_type = PIPE_QUERY_TIMESTAMP,255.always = true,256.size = sizeof(struct fd6_query_sample),257.resume = timestamp_resume,258.pause = timestamp_pause,259.result = timestamp_accumulate_result,260};261262struct PACKED fd6_primitives_sample {263struct {264uint64_t emitted, generated;265} start[4], stop[4], result;266267uint64_t prim_start[16], prim_stop[16], prim_emitted;268};269270#define primitives_relocw(ring, aq, field) \271OUT_RELOC(ring, fd_resource((aq)->prsc)->bo, \272offsetof(struct fd6_primitives_sample, field), 0, 0);273#define primitives_reloc(ring, aq, field) \274OUT_RELOC(ring, fd_resource((aq)->prsc)->bo, \275offsetof(struct fd6_primitives_sample, field), 0, 0);276277#ifdef DEBUG_COUNTERS278static const unsigned counter_count = 10;279static const unsigned counter_base = REG_A6XX_RBBM_PRIMCTR_0_LO;280281static void282log_counters(struct fd6_primitives_sample *ps)283{284const char *labels[] = {285"vs_vertices_in", "vs_primitives_out",286"hs_vertices_in", "hs_patches_out",287"ds_vertices_in", "ds_primitives_out",288"gs_primitives_in", "gs_primitives_out",289"ras_primitives_in", "x",290};291292mesa_logd(" counter\t\tstart\t\t\tstop\t\t\tdiff");293for (int i = 0; i < ARRAY_SIZE(labels); i++) {294int register_idx = i + (counter_base - REG_A6XX_RBBM_PRIMCTR_0_LO) / 2;295mesa_logd(" RBBM_PRIMCTR_%d\t0x%016" PRIx64 "\t0x%016" PRIx64 "\t%" PRIi64296"\t%s",297register_idx, ps->prim_start[i], ps->prim_stop[i],298ps->prim_stop[i] - ps->prim_start[i], labels[register_idx]);299}300301mesa_logd(" so counts");302for (int i = 0; i < ARRAY_SIZE(ps->start); i++) {303mesa_logd(" CHANNEL %d emitted\t0x%016" PRIx64 "\t0x%016" PRIx64304"\t%" PRIi64,305i, ps->start[i].generated, ps->stop[i].generated,306ps->stop[i].generated - ps->start[i].generated);307mesa_logd(" CHANNEL %d generated\t0x%016" PRIx64 "\t0x%016" PRIx64308"\t%" PRIi64,309i, ps->start[i].emitted, ps->stop[i].emitted,310ps->stop[i].emitted - ps->start[i].emitted);311}312313mesa_logd("generated %" PRIu64 ", emitted %" PRIu64, ps->result.generated,314ps->result.emitted);315}316317#else318319static const unsigned counter_count = 1;320static const unsigned counter_base = REG_A6XX_RBBM_PRIMCTR_8_LO;321322static void323log_counters(struct fd6_primitives_sample *ps)324{325}326327#endif328329static void330primitives_generated_resume(struct fd_acc_query *aq,331struct fd_batch *batch) assert_dt332{333struct fd_ringbuffer *ring = batch->draw;334335fd_wfi(batch, ring);336337OUT_PKT7(ring, CP_REG_TO_MEM, 3);338OUT_RING(ring, CP_REG_TO_MEM_0_64B | CP_REG_TO_MEM_0_CNT(counter_count * 2) |339CP_REG_TO_MEM_0_REG(counter_base));340primitives_relocw(ring, aq, prim_start);341342fd6_event_write(batch, ring, START_PRIMITIVE_CTRS, false);343}344345static void346primitives_generated_pause(struct fd_acc_query *aq,347struct fd_batch *batch) assert_dt348{349struct fd_ringbuffer *ring = batch->draw;350351fd_wfi(batch, ring);352353/* snapshot the end values: */354OUT_PKT7(ring, CP_REG_TO_MEM, 3);355OUT_RING(ring, CP_REG_TO_MEM_0_64B | CP_REG_TO_MEM_0_CNT(counter_count * 2) |356CP_REG_TO_MEM_0_REG(counter_base));357primitives_relocw(ring, aq, prim_stop);358359fd6_event_write(batch, ring, STOP_PRIMITIVE_CTRS, false);360361/* result += stop - start: */362OUT_PKT7(ring, CP_MEM_TO_MEM, 9);363OUT_RING(ring, CP_MEM_TO_MEM_0_DOUBLE | CP_MEM_TO_MEM_0_NEG_C | 0x40000000);364primitives_relocw(ring, aq, result.generated);365primitives_reloc(ring, aq, prim_emitted);366primitives_reloc(ring, aq,367prim_stop[(REG_A6XX_RBBM_PRIMCTR_8_LO - counter_base) / 2])368primitives_reloc(369ring, aq, prim_start[(REG_A6XX_RBBM_PRIMCTR_8_LO - counter_base) / 2]);370}371372static void373primitives_generated_result(struct fd_acc_query *aq, void *buf,374union pipe_query_result *result)375{376struct fd6_primitives_sample *ps = buf;377378log_counters(ps);379380result->u64 = ps->result.generated;381}382383static const struct fd_acc_sample_provider primitives_generated = {384.query_type = PIPE_QUERY_PRIMITIVES_GENERATED,385.size = sizeof(struct fd6_primitives_sample),386.resume = primitives_generated_resume,387.pause = primitives_generated_pause,388.result = primitives_generated_result,389};390391static void392primitives_emitted_resume(struct fd_acc_query *aq,393struct fd_batch *batch) assert_dt394{395struct fd_ringbuffer *ring = batch->draw;396397fd_wfi(batch, ring);398OUT_PKT4(ring, REG_A6XX_VPC_SO_STREAM_COUNTS, 2);399primitives_relocw(ring, aq, start[0]);400401fd6_event_write(batch, ring, WRITE_PRIMITIVE_COUNTS, false);402}403404static void405primitives_emitted_pause(struct fd_acc_query *aq,406struct fd_batch *batch) assert_dt407{408struct fd_ringbuffer *ring = batch->draw;409410fd_wfi(batch, ring);411412OUT_PKT4(ring, REG_A6XX_VPC_SO_STREAM_COUNTS, 2);413primitives_relocw(ring, aq, stop[0]);414fd6_event_write(batch, ring, WRITE_PRIMITIVE_COUNTS, false);415416fd6_event_write(batch, batch->draw, CACHE_FLUSH_TS, true);417418/* result += stop - start: */419OUT_PKT7(ring, CP_MEM_TO_MEM, 9);420OUT_RING(ring, CP_MEM_TO_MEM_0_DOUBLE | CP_MEM_TO_MEM_0_NEG_C | 0x80000000);421primitives_relocw(ring, aq, result.emitted);422primitives_reloc(ring, aq, result.emitted);423primitives_reloc(ring, aq, stop[aq->base.index].emitted);424primitives_reloc(ring, aq, start[aq->base.index].emitted);425}426427static void428primitives_emitted_result(struct fd_acc_query *aq, void *buf,429union pipe_query_result *result)430{431struct fd6_primitives_sample *ps = buf;432433log_counters(ps);434435result->u64 = ps->result.emitted;436}437438static const struct fd_acc_sample_provider primitives_emitted = {439.query_type = PIPE_QUERY_PRIMITIVES_EMITTED,440.size = sizeof(struct fd6_primitives_sample),441.resume = primitives_emitted_resume,442.pause = primitives_emitted_pause,443.result = primitives_emitted_result,444};445446/*447* Performance Counter (batch) queries:448*449* Only one of these is active at a time, per design of the gallium450* batch_query API design. On perfcntr query tracks N query_types,451* each of which has a 'fd_batch_query_entry' that maps it back to452* the associated group and counter.453*/454455struct fd_batch_query_entry {456uint8_t gid; /* group-id */457uint8_t cid; /* countable-id within the group */458};459460struct fd_batch_query_data {461struct fd_screen *screen;462unsigned num_query_entries;463struct fd_batch_query_entry query_entries[];464};465466static void467perfcntr_resume(struct fd_acc_query *aq, struct fd_batch *batch) assert_dt468{469struct fd_batch_query_data *data = aq->query_data;470struct fd_screen *screen = data->screen;471struct fd_ringbuffer *ring = batch->draw;472473unsigned counters_per_group[screen->num_perfcntr_groups];474memset(counters_per_group, 0, sizeof(counters_per_group));475476fd_wfi(batch, ring);477478/* configure performance counters for the requested queries: */479for (unsigned i = 0; i < data->num_query_entries; i++) {480struct fd_batch_query_entry *entry = &data->query_entries[i];481const struct fd_perfcntr_group *g = &screen->perfcntr_groups[entry->gid];482unsigned counter_idx = counters_per_group[entry->gid]++;483484debug_assert(counter_idx < g->num_counters);485486OUT_PKT4(ring, g->counters[counter_idx].select_reg, 1);487OUT_RING(ring, g->countables[entry->cid].selector);488}489490memset(counters_per_group, 0, sizeof(counters_per_group));491492/* and snapshot the start values */493for (unsigned i = 0; i < data->num_query_entries; i++) {494struct fd_batch_query_entry *entry = &data->query_entries[i];495const struct fd_perfcntr_group *g = &screen->perfcntr_groups[entry->gid];496unsigned counter_idx = counters_per_group[entry->gid]++;497const struct fd_perfcntr_counter *counter = &g->counters[counter_idx];498499OUT_PKT7(ring, CP_REG_TO_MEM, 3);500OUT_RING(ring, CP_REG_TO_MEM_0_64B |501CP_REG_TO_MEM_0_REG(counter->counter_reg_lo));502OUT_RELOC(ring, query_sample_idx(aq, i, start));503}504}505506static void507perfcntr_pause(struct fd_acc_query *aq, struct fd_batch *batch) assert_dt508{509struct fd_batch_query_data *data = aq->query_data;510struct fd_screen *screen = data->screen;511struct fd_ringbuffer *ring = batch->draw;512513unsigned counters_per_group[screen->num_perfcntr_groups];514memset(counters_per_group, 0, sizeof(counters_per_group));515516fd_wfi(batch, ring);517518/* TODO do we need to bother to turn anything off? */519520/* snapshot the end values: */521for (unsigned i = 0; i < data->num_query_entries; i++) {522struct fd_batch_query_entry *entry = &data->query_entries[i];523const struct fd_perfcntr_group *g = &screen->perfcntr_groups[entry->gid];524unsigned counter_idx = counters_per_group[entry->gid]++;525const struct fd_perfcntr_counter *counter = &g->counters[counter_idx];526527OUT_PKT7(ring, CP_REG_TO_MEM, 3);528OUT_RING(ring, CP_REG_TO_MEM_0_64B |529CP_REG_TO_MEM_0_REG(counter->counter_reg_lo));530OUT_RELOC(ring, query_sample_idx(aq, i, stop));531}532533/* and compute the result: */534for (unsigned i = 0; i < data->num_query_entries; i++) {535/* result += stop - start: */536OUT_PKT7(ring, CP_MEM_TO_MEM, 9);537OUT_RING(ring, CP_MEM_TO_MEM_0_DOUBLE | CP_MEM_TO_MEM_0_NEG_C);538OUT_RELOC(ring, query_sample_idx(aq, i, result)); /* dst */539OUT_RELOC(ring, query_sample_idx(aq, i, result)); /* srcA */540OUT_RELOC(ring, query_sample_idx(aq, i, stop)); /* srcB */541OUT_RELOC(ring, query_sample_idx(aq, i, start)); /* srcC */542}543}544545static void546perfcntr_accumulate_result(struct fd_acc_query *aq, void *buf,547union pipe_query_result *result)548{549struct fd_batch_query_data *data = aq->query_data;550struct fd6_query_sample *sp = buf;551552for (unsigned i = 0; i < data->num_query_entries; i++) {553result->batch[i].u64 = sp[i].result;554}555}556557static const struct fd_acc_sample_provider perfcntr = {558.query_type = FD_QUERY_FIRST_PERFCNTR,559.always = true,560.resume = perfcntr_resume,561.pause = perfcntr_pause,562.result = perfcntr_accumulate_result,563};564565static struct pipe_query *566fd6_create_batch_query(struct pipe_context *pctx, unsigned num_queries,567unsigned *query_types)568{569struct fd_context *ctx = fd_context(pctx);570struct fd_screen *screen = ctx->screen;571struct fd_query *q;572struct fd_acc_query *aq;573struct fd_batch_query_data *data;574575data = CALLOC_VARIANT_LENGTH_STRUCT(576fd_batch_query_data, num_queries * sizeof(data->query_entries[0]));577578data->screen = screen;579data->num_query_entries = num_queries;580581/* validate the requested query_types and ensure we don't try582* to request more query_types of a given group than we have583* counters:584*/585unsigned counters_per_group[screen->num_perfcntr_groups];586memset(counters_per_group, 0, sizeof(counters_per_group));587588for (unsigned i = 0; i < num_queries; i++) {589unsigned idx = query_types[i] - FD_QUERY_FIRST_PERFCNTR;590591/* verify valid query_type, ie. is it actually a perfcntr? */592if ((query_types[i] < FD_QUERY_FIRST_PERFCNTR) ||593(idx >= screen->num_perfcntr_queries)) {594mesa_loge("invalid batch query query_type: %u", query_types[i]);595goto error;596}597598struct fd_batch_query_entry *entry = &data->query_entries[i];599struct pipe_driver_query_info *pq = &screen->perfcntr_queries[idx];600601entry->gid = pq->group_id;602603/* the perfcntr_queries[] table flattens all the countables604* for each group in series, ie:605*606* (G0,C0), .., (G0,Cn), (G1,C0), .., (G1,Cm), ...607*608* So to find the countable index just step back through the609* table to find the first entry with the same group-id.610*/611while (pq > screen->perfcntr_queries) {612pq--;613if (pq->group_id == entry->gid)614entry->cid++;615}616617if (counters_per_group[entry->gid] >=618screen->perfcntr_groups[entry->gid].num_counters) {619mesa_loge("too many counters for group %u", entry->gid);620goto error;621}622623counters_per_group[entry->gid]++;624}625626q = fd_acc_create_query2(ctx, 0, 0, &perfcntr);627aq = fd_acc_query(q);628629/* sample buffer size is based on # of queries: */630aq->size = num_queries * sizeof(struct fd6_query_sample);631aq->query_data = data;632633return (struct pipe_query *)q;634635error:636free(data);637return NULL;638}639640void641fd6_query_context_init(struct pipe_context *pctx) disable_thread_safety_analysis642{643struct fd_context *ctx = fd_context(pctx);644645ctx->create_query = fd_acc_create_query;646ctx->query_update_batch = fd_acc_query_update_batch;647648ctx->record_timestamp = record_timestamp;649ctx->ts_to_ns = ticks_to_ns;650651pctx->create_batch_query = fd6_create_batch_query;652653fd_acc_query_register_provider(pctx, &occlusion_counter);654fd_acc_query_register_provider(pctx, &occlusion_predicate);655fd_acc_query_register_provider(pctx, &occlusion_predicate_conservative);656657fd_acc_query_register_provider(pctx, &time_elapsed);658fd_acc_query_register_provider(pctx, ×tamp);659660fd_acc_query_register_provider(pctx, &primitives_generated);661fd_acc_query_register_provider(pctx, &primitives_emitted);662}663664665