Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
scenefx/render/fx_renderer/tracy.c (5.5K)
1 #ifdef TRACY_ENABLE
2 #include <GLES2/gl2.h>
3 #include <assert.h>
4 #include <stdatomic.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <tracy/TracyC.h>
9 #include <wayland-util.h>
10 #include <wlr/util/log.h>
11
12 #include "render/fx_renderer/fx_renderer.h"
13 #include "render/tracy.h"
14
15 // Docs used in the implementation:
16 // - https://github.com/wolfpld/tracy/releases/latest/download/tracy.pdf
17 // - https://registry.khronos.org/OpenGL/extensions/EXT/EXT_disjoint_timer_query.txt
18 // - https://github.com/wolfpld/tracy/blob/7388a476587c93f4e8e3e50d64c1400fc8c5e47e/public/tracy/TracyOpenGL.hpp
19
20 #define QUERY_QUEUE_LEN (64 * 1024)
21
22 // Colors:
23 // From https://github.com/wolfpld/tracy/blob/7388a476587c93f4e8e3e50d64c1400fc8c5e47e/public/common/TracyColor.hpp
24 #define RED4 0x8b0000
25
26 static atomic_int id_counter = 0;
27
28 struct tracy_data {
29 struct fx_renderer *renderer;
30
31 uint8_t context_id;
32
33 struct {
34 uint32_t queries[QUERY_QUEUE_LEN];
35 uint32_t head;
36 uint32_t tail;
37 } queue;
38 };
39
40 /*
41 * GPU Zone
42 */
43
44 static inline unsigned int get_next_query_index(struct tracy_data *tracy_data) {
45 const unsigned int id = tracy_data->queue.head;
46 tracy_data->queue.head = (tracy_data->queue.head + 1) % QUERY_QUEUE_LEN;
47 assert(tracy_data->queue.head != tracy_data->queue.tail);
48 return id;
49 }
50
51 void tracy_gpu_zone_begin(struct tracy_data *tracy_data, struct tracy_gpu_zone_context *out_ctx,
52 const int line, const char *source, const char *func, const char *name) {
53 if (out_ctx == NULL || tracy_data == NULL) {
54 return;
55 }
56
57 out_ctx->tracy_data = tracy_data;
58 #ifdef TRACY_ON_DEMAND
59 out_ctx->is_active = TracyCIsConnected;
60 #else
61 out_ctx->is_active = true;
62 #endif
63
64 if (!out_ctx->is_active) {
65 return;
66 }
67
68 // Create the query object
69 const unsigned int query = get_next_query_index(tracy_data);
70 tracy_data->renderer->procs.glQueryCounterEXT(tracy_data->queue.queries[query], GL_TIMESTAMP_EXT);
71
72 // Label the zone
73 uint64_t srcloc = ___tracy_alloc_srcloc_name(line,
74 source, strlen(source),
75 func, strlen(func),
76 name, strlen(name),
77 0);
78
79 // Begin the Tracy GPU zone
80 const struct ___tracy_gpu_zone_begin_data data = {
81 .context = tracy_data->context_id,
82 .queryId = (uint16_t) query,
83 .srcloc = srcloc,
84 };
85 ___tracy_emit_gpu_zone_begin_alloc(data);
86 }
87
88 void tracy_gpu_zone_end(struct tracy_gpu_zone_context *ctx) {
89 if (ctx == NULL || ctx->tracy_data == NULL || !ctx->is_active) {
90 return;
91 }
92 struct tracy_data *tracy_data = ctx->tracy_data;
93
94 // Create the query object
95 const unsigned int query = get_next_query_index(tracy_data);
96 tracy_data->renderer->procs.glQueryCounterEXT(tracy_data->queue.queries[query], GL_TIMESTAMP_EXT);
97
98 // End the Tracy GPU zone
99 const struct ___tracy_gpu_zone_end_data data = {
100 .context = tracy_data->context_id,
101 .queryId = (uint16_t) query,
102 };
103 ___tracy_emit_gpu_zone_end(data);
104 }
105
106 void tracy_gpu_context_collect(struct tracy_data *tracy_data) {
107 if (tracy_data == NULL) {
108 TracyCMessageL("tracy_data == NULL");
109 return;
110 }
111
112 TracyCZoneC(ctx, RED4, true);
113
114 if (tracy_data->queue.tail == tracy_data->queue.head) {
115 goto done;
116 }
117
118 #ifdef TRACY_ON_DEMAND
119 if (!TracyCIsConnected) {
120 tracy_data->queue.head = 0;
121 tracy_data->queue.tail = 0;
122 goto done;
123 }
124 #endif
125
126 while (tracy_data->queue.tail != tracy_data->queue.head) {
127 GLint available;
128 tracy_data->renderer->procs.glGetQueryObjectivEXT(
129 tracy_data->queue.queries[tracy_data->queue.tail],
130 GL_QUERY_RESULT_AVAILABLE_EXT, &available);
131 if (!available) {
132 goto done;
133 }
134
135 GLuint64 time;
136 tracy_data->renderer->procs.glGetQueryObjectui64vEXT(
137 tracy_data->queue.queries[tracy_data->queue.tail],
138 GL_QUERY_RESULT_EXT, &time);
139
140 const struct ___tracy_gpu_time_data data = {
141 .context = tracy_data->context_id,
142 .gpuTime = time,
143 .queryId = (uint16_t) tracy_data->queue.tail,
144 };
145 ___tracy_emit_gpu_time(data);
146
147 tracy_data->queue.tail = (tracy_data->queue.tail + 1) % QUERY_QUEUE_LEN;
148 }
149
150 done:
151 TracyCZoneEnd(ctx);
152 }
153
154 void tracy_gpu_context_destroy(struct tracy_data *tracy_data) {
155 id_counter--;
156 if (tracy_data == NULL) {
157 return;
158 }
159
160 tracy_data->renderer->procs.glDeleteQueriesEXT(QUERY_QUEUE_LEN, tracy_data->queue.queries);
161 free(tracy_data);
162 }
163
164 struct tracy_data *tracy_gpu_context_new(struct fx_renderer *renderer) {
165 assert(renderer);
166
167 struct tracy_data *tracy_data = calloc(1, sizeof(*tracy_data));
168 if (tracy_data == NULL) {
169 wlr_log_errno(WLR_ERROR, "Allocation failed");
170 return NULL;
171 }
172
173 tracy_data->renderer = renderer;
174 tracy_data->context_id = ++id_counter;
175 tracy_data->queue.head = 0;
176 tracy_data->queue.tail = 0;
177
178 // Create the query objects
179 renderer->procs.glGenQueriesEXT(QUERY_QUEUE_LEN, tracy_data->queue.queries);
180
181 // Get the current GL time
182 GLint64 gl_gpu_time;
183 renderer->procs.glGetInteger64vEXT(GL_TIMESTAMP_EXT, &gl_gpu_time);
184
185 // Create the query objects
186 GLint bits;
187 renderer->procs.glGetQueryivEXT(GL_TIMESTAMP_EXT, GL_QUERY_COUNTER_BITS_EXT, &bits);
188
189 const struct ___tracy_gpu_new_context_data data = {
190 .context = tracy_data->context_id,
191 .gpuTime = gl_gpu_time,
192 .period = 1.0f,
193 .flags = 0,
194 .type = 1, // `enum class GpuContextType` in TracyQueue.hpp
195 };
196 ___tracy_emit_gpu_new_context(data);
197
198 // Set the custom name
199 int len = snprintf(NULL, 0, "FX Renderer (GLESV2): %s",
200 glGetString(GL_RENDERER)) + 1; \
201 char ctx_name[len]; \
202 snprintf(ctx_name, len, "FX Renderer (GLESV2): %s",
203 glGetString(GL_RENDERER)); \
204 const struct ___tracy_gpu_context_name_data name_data = {
205 .context = tracy_data->context_id,
206 .name = ctx_name,
207 .len = strlen(ctx_name),
208 };
209 ___tracy_emit_gpu_context_name(name_data);
210 return tracy_data;
211 }
212 #endif /* ifdef TRACY_ENABLE */