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