1 #include "config.h"
2
3 #include "gskvulkanrendererprivate.h"
4
5 #include "gskdebugprivate.h"
6 #include "gskprivate.h"
7 #include "gskrendererprivate.h"
8 #include "gskrendernodeprivate.h"
9 #include "gskvulkanbufferprivate.h"
10 #include "gskvulkanimageprivate.h"
11 #include "gskvulkanpipelineprivate.h"
12 #include "gskvulkanrenderprivate.h"
13 #include "gskvulkanglyphcacheprivate.h"
14
15 #include "gdk/gdktextureprivate.h"
16 #include "gdk/gdkprofilerprivate.h"
17
18 #include <graphene.h>
19
20 typedef struct _GskVulkanTextureData GskVulkanTextureData;
21
22 struct _GskVulkanTextureData {
23 GdkTexture *texture;
24 GskVulkanImage *image;
25 GskVulkanRenderer *renderer;
26 };
27
28 #ifdef G_ENABLE_DEBUG
29 typedef struct {
30 GQuark frames;
31 GQuark render_passes;
32 GQuark fallback_pixels;
33 GQuark texture_pixels;
34 } ProfileCounters;
35
36 typedef struct {
37 GQuark cpu_time;
38 GQuark gpu_time;
39 } ProfileTimers;
40
41 static guint texture_pixels_counter;
42 static guint fallback_pixels_counter;
43 #endif
44
45 struct _GskVulkanRenderer
46 {
47 GskRenderer parent_instance;
48
49 GdkVulkanContext *vulkan;
50
51 guint n_targets;
52 GskVulkanImage **targets;
53
54 GskVulkanRender *render;
55
56 GSList *textures;
57
58 GskVulkanGlyphCache *glyph_cache;
59
60 #ifdef G_ENABLE_DEBUG
61 ProfileCounters profile_counters;
62 ProfileTimers profile_timers;
63 #endif
64 };
65
66 struct _GskVulkanRendererClass
67 {
68 GskRendererClass parent_class;
69 };
70
G_DEFINE_TYPE(GskVulkanRenderer,gsk_vulkan_renderer,GSK_TYPE_RENDERER)71 G_DEFINE_TYPE (GskVulkanRenderer, gsk_vulkan_renderer, GSK_TYPE_RENDERER)
72
73 static void
74 gsk_vulkan_renderer_free_targets (GskVulkanRenderer *self)
75 {
76 guint i;
77
78 for (i = 0; i < self->n_targets; i++)
79 {
80 g_object_unref (self->targets[i]);
81 }
82
83 g_clear_pointer (&self->targets, g_free);
84 self->n_targets = 0;
85 }
86
87 static void
gsk_vulkan_renderer_update_images_cb(GdkVulkanContext * context,GskVulkanRenderer * self)88 gsk_vulkan_renderer_update_images_cb (GdkVulkanContext *context,
89 GskVulkanRenderer *self)
90 {
91 GdkSurface *window;
92 int scale_factor;
93 gsize width, height;
94 guint i;
95
96 gsk_vulkan_renderer_free_targets (self);
97
98 self->n_targets = gdk_vulkan_context_get_n_images (context);
99 self->targets = g_new (GskVulkanImage *, self->n_targets);
100
101 window = gsk_renderer_get_surface (GSK_RENDERER (self));
102 scale_factor = gdk_surface_get_scale_factor (window);
103 width = gdk_surface_get_width (window) * scale_factor;
104 height = gdk_surface_get_height (window) * scale_factor;
105
106 for (i = 0; i < self->n_targets; i++)
107 {
108 self->targets[i] = gsk_vulkan_image_new_for_swapchain (self->vulkan,
109 gdk_vulkan_context_get_image (context, i),
110 gdk_vulkan_context_get_image_format (self->vulkan),
111 width, height);
112 }
113 }
114
115 static gboolean
gsk_vulkan_renderer_realize(GskRenderer * renderer,GdkSurface * window,GError ** error)116 gsk_vulkan_renderer_realize (GskRenderer *renderer,
117 GdkSurface *window,
118 GError **error)
119 {
120 GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
121
122 self->vulkan = gdk_surface_create_vulkan_context (window, error);
123 if (self->vulkan == NULL)
124 return FALSE;
125
126 g_signal_connect (self->vulkan,
127 "images-updated",
128 G_CALLBACK (gsk_vulkan_renderer_update_images_cb),
129 self);
130 gsk_vulkan_renderer_update_images_cb (self->vulkan, self);
131
132 self->render = gsk_vulkan_render_new (renderer, self->vulkan);
133
134 self->glyph_cache = gsk_vulkan_glyph_cache_new (renderer, self->vulkan);
135
136 return TRUE;
137 }
138
139 static void
gsk_vulkan_renderer_unrealize(GskRenderer * renderer)140 gsk_vulkan_renderer_unrealize (GskRenderer *renderer)
141 {
142 GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
143 GSList *l;
144
145 g_clear_object (&self->glyph_cache);
146
147 for (l = self->textures; l; l = l->next)
148 {
149 GskVulkanTextureData *data = l->data;
150
151 data->renderer = NULL;
152 gdk_texture_clear_render_data (data->texture);
153 }
154 g_clear_pointer (&self->textures, g_slist_free);
155
156 g_clear_pointer (&self->render, gsk_vulkan_render_free);
157
158 gsk_vulkan_renderer_free_targets (self);
159 g_signal_handlers_disconnect_by_func(self->vulkan,
160 gsk_vulkan_renderer_update_images_cb,
161 self);
162
163 g_clear_object (&self->vulkan);
164 }
165
166 static GdkTexture *
gsk_vulkan_renderer_render_texture(GskRenderer * renderer,GskRenderNode * root,const graphene_rect_t * viewport)167 gsk_vulkan_renderer_render_texture (GskRenderer *renderer,
168 GskRenderNode *root,
169 const graphene_rect_t *viewport)
170 {
171 GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
172 GskVulkanRender *render;
173 GskVulkanImage *image;
174 GdkTexture *texture;
175 #ifdef G_ENABLE_DEBUG
176 GskProfiler *profiler;
177 gint64 cpu_time;
178 gint64 start_time G_GNUC_UNUSED;
179 #endif
180
181 #ifdef G_ENABLE_DEBUG
182 profiler = gsk_renderer_get_profiler (renderer);
183 gsk_profiler_counter_set (profiler, self->profile_counters.fallback_pixels, 0);
184 gsk_profiler_counter_set (profiler, self->profile_counters.texture_pixels, 0);
185 gsk_profiler_counter_set (profiler, self->profile_counters.render_passes, 0);
186 gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time);
187 #endif
188
189 render = gsk_vulkan_render_new (renderer, self->vulkan);
190
191 image = gsk_vulkan_image_new_for_framebuffer (self->vulkan,
192 ceil (viewport->size.width),
193 ceil (viewport->size.height));
194
195 gsk_vulkan_render_reset (render, image, viewport, NULL);
196
197 gsk_vulkan_render_add_node (render, root);
198
199 gsk_vulkan_render_upload (render);
200
201 gsk_vulkan_render_draw (render);
202
203 texture = gsk_vulkan_render_download_target (render);
204
205 g_object_unref (image);
206 gsk_vulkan_render_free (render);
207
208 #ifdef G_ENABLE_DEBUG
209 start_time = gsk_profiler_timer_get_start (profiler, self->profile_timers.cpu_time);
210 cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
211 gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time);
212
213 gsk_profiler_push_samples (profiler);
214
215 if (GDK_PROFILER_IS_RUNNING)
216 {
217 gdk_profiler_add_mark (start_time * 1000, cpu_time * 1000, "render", "");
218 gdk_profiler_set_int_counter (texture_pixels_counter,
219 gsk_profiler_counter_get (profiler, self->profile_counters.texture_pixels));
220 gdk_profiler_set_int_counter (fallback_pixels_counter,
221 gsk_profiler_counter_get (profiler, self->profile_counters.fallback_pixels));
222 }
223 #endif
224
225 return texture;
226 }
227
228 static void
gsk_vulkan_renderer_render(GskRenderer * renderer,GskRenderNode * root,const cairo_region_t * region)229 gsk_vulkan_renderer_render (GskRenderer *renderer,
230 GskRenderNode *root,
231 const cairo_region_t *region)
232 {
233 GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
234 GskVulkanRender *render;
235 const cairo_region_t *clip;
236 #ifdef G_ENABLE_DEBUG
237 GskProfiler *profiler;
238 gint64 cpu_time;
239 #endif
240
241 #ifdef G_ENABLE_DEBUG
242 profiler = gsk_renderer_get_profiler (renderer);
243 gsk_profiler_counter_set (profiler, self->profile_counters.fallback_pixels, 0);
244 gsk_profiler_counter_set (profiler, self->profile_counters.texture_pixels, 0);
245 gsk_profiler_counter_set (profiler, self->profile_counters.render_passes, 0);
246 gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time);
247 #endif
248
249 gdk_draw_context_begin_frame (GDK_DRAW_CONTEXT (self->vulkan), region);
250 render = self->render;
251
252 clip = gdk_draw_context_get_frame_region (GDK_DRAW_CONTEXT (self->vulkan));
253 gsk_vulkan_render_reset (render, self->targets[gdk_vulkan_context_get_draw_index (self->vulkan)], NULL, clip);
254
255 gsk_vulkan_render_add_node (render, root);
256
257 gsk_vulkan_render_upload (render);
258
259 gsk_vulkan_render_draw (render);
260
261 #ifdef G_ENABLE_DEBUG
262 gsk_profiler_counter_inc (profiler, self->profile_counters.frames);
263
264 cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
265 gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time);
266
267 gsk_profiler_push_samples (profiler);
268 #endif
269
270 gdk_draw_context_end_frame (GDK_DRAW_CONTEXT (self->vulkan));
271 }
272
273 static void
gsk_vulkan_renderer_class_init(GskVulkanRendererClass * klass)274 gsk_vulkan_renderer_class_init (GskVulkanRendererClass *klass)
275 {
276 GskRendererClass *renderer_class = GSK_RENDERER_CLASS (klass);
277
278 renderer_class->realize = gsk_vulkan_renderer_realize;
279 renderer_class->unrealize = gsk_vulkan_renderer_unrealize;
280 renderer_class->render = gsk_vulkan_renderer_render;
281 renderer_class->render_texture = gsk_vulkan_renderer_render_texture;
282 }
283
284 static void
gsk_vulkan_renderer_init(GskVulkanRenderer * self)285 gsk_vulkan_renderer_init (GskVulkanRenderer *self)
286 {
287 #ifdef G_ENABLE_DEBUG
288 GskProfiler *profiler = gsk_renderer_get_profiler (GSK_RENDERER (self));
289 #endif
290
291 gsk_ensure_resources ();
292
293 #ifdef G_ENABLE_DEBUG
294 self->profile_counters.frames = gsk_profiler_add_counter (profiler, "frames", "Frames", FALSE);
295 self->profile_counters.render_passes = gsk_profiler_add_counter (profiler, "render-passes", "Render passes", FALSE);
296 self->profile_counters.fallback_pixels = gsk_profiler_add_counter (profiler, "fallback-pixels", "Fallback pixels", TRUE);
297 self->profile_counters.texture_pixels = gsk_profiler_add_counter (profiler, "texture-pixels", "Texture pixels", TRUE);
298
299 self->profile_timers.cpu_time = gsk_profiler_add_timer (profiler, "cpu-time", "CPU time", FALSE, TRUE);
300 if (GSK_RENDERER_DEBUG_CHECK (GSK_RENDERER (self), SYNC))
301 self->profile_timers.gpu_time = gsk_profiler_add_timer (profiler, "gpu-time", "GPU time", FALSE, TRUE);
302
303 if (texture_pixels_counter == 0)
304 {
305 texture_pixels_counter = gdk_profiler_define_int_counter ("texture-pixels", "Texture Pixels");
306 fallback_pixels_counter = gdk_profiler_define_int_counter ("fallback-pixels", "Fallback Pixels");
307 }
308
309 #endif
310 }
311
312 static void
gsk_vulkan_renderer_clear_texture(gpointer p)313 gsk_vulkan_renderer_clear_texture (gpointer p)
314 {
315 GskVulkanTextureData *data = p;
316
317 if (data->renderer != NULL)
318 data->renderer->textures = g_slist_remove (data->renderer->textures, data);
319
320 g_object_unref (data->image);
321
322 g_slice_free (GskVulkanTextureData, data);
323 }
324
325 GskVulkanImage *
gsk_vulkan_renderer_ref_texture_image(GskVulkanRenderer * self,GdkTexture * texture,GskVulkanUploader * uploader)326 gsk_vulkan_renderer_ref_texture_image (GskVulkanRenderer *self,
327 GdkTexture *texture,
328 GskVulkanUploader *uploader)
329 {
330 GskVulkanTextureData *data;
331 cairo_surface_t *surface;
332 GskVulkanImage *image;
333
334 data = gdk_texture_get_render_data (texture, self);
335 if (data)
336 return g_object_ref (data->image);
337
338 surface = gdk_texture_download_surface (texture);
339 image = gsk_vulkan_image_new_from_data (uploader,
340 cairo_image_surface_get_data (surface),
341 cairo_image_surface_get_width (surface),
342 cairo_image_surface_get_height (surface),
343 cairo_image_surface_get_stride (surface));
344 cairo_surface_destroy (surface);
345
346 data = g_slice_new0 (GskVulkanTextureData);
347 data->image = image;
348 data->texture = texture;
349 data->renderer = self;
350
351 if (gdk_texture_set_render_data (texture, self, data, gsk_vulkan_renderer_clear_texture))
352 {
353 g_object_ref (data->image);
354 self->textures = g_slist_prepend (self->textures, data);
355 }
356 else
357 {
358 g_slice_free (GskVulkanTextureData, data);
359 }
360
361 return image;
362 }
363
364 GskVulkanImage *
gsk_vulkan_renderer_ref_glyph_image(GskVulkanRenderer * self,GskVulkanUploader * uploader,guint index)365 gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer *self,
366 GskVulkanUploader *uploader,
367 guint index)
368 {
369 return g_object_ref (gsk_vulkan_glyph_cache_get_glyph_image (self->glyph_cache, uploader, index));
370 }
371
372 guint
gsk_vulkan_renderer_cache_glyph(GskVulkanRenderer * self,PangoFont * font,PangoGlyph glyph,int x,int y,float scale)373 gsk_vulkan_renderer_cache_glyph (GskVulkanRenderer *self,
374 PangoFont *font,
375 PangoGlyph glyph,
376 int x,
377 int y,
378 float scale)
379 {
380 return gsk_vulkan_glyph_cache_lookup (self->glyph_cache, TRUE, font, glyph, x, y, scale)->texture_index;
381 }
382
383 GskVulkanCachedGlyph *
gsk_vulkan_renderer_get_cached_glyph(GskVulkanRenderer * self,PangoFont * font,PangoGlyph glyph,int x,int y,float scale)384 gsk_vulkan_renderer_get_cached_glyph (GskVulkanRenderer *self,
385 PangoFont *font,
386 PangoGlyph glyph,
387 int x,
388 int y,
389 float scale)
390 {
391 return gsk_vulkan_glyph_cache_lookup (self->glyph_cache, FALSE, font, glyph, x, y, scale);
392 }
393
394 /**
395 * gsk_vulkan_renderer_new:
396 *
397 * Creates a new Vulkan renderer.
398 *
399 * The Vulkan renderer is a renderer that uses the Vulkan library for
400 * rendering.
401 *
402 * This function is only available when GTK was compiled with Vulkan
403 * support.
404 *
405 * Returns: a new Vulkan renderer
406 **/
407 GskRenderer *
gsk_vulkan_renderer_new(void)408 gsk_vulkan_renderer_new (void)
409 {
410 return g_object_new (GSK_TYPE_VULKAN_RENDERER, NULL);
411 }
412