git.lucas.co / cce-compositor
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 */