GPU: Rename GPU_shader_get_uniform to GPU_shader_get_uniform_ensure
[blender.git] / source / blender / gpu / intern / gpu_viewport.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2006 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s):
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/gpu/intern/gpu_viewport.c
29  *  \ingroup gpu
30  *
31  * System that manages viewport drawing.
32  */
33
34 #include <string.h>
35
36 #include "BLI_listbase.h"
37 #include "BLI_rect.h"
38 #include "BLI_string.h"
39 #include "BLI_mempool.h"
40
41 #include "BIF_gl.h"
42
43 #include "DNA_vec_types.h"
44 #include "DNA_userdef_types.h"
45
46 #include "BKE_global.h"
47
48 #include "GPU_framebuffer.h"
49 #include "GPU_glew.h"
50 #include "GPU_immediate.h"
51 #include "GPU_texture.h"
52 #include "GPU_viewport.h"
53 #include "GPU_draw.h"
54
55 #include "DRW_engine.h"
56
57 #include "MEM_guardedalloc.h"
58
59 static const int default_fbl_len = (sizeof(DefaultFramebufferList)) / sizeof(void *);
60 static const int default_txl_len = (sizeof(DefaultTextureList)) / sizeof(void *);
61
62 /* Maximum number of simultaneous engine enabled at the same time.
63  * Setting it lower than the real number will do lead to
64  * higher VRAM usage due to sub-efficient buffer reuse. */
65 #define MAX_ENGINE_BUFFER_SHARING 5
66
67 typedef struct ViewportTempTexture {
68         struct ViewportTempTexture *next, *prev;
69         void *user[MAX_ENGINE_BUFFER_SHARING];
70         GPUTexture *texture;
71 } ViewportTempTexture;
72
73 struct GPUViewport {
74         int size[2];
75         int samples;
76         int flag;
77
78         ListBase data;  /* ViewportEngineData wrapped in LinkData */
79         uint data_hash;  /* If hash mismatch we free all ViewportEngineData in this viewport */
80
81         DefaultFramebufferList *fbl;
82         DefaultTextureList *txl;
83
84         ViewportMemoryPool vmempool; /* Used for rendering data structure. */
85         struct DRWInstanceDataList *idatalist; /* Used for rendering data structure. */
86
87         ListBase tex_pool;  /* ViewportTempTexture list : Temporary textures shared across draw engines */
88
89         /* Profiling data */
90         double cache_time;
91 };
92
93 enum {
94         DO_UPDATE = (1 << 0),
95 };
96
97 static void gpu_viewport_buffers_free(FramebufferList *fbl, int fbl_len, TextureList *txl, int txl_len);
98 static void gpu_viewport_storage_free(StorageList *stl, int stl_len);
99 static void gpu_viewport_passes_free(PassList *psl, int psl_len);
100 static void gpu_viewport_texture_pool_free(GPUViewport *viewport);
101 static void gpu_viewport_default_fb_create(GPUViewport *viewport);
102
103 void GPU_viewport_tag_update(GPUViewport *viewport)
104 {
105         viewport->flag |= DO_UPDATE;
106 }
107
108 bool GPU_viewport_do_update(GPUViewport *viewport)
109 {
110         bool ret = (viewport->flag & DO_UPDATE);
111         viewport->flag &= ~DO_UPDATE;
112         return ret;
113 }
114
115 GPUViewport *GPU_viewport_create(void)
116 {
117         GPUViewport *viewport = MEM_callocN(sizeof(GPUViewport), "GPUViewport");
118         viewport->fbl = MEM_callocN(sizeof(DefaultFramebufferList), "FramebufferList");
119         viewport->txl = MEM_callocN(sizeof(DefaultTextureList), "TextureList");
120         viewport->idatalist = DRW_instance_data_list_create();
121
122         viewport->size[0] = viewport->size[1] = -1;
123
124         return viewport;
125 }
126
127 GPUViewport *GPU_viewport_create_from_offscreen(struct GPUOffScreen *ofs)
128 {
129         GPUViewport *viewport = GPU_viewport_create();
130         GPUTexture *color, *depth;
131         GPUFrameBuffer *fb;
132         viewport->size[0] = GPU_offscreen_width(ofs);
133         viewport->size[1] = GPU_offscreen_height(ofs);
134
135         GPU_offscreen_viewport_data_get(ofs, &fb, &color, &depth);
136
137         if (GPU_texture_samples(color)) {
138                 viewport->txl->multisample_color = color;
139                 viewport->txl->multisample_depth = depth;
140                 viewport->fbl->multisample_fb = fb;
141                 gpu_viewport_default_fb_create(viewport);
142         }
143         else {
144                 viewport->fbl->default_fb = fb;
145                 viewport->txl->color = color;
146                 viewport->txl->depth = depth;
147                 GPU_framebuffer_ensure_config(&viewport->fbl->color_only_fb, {
148                         GPU_ATTACHMENT_NONE,
149                         GPU_ATTACHMENT_TEXTURE(viewport->txl->color)
150                 });
151                 GPU_framebuffer_ensure_config(&viewport->fbl->depth_only_fb, {
152                         GPU_ATTACHMENT_TEXTURE(viewport->txl->depth),
153                         GPU_ATTACHMENT_NONE
154                 });
155         }
156
157         return viewport;
158 }
159 /**
160  * Clear vars assigned from offscreen, so we don't free data owned by `GPUOffScreen`.
161  */
162 void GPU_viewport_clear_from_offscreen(GPUViewport *viewport)
163 {
164         DefaultFramebufferList *dfbl = viewport->fbl;
165         DefaultTextureList *dtxl = viewport->txl;
166
167         if (dfbl->multisample_fb) {
168                 /* GPUViewport expect the final result to be in default_fb but
169                  * GPUOffscreen wants it in its multisample_fb, so we sync it back. */
170                 GPU_framebuffer_blit(dfbl->default_fb, 0, dfbl->multisample_fb, 0, GPU_COLOR_BIT | GPU_DEPTH_BIT);
171                 dfbl->multisample_fb = NULL;
172                 dtxl->multisample_color = NULL;
173                 dtxl->multisample_depth = NULL;
174         }
175         else {
176                 viewport->fbl->default_fb = NULL;
177                 dtxl->color = NULL;
178                 dtxl->depth = NULL;
179         }
180 }
181
182 void *GPU_viewport_engine_data_create(GPUViewport *viewport, void *engine_type)
183 {
184         LinkData *ld = MEM_callocN(sizeof(LinkData), "LinkData");
185         ViewportEngineData *data = MEM_callocN(sizeof(ViewportEngineData), "ViewportEngineData");
186         int fbl_len, txl_len, psl_len, stl_len;
187
188         DRW_engine_viewport_data_size_get(engine_type, &fbl_len, &txl_len, &psl_len, &stl_len);
189
190         data->engine_type = engine_type;
191
192         data->fbl = MEM_callocN((sizeof(void *) * fbl_len) + sizeof(FramebufferList), "FramebufferList");
193         data->txl = MEM_callocN((sizeof(void *) * txl_len) + sizeof(TextureList), "TextureList");
194         data->psl = MEM_callocN((sizeof(void *) * psl_len) + sizeof(PassList), "PassList");
195         data->stl = MEM_callocN((sizeof(void *) * stl_len) + sizeof(StorageList), "StorageList");
196
197         ld->data = data;
198         BLI_addtail(&viewport->data, ld);
199
200         return data;
201 }
202
203 static void gpu_viewport_engines_data_free(GPUViewport *viewport)
204 {
205         int fbl_len, txl_len, psl_len, stl_len;
206
207         LinkData *next;
208         for (LinkData *link = viewport->data.first; link; link = next) {
209                 next = link->next;
210                 ViewportEngineData *data = link->data;
211                 DRW_engine_viewport_data_size_get(data->engine_type, &fbl_len, &txl_len, &psl_len, &stl_len);
212
213                 gpu_viewport_buffers_free(data->fbl, fbl_len, data->txl, txl_len);
214                 gpu_viewport_passes_free(data->psl, psl_len);
215                 gpu_viewport_storage_free(data->stl, stl_len);
216
217                 MEM_freeN(data->fbl);
218                 MEM_freeN(data->txl);
219                 MEM_freeN(data->psl);
220                 MEM_freeN(data->stl);
221
222                 /* We could handle this in the DRW module */
223                 if (data->text_draw_cache) {
224                         extern void DRW_text_cache_destroy(struct DRWTextStore *dt);
225                         DRW_text_cache_destroy(data->text_draw_cache);
226                         data->text_draw_cache = NULL;
227                 }
228
229                 MEM_freeN(data);
230
231                 BLI_remlink(&viewport->data, link);
232                 MEM_freeN(link);
233         }
234
235         gpu_viewport_texture_pool_free(viewport);
236 }
237
238 void *GPU_viewport_engine_data_get(GPUViewport *viewport, void *engine_type)
239 {
240         for (LinkData *link = viewport->data.first; link; link = link->next) {
241                 ViewportEngineData *vdata = link->data;
242                 if (vdata->engine_type == engine_type) {
243                         return vdata;
244                 }
245         }
246         return NULL;
247 }
248
249 ViewportMemoryPool *GPU_viewport_mempool_get(GPUViewport *viewport)
250 {
251         return &viewport->vmempool;
252 }
253
254 struct DRWInstanceDataList *GPU_viewport_instance_data_list_get(GPUViewport *viewport)
255 {
256         return viewport->idatalist;
257 }
258
259 void *GPU_viewport_framebuffer_list_get(GPUViewport *viewport)
260 {
261         return viewport->fbl;
262 }
263
264 void *GPU_viewport_texture_list_get(GPUViewport *viewport)
265 {
266         return viewport->txl;
267 }
268
269 void GPU_viewport_size_get(const GPUViewport *viewport, int size[2])
270 {
271         size[0] = viewport->size[0];
272         size[1] = viewport->size[1];
273 }
274
275 /**
276  * Special case, this is needed for when we have a viewport without a frame-buffer output
277  * (occlusion queries for eg) but still need to set the size since it may be used for other calculations.
278  */
279 void GPU_viewport_size_set(GPUViewport *viewport, const int size[2])
280 {
281         viewport->size[0] = size[0];
282         viewport->size[1] = size[1];
283 }
284
285 double *GPU_viewport_cache_time_get(GPUViewport *viewport)
286 {
287         return &viewport->cache_time;
288 }
289
290 /**
291  * Try to find a texture corresponding to params into the texture pool.
292  * If no texture was found, create one and add it to the pool.
293  */
294 GPUTexture *GPU_viewport_texture_pool_query(GPUViewport *viewport, void *engine, int width, int height, int format)
295 {
296         GPUTexture *tex;
297
298         for (ViewportTempTexture *tmp_tex = viewport->tex_pool.first; tmp_tex; tmp_tex = tmp_tex->next) {
299                 if ((GPU_texture_format(tmp_tex->texture) == format) &&
300                     (GPU_texture_width(tmp_tex->texture) == width) &&
301                     (GPU_texture_height(tmp_tex->texture) == height))
302                 {
303                         /* Search if the engine is not already using this texture */
304                         for (int i = 0; i < MAX_ENGINE_BUFFER_SHARING; ++i) {
305                                 if (tmp_tex->user[i] == engine) {
306                                         break;
307                                 }
308
309                                 if (tmp_tex->user[i] == NULL) {
310                                         tmp_tex->user[i] = engine;
311                                         return tmp_tex->texture;
312                                 }
313                         }
314                 }
315         }
316
317         tex = GPU_texture_create_2D(width, height, format, NULL, NULL);
318         GPU_texture_bind(tex, 0);
319         /* Doing filtering for depth does not make sense when not doing shadow mapping,
320          * and enabling texture filtering on integer texture make them unreadable. */
321         bool do_filter = !GPU_texture_depth(tex) && !GPU_texture_integer(tex);
322         GPU_texture_filter_mode(tex, do_filter);
323         GPU_texture_unbind(tex);
324
325         ViewportTempTexture *tmp_tex = MEM_callocN(sizeof(ViewportTempTexture), "ViewportTempTexture");
326         tmp_tex->texture = tex;
327         tmp_tex->user[0] = engine;
328         BLI_addtail(&viewport->tex_pool, tmp_tex);
329
330         return tex;
331 }
332
333 static void gpu_viewport_texture_pool_clear_users(GPUViewport *viewport)
334 {
335         ViewportTempTexture *tmp_tex_next;
336
337         for (ViewportTempTexture *tmp_tex = viewport->tex_pool.first; tmp_tex; tmp_tex = tmp_tex_next) {
338                 tmp_tex_next = tmp_tex->next;
339                 bool no_user = true;
340                 for (int i = 0; i < MAX_ENGINE_BUFFER_SHARING; ++i) {
341                         if (tmp_tex->user[i] != NULL) {
342                                 tmp_tex->user[i] = NULL;
343                                 no_user = false;
344                         }
345                 }
346
347                 if (no_user) {
348                         GPU_texture_free(tmp_tex->texture);
349                         BLI_freelinkN(&viewport->tex_pool, tmp_tex);
350                 }
351         }
352 }
353
354 static void gpu_viewport_texture_pool_free(GPUViewport *viewport)
355 {
356         for (ViewportTempTexture *tmp_tex = viewport->tex_pool.first; tmp_tex; tmp_tex = tmp_tex->next) {
357                 GPU_texture_free(tmp_tex->texture);
358         }
359
360         BLI_freelistN(&viewport->tex_pool);
361 }
362
363 bool GPU_viewport_engines_data_validate(GPUViewport *viewport, uint hash)
364 {
365         bool dirty = false;
366
367         if (viewport->data_hash != hash) {
368                 gpu_viewport_engines_data_free(viewport);
369                 dirty = true;
370         }
371
372         viewport->data_hash = hash;
373
374         return dirty;
375 }
376
377 void GPU_viewport_cache_release(GPUViewport *viewport)
378 {
379         for (LinkData *link = viewport->data.first; link; link = link->next) {
380                 ViewportEngineData *data = link->data;
381                 int psl_len;
382                 DRW_engine_viewport_data_size_get(data->engine_type, NULL, NULL, &psl_len, NULL);
383                 gpu_viewport_passes_free(data->psl, psl_len);
384         }
385 }
386
387 static void gpu_viewport_default_fb_create(GPUViewport *viewport)
388 {
389         DefaultFramebufferList *dfbl = viewport->fbl;
390         DefaultTextureList *dtxl = viewport->txl;
391         int *size = viewport->size;
392         bool ok = true;
393
394         dtxl->color = GPU_texture_create_2D(size[0], size[1], GPU_RGBA8, NULL, NULL);
395         dtxl->depth = GPU_texture_create_2D(size[0], size[1], GPU_DEPTH24_STENCIL8, NULL, NULL);
396
397         if (!(dtxl->depth && dtxl->color)) {
398                 ok = false;
399                 goto cleanup;
400         }
401
402         GPU_framebuffer_ensure_config(&dfbl->default_fb, {
403                 GPU_ATTACHMENT_TEXTURE(dtxl->depth),
404                 GPU_ATTACHMENT_TEXTURE(dtxl->color)
405         });
406
407         GPU_framebuffer_ensure_config(&dfbl->depth_only_fb, {
408                 GPU_ATTACHMENT_TEXTURE(dtxl->depth),
409                 GPU_ATTACHMENT_NONE
410         });
411
412         GPU_framebuffer_ensure_config(&dfbl->color_only_fb, {
413                 GPU_ATTACHMENT_NONE,
414                 GPU_ATTACHMENT_TEXTURE(dtxl->color)
415         });
416
417         ok = ok && GPU_framebuffer_check_valid(dfbl->default_fb, NULL);
418         ok = ok && GPU_framebuffer_check_valid(dfbl->color_only_fb, NULL);
419         ok = ok && GPU_framebuffer_check_valid(dfbl->depth_only_fb, NULL);
420
421 cleanup:
422         if (!ok) {
423                 GPU_viewport_free(viewport);
424                 DRW_opengl_context_disable();
425                 return;
426         }
427
428         GPU_framebuffer_restore();
429 }
430
431 static void gpu_viewport_default_multisample_fb_create(GPUViewport *viewport)
432 {
433         DefaultFramebufferList *dfbl = viewport->fbl;
434         DefaultTextureList *dtxl = viewport->txl;
435         int *size = viewport->size;
436         int samples = viewport->samples;
437         bool ok = true;
438
439         dtxl->multisample_color = GPU_texture_create_2D_multisample(size[0], size[1], GPU_RGBA8, NULL, samples, NULL);
440         dtxl->multisample_depth = GPU_texture_create_2D_multisample(size[0], size[1], GPU_DEPTH24_STENCIL8, NULL, samples, NULL);
441
442         if (!(dtxl->multisample_depth && dtxl->multisample_color)) {
443                 ok = false;
444                 goto cleanup;
445         }
446
447         GPU_framebuffer_ensure_config(&dfbl->multisample_fb, {
448                 GPU_ATTACHMENT_TEXTURE(dtxl->multisample_depth),
449                 GPU_ATTACHMENT_TEXTURE(dtxl->multisample_color)
450         });
451
452         ok = ok && GPU_framebuffer_check_valid(dfbl->multisample_fb, NULL);
453
454 cleanup:
455         if (!ok) {
456                 GPU_viewport_free(viewport);
457                 DRW_opengl_context_disable();
458                 return;
459         }
460
461         GPU_framebuffer_restore();
462 }
463
464 void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect)
465 {
466         DefaultFramebufferList *dfbl = viewport->fbl;
467         int fbl_len, txl_len;
468
469         /* add one pixel because of scissor test */
470         int rect_w = BLI_rcti_size_x(rect) + 1;
471         int rect_h = BLI_rcti_size_y(rect) + 1;
472
473         DRW_opengl_context_enable();
474
475         if (dfbl->default_fb) {
476                 if (rect_w != viewport->size[0] || rect_h != viewport->size[1] || U.ogl_multisamples != viewport->samples) {
477                         gpu_viewport_buffers_free(
478                                 (FramebufferList *)viewport->fbl, default_fbl_len,
479                                 (TextureList *)viewport->txl, default_txl_len);
480
481                         for (LinkData *link = viewport->data.first; link; link = link->next) {
482                                 ViewportEngineData *data = link->data;
483                                 DRW_engine_viewport_data_size_get(data->engine_type, &fbl_len, &txl_len, NULL, NULL);
484                                 gpu_viewport_buffers_free(data->fbl, fbl_len, data->txl, txl_len);
485                         }
486
487                         gpu_viewport_texture_pool_free(viewport);
488                 }
489         }
490
491         viewport->size[0] = rect_w;
492         viewport->size[1] = rect_h;
493         viewport->samples = U.ogl_multisamples;
494
495         gpu_viewport_texture_pool_clear_users(viewport);
496
497         /* Multisample Buffer */
498         if (viewport->samples > 0) {
499                 if (!dfbl->default_fb) {
500                         gpu_viewport_default_multisample_fb_create(viewport);
501                 }
502         }
503
504         if (!dfbl->default_fb) {
505                 gpu_viewport_default_fb_create(viewport);
506         }
507 }
508
509 void GPU_viewport_draw_to_screen(GPUViewport *viewport, const rcti *rect)
510 {
511         DefaultFramebufferList *dfbl = viewport->fbl;
512
513         if (dfbl->default_fb == NULL)
514                 return;
515
516         DefaultTextureList *dtxl = viewport->txl;
517
518         GPUTexture *color = dtxl->color;
519
520         const float w = (float)GPU_texture_width(color);
521         const float h = (float)GPU_texture_height(color);
522
523         BLI_assert(w == BLI_rcti_size_x(rect) + 1);
524         BLI_assert(h == BLI_rcti_size_y(rect) + 1);
525
526         /* wmOrtho for the screen has this same offset */
527         const float halfx = GLA_PIXEL_OFS / w;
528         const float halfy = GLA_PIXEL_OFS / h;
529
530         float x1 = rect->xmin;
531         float x2 = rect->xmin + w;
532         float y1 = rect->ymin;
533         float y2 = rect->ymin + h;
534
535         GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_RECT_COLOR);
536         GPU_shader_bind(shader);
537
538         GPU_texture_bind(color, 0);
539         glUniform1i(GPU_shader_get_uniform_ensure(shader, "image"), 0);
540         glUniform4f(GPU_shader_get_uniform_ensure(shader, "rect_icon"), halfx, halfy, 1.0f + halfx, 1.0f + halfy);
541         glUniform4f(GPU_shader_get_uniform_ensure(shader, "rect_geom"), x1, y1, x2, y2);
542         glUniform4f(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_COLOR), 1.0f, 1.0f, 1.0f, 1.0f);
543
544         GPU_draw_primitive(GPU_PRIM_TRI_STRIP, 4);
545
546         GPU_texture_unbind(color);
547 }
548
549 void GPU_viewport_unbind(GPUViewport *UNUSED(viewport))
550 {
551         GPU_framebuffer_restore();
552         DRW_opengl_context_disable();
553 }
554
555
556 GPUTexture *GPU_viewport_color_texture(GPUViewport *viewport)
557 {
558         DefaultFramebufferList *dfbl = viewport->fbl;
559
560         if (dfbl->default_fb) {
561                 DefaultTextureList *dtxl = viewport->txl;
562                 return dtxl->color;
563         }
564
565         return NULL;
566 }
567
568 static void gpu_viewport_buffers_free(
569         FramebufferList *fbl, int fbl_len,
570         TextureList *txl, int txl_len)
571 {
572         for (int i = 0; i < fbl_len; i++) {
573                 GPUFrameBuffer *fb = fbl->framebuffers[i];
574                 if (fb) {
575                         GPU_framebuffer_free(fb);
576                         fbl->framebuffers[i] = NULL;
577                 }
578         }
579         for (int i = 0; i < txl_len; i++) {
580                 GPUTexture *tex = txl->textures[i];
581                 if (tex) {
582                         GPU_texture_free(tex);
583                         txl->textures[i] = NULL;
584                 }
585         }
586 }
587
588 static void gpu_viewport_storage_free(StorageList *stl, int stl_len)
589 {
590         for (int i = 0; i < stl_len; i++) {
591                 void *storage = stl->storage[i];
592                 if (storage) {
593                         MEM_freeN(storage);
594                         stl->storage[i] = NULL;
595                 }
596         }
597 }
598
599 static void gpu_viewport_passes_free(PassList *psl, int psl_len)
600 {
601         for (int i = 0; i < psl_len; i++) {
602                 struct DRWPass *pass = psl->passes[i];
603                 if (pass) {
604                         DRW_pass_free(pass);
605                         psl->passes[i] = NULL;
606                 }
607         }
608 }
609
610 /* Must be executed inside Drawmanager Opengl Context. */
611 void GPU_viewport_free(GPUViewport *viewport)
612 {
613         gpu_viewport_engines_data_free(viewport);
614
615         gpu_viewport_buffers_free(
616                 (FramebufferList *)viewport->fbl, default_fbl_len,
617                 (TextureList *)viewport->txl, default_txl_len);
618
619         gpu_viewport_texture_pool_free(viewport);
620
621         MEM_freeN(viewport->fbl);
622         MEM_freeN(viewport->txl);
623
624         if (viewport->vmempool.calls != NULL) {
625                 BLI_mempool_destroy(viewport->vmempool.calls);
626         }
627         if (viewport->vmempool.states != NULL) {
628                 BLI_mempool_destroy(viewport->vmempool.states);
629         }
630         if (viewport->vmempool.shgroups != NULL) {
631                 BLI_mempool_destroy(viewport->vmempool.shgroups);
632         }
633         if (viewport->vmempool.uniforms != NULL) {
634                 BLI_mempool_destroy(viewport->vmempool.uniforms);
635         }
636         if (viewport->vmempool.passes != NULL) {
637                 BLI_mempool_destroy(viewport->vmempool.passes);
638         }
639
640         DRW_instance_data_list_free(viewport->idatalist);
641         MEM_freeN(viewport->idatalist);
642
643         MEM_freeN(viewport);
644 }