1 /*
2 Copyright (C) 1996-2001 Id Software, Inc.
3 Copyright (C) 2002-2009 John Fitzgibbons and others
4 Copyright (C) 2007-2008 Kristian Duske
5 Copyright (C) 2010-2014 QuakeSpasm developers
6 Copyright (C) 2016 Axel Gneiting
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
17 See the GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22 */
23 
24 //gl_texmgr.c -- fitzquake's texture manager. manages texture images
25 
26 #include "quakedef.h"
27 #include "gl_heap.h"
28 
29 #define STB_IMAGE_RESIZE_IMPLEMENTATION
30 #define STB_IMAGE_RESIZE_STATIC
31 #include "stb_image_resize.h"
32 
33 static cvar_t	gl_max_size = {"gl_max_size", "0", CVAR_NONE};
34 static cvar_t	gl_picmip = {"gl_picmip", "0", CVAR_NONE};
35 
36 extern cvar_t vid_filter;
37 extern cvar_t vid_anisotropic;
38 
39 #define	MAX_MIPS 16
40 static int numgltextures;
41 static gltexture_t	*active_gltextures, *free_gltextures;
42 gltexture_t		*notexture, *nulltexture, *whitetexture, *greytexture;
43 
44 unsigned int d_8to24table[256];
45 unsigned int d_8to24table_fbright[256];
46 unsigned int d_8to24table_fbright_fence[256];
47 unsigned int d_8to24table_nobright[256];
48 unsigned int d_8to24table_nobright_fence[256];
49 unsigned int d_8to24table_conchars[256];
50 unsigned int d_8to24table_shirt[256];
51 unsigned int d_8to24table_pants[256];
52 
53 // Heap
54 #define TEXTURE_HEAP_SIZE_MB 32
55 
56 static glheap_t ** texmgr_heaps;
57 static int num_texmgr_heaps;
58 
59 static byte *image_resize_buffer;
60 static int image_resize_buffer_size;
61 
62 /*
63 ================================================================================
64 
65 	COMMANDS
66 
67 ================================================================================
68 */
69 
70 /*
71 ===============
72 TexMgr_SetFilterModes
73 ===============
74 */
TexMgr_SetFilterModes(gltexture_t * glt)75 static void TexMgr_SetFilterModes (gltexture_t *glt)
76 {
77 	VkDescriptorImageInfo image_info;
78 	memset(&image_info, 0, sizeof(image_info));
79 	image_info.imageView = glt->image_view;
80 	image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
81 
82 	VkSampler point_sampler = (vid_anisotropic.value == 1) ? vulkan_globals.point_aniso_sampler_lod_bias : vulkan_globals.point_sampler_lod_bias;
83 	VkSampler linear_sampler = (vid_anisotropic.value == 1) ? vulkan_globals.linear_aniso_sampler_lod_bias : vulkan_globals.linear_sampler_lod_bias;
84 
85 	if (glt->flags & TEXPREF_NEAREST)
86 		image_info.sampler = point_sampler;
87 	else if (glt->flags & TEXPREF_LINEAR)
88 		image_info.sampler = linear_sampler;
89 	else
90 		image_info.sampler = (vid_filter.value == 1) ? point_sampler : linear_sampler;
91 
92 	VkWriteDescriptorSet texture_write;
93 	memset(&texture_write, 0, sizeof(texture_write));
94 	texture_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
95 	texture_write.dstSet = glt->descriptor_set;
96 	texture_write.dstBinding = 0;
97 	texture_write.dstArrayElement = 0;
98 	texture_write.descriptorCount = 1;
99 	texture_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
100 	texture_write.pImageInfo = &image_info;
101 
102 	vkUpdateDescriptorSets(vulkan_globals.device, 1, &texture_write, 0, NULL);
103 }
104 
105 /*
106 ===============
107 TexMgr_UpdateTextureDescriptorSets
108 ===============
109 */
TexMgr_UpdateTextureDescriptorSets(void)110 void TexMgr_UpdateTextureDescriptorSets(void)
111 {
112 	gltexture_t	*glt;
113 
114 	for (glt = active_gltextures; glt; glt = glt->next)
115 		TexMgr_SetFilterModes (glt);
116 }
117 
118 /*
119 ===============
120 TexMgr_Imagelist_f -- report loaded textures
121 ===============
122 */
TexMgr_Imagelist_f(void)123 static void TexMgr_Imagelist_f (void)
124 {
125 	float mb;
126 	float texels = 0;
127 	gltexture_t	*glt;
128 
129 	for (glt = active_gltextures; glt; glt = glt->next)
130 	{
131 		Con_SafePrintf ("   %4i x%4i %s\n", glt->width, glt->height, glt->name);
132 		if (glt->flags & TEXPREF_MIPMAP)
133 			texels += glt->width * glt->height * 4.0f / 3.0f;
134 		else
135 			texels += (glt->width * glt->height);
136 	}
137 
138 	mb = (texels * 4) / 0x100000;
139 	Con_Printf ("%i textures %i pixels %1.1f megabytes\n", numgltextures, (int)texels, mb);
140 }
141 
142 /*
143 ================================================================================
144 
145 	TEXTURE MANAGER
146 
147 ================================================================================
148 */
149 
150 /*
151 ================
152 TexMgr_FindTexture
153 ================
154 */
TexMgr_FindTexture(qmodel_t * owner,const char * name)155 gltexture_t *TexMgr_FindTexture (qmodel_t *owner, const char *name)
156 {
157 	gltexture_t	*glt;
158 
159 	if (name)
160 	{
161 		for (glt = active_gltextures; glt; glt = glt->next)
162 		{
163 			if (glt->owner == owner && !strcmp (glt->name, name))
164 				return glt;
165 		}
166 	}
167 
168 	return NULL;
169 }
170 
171 /*
172 ================
173 TexMgr_NewTexture
174 ================
175 */
TexMgr_NewTexture(void)176 gltexture_t *TexMgr_NewTexture (void)
177 {
178 	gltexture_t *glt;
179 
180 	glt = free_gltextures;
181 	free_gltextures = glt->next;
182 	glt->next = active_gltextures;
183 	active_gltextures = glt;
184 
185 	numgltextures++;
186 	return glt;
187 }
188 
189 static void GL_DeleteTexture (gltexture_t *texture);
190 
191 /*
192 ================
193 TexMgr_FreeTexture
194 ================
195 */
TexMgr_FreeTexture(gltexture_t * kill)196 void TexMgr_FreeTexture (gltexture_t *kill)
197 {
198 	gltexture_t *glt;
199 
200 	if (kill == NULL)
201 	{
202 		Con_Printf ("TexMgr_FreeTexture: NULL texture\n");
203 		return;
204 	}
205 
206 	if (active_gltextures == kill)
207 	{
208 		active_gltextures = kill->next;
209 		kill->next = free_gltextures;
210 		free_gltextures = kill;
211 
212 		GL_DeleteTexture(kill);
213 		numgltextures--;
214 		return;
215 	}
216 
217 	for (glt = active_gltextures; glt; glt = glt->next)
218 	{
219 		if (glt->next == kill)
220 		{
221 			glt->next = kill->next;
222 			kill->next = free_gltextures;
223 			free_gltextures = kill;
224 
225 			GL_DeleteTexture(kill);
226 			numgltextures--;
227 			return;
228 		}
229 	}
230 
231 	Con_Printf ("TexMgr_FreeTexture: not found\n");
232 }
233 
234 /*
235 ================
236 TexMgr_FreeTextures
237 
238 compares each bit in "flags" to the one in glt->flags only if that bit is active in "mask"
239 ================
240 */
TexMgr_FreeTextures(unsigned int flags,unsigned int mask)241 void TexMgr_FreeTextures (unsigned int flags, unsigned int mask)
242 {
243 	gltexture_t *glt, *next;
244 
245 	for (glt = active_gltextures; glt; glt = next)
246 	{
247 		next = glt->next;
248 		if ((glt->flags & mask) == (flags & mask))
249 			TexMgr_FreeTexture (glt);
250 	}
251 }
252 
253 /*
254 ================
255 TexMgr_FreeTexturesForOwner
256 ================
257 */
TexMgr_FreeTexturesForOwner(qmodel_t * owner)258 void TexMgr_FreeTexturesForOwner (qmodel_t *owner)
259 {
260 	gltexture_t *glt, *next;
261 
262 	for (glt = active_gltextures; glt; glt = next)
263 	{
264 		next = glt->next;
265 		if (glt && glt->owner == owner)
266 			TexMgr_FreeTexture (glt);
267 	}
268 }
269 
270 /*
271 ================
272 TexMgr_DeleteTextureObjects
273 ================
274 */
TexMgr_DeleteTextureObjects(void)275 void TexMgr_DeleteTextureObjects (void)
276 {
277 	gltexture_t *glt;
278 
279 	for (glt = active_gltextures; glt; glt = glt->next)
280 	{
281 		GL_DeleteTexture (glt);
282 	}
283 }
284 
285 /*
286 ================================================================================
287 
288 	INIT
289 
290 ================================================================================
291 */
292 
293 /*
294 =================
295 TexMgr_LoadPalette -- johnfitz -- was VID_SetPalette, moved here, renamed, rewritten
296 =================
297 */
TexMgr_LoadPalette(void)298 void TexMgr_LoadPalette (void)
299 {
300 	byte *pal, *src, *dst;
301 	int i, mark;
302 	FILE *f;
303 
304 	COM_FOpenFile ("gfx/palette.lmp", &f, NULL);
305 	if (!f)
306 		Sys_Error ("Couldn't load gfx/palette.lmp");
307 
308 	mark = Hunk_LowMark ();
309 	pal = (byte *) Hunk_Alloc (768);
310 	if (fread (pal, 1, 768, f) != 768)
311 		Sys_Error ("Couldn't load gfx/palette.lmp");
312 	fclose(f);
313 
314 	//standard palette, 255 is transparent
315 	dst = (byte *)d_8to24table;
316 	src = pal;
317 	for (i = 0; i < 256; i++)
318 	{
319 		*dst++ = *src++;
320 		*dst++ = *src++;
321 		*dst++ = *src++;
322 		*dst++ = 255;
323 	}
324 	((byte *) &d_8to24table[255]) [3] = 0;
325 
326 	//fullbright palette, 0-223 are black (for additive blending)
327 	src = pal + 224*3;
328 	dst = (byte *) &d_8to24table_fbright[224];
329 	for (i = 224; i < 256; i++)
330 	{
331 		*dst++ = *src++;
332 		*dst++ = *src++;
333 		*dst++ = *src++;
334 		*dst++ = 255;
335 	}
336 	for (i = 0; i < 224; i++)
337 	{
338 		dst = (byte *) &d_8to24table_fbright[i];
339 		dst[3] = 255;
340 		dst[2] = dst[1] = dst[0] = 0;
341 	}
342 
343 	//nobright palette, 224-255 are black (for additive blending)
344 	dst = (byte *)d_8to24table_nobright;
345 	src = pal;
346 	for (i = 0; i < 256; i++)
347 	{
348 		*dst++ = *src++;
349 		*dst++ = *src++;
350 		*dst++ = *src++;
351 		*dst++ = 255;
352 	}
353 	for (i = 224; i < 256; i++)
354 	{
355 		dst = (byte *) &d_8to24table_nobright[i];
356 		dst[3] = 255;
357 		dst[2] = dst[1] = dst[0] = 0;
358 	}
359 
360 	//fullbright palette, for fence textures
361 	memcpy(d_8to24table_fbright_fence, d_8to24table_fbright, 256*4);
362 	d_8to24table_fbright_fence[255] = 0; // Alpha of zero.
363 
364 	//nobright palette, for fence textures
365 	memcpy(d_8to24table_nobright_fence, d_8to24table_nobright, 256*4);
366 	d_8to24table_nobright_fence[255] = 0; // Alpha of zero.
367 
368 	//conchars palette, 0 and 255 are transparent
369 	memcpy(d_8to24table_conchars, d_8to24table, 256*4);
370 	((byte *) &d_8to24table_conchars[0]) [3] = 0;
371 
372 	Hunk_FreeToLowMark (mark);
373 }
374 
375 /*
376 ================
377 TexMgr_NewGame
378 ================
379 */
TexMgr_NewGame(void)380 void TexMgr_NewGame (void)
381 {
382 	TexMgr_FreeTextures (0, TEXPREF_PERSIST); //deletes all textures where TEXPREF_PERSIST is unset
383 	TexMgr_LoadPalette ();
384 }
385 
386 /*
387 ================
388 TexMgr_Init
389 
390 must be called before any texture loading
391 ================
392 */
TexMgr_Init(void)393 void TexMgr_Init (void)
394 {
395 	int i;
396 	static byte notexture_data[16] = {159,91,83,255,0,0,0,255,0,0,0,255,159,91,83,255}; //black and pink checker
397 	static byte nulltexture_data[16] = {127,191,255,255,0,0,0,255,0,0,0,255,127,191,255,255}; //black and blue checker
398 	static byte whitetexture_data[16] = {255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255}; //white
399 	static byte greytexture_data[16] = {127,127,127,255,127,127,127,255,127,127,127,255,127,127,127,255}; //50% grey
400 	extern texture_t *r_notexture_mip, *r_notexture_mip2;
401 
402 	// init texture list
403 	free_gltextures = (gltexture_t *) Hunk_AllocName (MAX_GLTEXTURES * sizeof(gltexture_t), "gltextures");
404 	active_gltextures = NULL;
405 	for (i = 0; i < MAX_GLTEXTURES - 1; i++)
406 		free_gltextures[i].next = &free_gltextures[i+1];
407 	free_gltextures[i].next = NULL;
408 	numgltextures = 0;
409 
410 	// palette
411 	TexMgr_LoadPalette ();
412 
413 	Cvar_RegisterVariable (&gl_max_size);
414 	Cvar_RegisterVariable (&gl_picmip);
415 	Cmd_AddCommand ("imagelist", &TexMgr_Imagelist_f);
416 
417 	// load notexture images
418 	notexture = TexMgr_LoadImage (NULL, "notexture", 2, 2, SRC_RGBA, notexture_data, "", (src_offset_t)notexture_data, TEXPREF_NEAREST | TEXPREF_PERSIST | TEXPREF_NOPICMIP);
419 	nulltexture = TexMgr_LoadImage (NULL, "nulltexture", 2, 2, SRC_RGBA, nulltexture_data, "", (src_offset_t)nulltexture_data, TEXPREF_NEAREST | TEXPREF_PERSIST | TEXPREF_NOPICMIP);
420 	whitetexture = TexMgr_LoadImage (NULL, "whitetexture", 2, 2, SRC_RGBA, whitetexture_data, "", (src_offset_t)whitetexture_data, TEXPREF_NEAREST | TEXPREF_PERSIST | TEXPREF_NOPICMIP);
421 	greytexture = TexMgr_LoadImage (NULL, "greytexture", 2, 2, SRC_RGBA, greytexture_data, "", (src_offset_t)greytexture_data, TEXPREF_NEAREST | TEXPREF_PERSIST | TEXPREF_NOPICMIP);
422 
423 	//have to assign these here becuase Mod_Init is called before TexMgr_Init
424 	r_notexture_mip->gltexture = r_notexture_mip2->gltexture = notexture;
425 }
426 
427 /*
428 ================================================================================
429 
430 	IMAGE LOADING
431 
432 ================================================================================
433 */
434 
435 /*
436 ================
437 TexMgr_Downsample
438 ================
439 */
TexMgr_Downsample(unsigned * data,int in_width,int in_height,int out_width,int out_height)440 static unsigned *TexMgr_Downsample (unsigned *data, int in_width, int in_height, int out_width, int out_height)
441 {
442 	const int out_size_bytes = out_width * out_height * 4;
443 
444 	assert((out_width >= 1) && (out_width < in_width));
445 	assert((out_height >= 1) && (out_height < in_height));
446 
447 	if (out_size_bytes > image_resize_buffer_size)
448 		image_resize_buffer = realloc(image_resize_buffer, out_size_bytes);
449 
450 	stbir_resize_uint8((byte*)data, in_width, in_height, 0, (byte*)image_resize_buffer, out_width, out_height, 0, 4);
451 	memcpy(data, image_resize_buffer, out_size_bytes);
452 
453 	return data;
454 }
455 
456 /*
457 ===============
458 TexMgr_AlphaEdgeFix
459 
460 eliminate pink edges on sprites, etc.
461 operates in place on 32bit data
462 ===============
463 */
TexMgr_AlphaEdgeFix(byte * data,int width,int height)464 static void TexMgr_AlphaEdgeFix (byte *data, int width, int height)
465 {
466 	int	i, j, n = 0, b, c[3] = {0,0,0},
467 		lastrow, thisrow, nextrow,
468 		lastpix, thispix, nextpix;
469 	byte	*dest = data;
470 
471 	for (i = 0; i < height; i++)
472 	{
473 		lastrow = width * 4 * ((i == 0) ? height-1 : i-1);
474 		thisrow = width * 4 * i;
475 		nextrow = width * 4 * ((i == height-1) ? 0 : i+1);
476 
477 		for (j = 0; j < width; j++, dest += 4)
478 		{
479 			if (dest[3]) //not transparent
480 				continue;
481 
482 			lastpix = 4 * ((j == 0) ? width-1 : j-1);
483 			thispix = 4 * j;
484 			nextpix = 4 * ((j == width-1) ? 0 : j+1);
485 
486 			b = lastrow + lastpix; if (data[b+3]) {c[0] += data[b]; c[1] += data[b+1]; c[2] += data[b+2]; n++;}
487 			b = thisrow + lastpix; if (data[b+3]) {c[0] += data[b]; c[1] += data[b+1]; c[2] += data[b+2]; n++;}
488 			b = nextrow + lastpix; if (data[b+3]) {c[0] += data[b]; c[1] += data[b+1]; c[2] += data[b+2]; n++;}
489 			b = lastrow + thispix; if (data[b+3]) {c[0] += data[b]; c[1] += data[b+1]; c[2] += data[b+2]; n++;}
490 			b = nextrow + thispix; if (data[b+3]) {c[0] += data[b]; c[1] += data[b+1]; c[2] += data[b+2]; n++;}
491 			b = lastrow + nextpix; if (data[b+3]) {c[0] += data[b]; c[1] += data[b+1]; c[2] += data[b+2]; n++;}
492 			b = thisrow + nextpix; if (data[b+3]) {c[0] += data[b]; c[1] += data[b+1]; c[2] += data[b+2]; n++;}
493 			b = nextrow + nextpix; if (data[b+3]) {c[0] += data[b]; c[1] += data[b+1]; c[2] += data[b+2]; n++;}
494 
495 			//average all non-transparent neighbors
496 			if (n)
497 			{
498 				dest[0] = (byte)(c[0]/n);
499 				dest[1] = (byte)(c[1]/n);
500 				dest[2] = (byte)(c[2]/n);
501 
502 				n = c[0] = c[1] = c[2] = 0;
503 			}
504 		}
505 	}
506 }
507 
508 /*
509 ================
510 TexMgr_8to32
511 ================
512 */
TexMgr_8to32(byte * in,int pixels,unsigned int * usepal)513 static unsigned *TexMgr_8to32 (byte *in, int pixels, unsigned int *usepal)
514 {
515 	int i;
516 	unsigned *out, *data;
517 
518 	out = data = (unsigned *) Hunk_Alloc(pixels*4);
519 
520 	for (i = 0; i < pixels; i++)
521 		*out++ = usepal[*in++];
522 
523 	return data;
524 }
525 
526 /*
527 ================
528 TexMgr_DeriveNumMips
529 ================
530 */
TexMgr_DeriveNumMips(int width,int height)531 static int TexMgr_DeriveNumMips(int width, int height)
532 {
533 	int num_mips = 0;
534 	while(width >= 1 && height >= 1)
535 	{
536 		width /= 2;
537 		height /= 2;
538 		num_mips += 1;
539 	}
540 	return num_mips;
541 }
542 
543 /*
544 ================
545 TexMgr_DeriveStagingSize
546 ================
547 */
TexMgr_DeriveStagingSize(int width,int height)548 static int TexMgr_DeriveStagingSize(int width, int height)
549 {
550 	int size = 0;
551 	while(width >= 1 && height >= 1)
552 	{
553 		size += width * height * 4;
554 		width /= 2;
555 		height /= 2;
556 	}
557 	return size;
558 }
559 
TexMgr_PreMultiply32(byte * in,size_t width,size_t height)560 static byte *TexMgr_PreMultiply32(byte *in, size_t width, size_t height)
561 {
562 	size_t pixels = width * height;
563 	byte *out = (byte *) Hunk_Alloc(pixels*4);
564 	byte *result = out;
565 	while (pixels --> 0)
566 	{
567 		out[0] = (in[0]*in[3])>>8;
568 		out[1] = (in[1]*in[3])>>8;
569 		out[2] = (in[2]*in[3])>>8;
570 		out[3] = in[3];
571 		in += 4;
572 		out += 4;
573 	}
574 	return result;
575 }
576 
577 /*
578 ================
579 TexMgr_LoadImage32 -- handles 32bit source data
580 ================
581 */
TexMgr_LoadImage32(gltexture_t * glt,unsigned * data)582 static void TexMgr_LoadImage32 (gltexture_t *glt, unsigned *data)
583 {
584 	GL_DeleteTexture(glt);
585 
586 	//do this before any rescaling
587 	if (glt->flags & TEXPREF_PREMULTIPLY)
588 		data = (unsigned*)TexMgr_PreMultiply32((byte*)data, glt->width, glt->height);
589 
590 	// mipmap down
591 	int picmip = (glt->flags & TEXPREF_NOPICMIP) ? 0 : q_max((int)gl_picmip.value, 0);
592 	int mipwidth = q_max(glt->width >> picmip, 1);
593 	int mipheight = q_max(glt->height >> picmip, 1);
594 
595 	int maxsize = (int)vulkan_globals.device_properties.limits.maxImageDimension2D;
596 	if ((mipwidth > maxsize) || (mipheight > maxsize))
597 	{
598 		if (mipwidth >= mipheight)
599 		{
600 			mipheight = q_max((mipheight * maxsize) / mipwidth, 1);
601 			mipwidth = maxsize;
602 		}
603 		else
604 		{
605 			mipwidth = q_max((mipwidth * maxsize) / mipheight, 1);
606 			mipheight = maxsize;
607 		}
608 	}
609 
610 	if ((int)glt->width != mipwidth || (int)glt->height != mipheight)
611 	{
612 		TexMgr_Downsample (data, glt->width, glt->height, mipwidth, mipheight);
613 		glt->width = mipwidth;
614 		glt->height = mipheight;
615 		if (glt->flags & TEXPREF_ALPHA)
616 			TexMgr_AlphaEdgeFix ((byte *)data, glt->width, glt->height);
617 	}
618 	int num_mips = (glt->flags & TEXPREF_MIPMAP) ? TexMgr_DeriveNumMips(glt->width, glt->height) : 1;
619 
620 	const qboolean warp_image = (glt->flags & TEXPREF_WARPIMAGE);
621 	if (warp_image)
622 		num_mips = WARPIMAGEMIPS;
623 
624 	// Check for sanity. This should never be reached.
625 	if (num_mips > MAX_MIPS)
626 		Sys_Error("Texture has over %d mips", MAX_MIPS);
627 
628 	VkResult err;
629 
630 	VkImageCreateInfo image_create_info;
631 	memset(&image_create_info, 0, sizeof(image_create_info));
632 	image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
633 	image_create_info.imageType = VK_IMAGE_TYPE_2D;
634 	image_create_info.format = VK_FORMAT_R8G8B8A8_UNORM;
635 	image_create_info.extent.width = glt->width;
636 	image_create_info.extent.height = glt->height;
637 	image_create_info.extent.depth = 1;
638 	image_create_info.mipLevels = num_mips;
639 	image_create_info.arrayLayers = 1;
640 	image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
641 	image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
642 	image_create_info.usage =
643 		warp_image ? (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT)
644 		: (VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
645 	image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
646 	image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
647 
648 	err = vkCreateImage(vulkan_globals.device, &image_create_info, NULL, &glt->image);
649 	if (err != VK_SUCCESS)
650 		Sys_Error("vkCreateImage failed");
651 	GL_SetObjectName((uint64_t)glt->image, VK_OBJECT_TYPE_IMAGE, va("%s image", glt->name));
652 
653 	VkMemoryRequirements memory_requirements;
654 	vkGetImageMemoryRequirements(vulkan_globals.device, glt->image, &memory_requirements);
655 
656 	uint32_t memory_type_index = GL_MemoryTypeFromProperties(memory_requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0);
657 	VkDeviceSize heap_size = TEXTURE_HEAP_SIZE_MB * (VkDeviceSize)1024 * (VkDeviceSize)1024;
658 	VkDeviceSize aligned_offset = GL_AllocateFromHeaps(&num_texmgr_heaps, &texmgr_heaps, heap_size, memory_type_index, VULKAN_MEMORY_TYPE_DEVICE, memory_requirements.size,
659 		memory_requirements.alignment, &glt->heap, &glt->heap_node, &num_vulkan_tex_allocations, "Textures Heap");
660 	err = vkBindImageMemory(vulkan_globals.device, glt->image, glt->heap->memory.handle, aligned_offset);
661 	if (err != VK_SUCCESS)
662 		Sys_Error("vkBindImageMemory failed");
663 
664 	VkImageViewCreateInfo image_view_create_info;
665 	memset(&image_view_create_info, 0, sizeof(image_view_create_info));
666 	image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
667 	image_view_create_info.image = glt->image;
668 	image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
669 	image_view_create_info.format = VK_FORMAT_R8G8B8A8_UNORM;
670 	image_view_create_info.components.r = VK_COMPONENT_SWIZZLE_R;
671 	image_view_create_info.components.g = VK_COMPONENT_SWIZZLE_G;
672 	image_view_create_info.components.b = VK_COMPONENT_SWIZZLE_B;
673 	image_view_create_info.components.a = VK_COMPONENT_SWIZZLE_A;
674 	image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
675 	image_view_create_info.subresourceRange.baseMipLevel = 0;
676 	image_view_create_info.subresourceRange.levelCount = num_mips;
677 	image_view_create_info.subresourceRange.baseArrayLayer = 0;
678 	image_view_create_info.subresourceRange.layerCount = 1;
679 
680 	err = vkCreateImageView(vulkan_globals.device, &image_view_create_info, NULL, &glt->image_view);
681 	if (err != VK_SUCCESS)
682 		Sys_Error("vkCreateImageView failed");
683 	GL_SetObjectName((uint64_t)glt->image_view, VK_OBJECT_TYPE_IMAGE_VIEW, va("%s image view", glt->name));
684 
685 	// Allocate and update descriptor for this texture
686 	glt->descriptor_set = R_AllocateDescriptorSet(&vulkan_globals.single_texture_set_layout);
687 	GL_SetObjectName((uint64_t)glt->descriptor_set, VK_OBJECT_TYPE_DESCRIPTOR_SET, va("%s desc set", glt->name));
688 
689 	TexMgr_SetFilterModes (glt);
690 
691 	// Don't upload data for warp image, will be updated by rendering
692 	if (warp_image)
693 	{
694 		image_view_create_info.subresourceRange.levelCount = 1;
695 		err = vkCreateImageView(vulkan_globals.device, &image_view_create_info, NULL, &glt->target_image_view);
696 		if (err != VK_SUCCESS)
697 			Sys_Error("vkCreateImageView failed");
698 		GL_SetObjectName((uint64_t)glt->target_image_view, VK_OBJECT_TYPE_IMAGE_VIEW, va("%s target image view", glt->name));
699 
700 		VkFramebufferCreateInfo framebuffer_create_info;
701 		memset(&framebuffer_create_info, 0, sizeof(framebuffer_create_info));
702 		framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
703 		framebuffer_create_info.renderPass = vulkan_globals.warp_render_pass;
704 		framebuffer_create_info.attachmentCount = 1;
705 		framebuffer_create_info.pAttachments = &glt->target_image_view;
706 		framebuffer_create_info.width = glt->width;
707 		framebuffer_create_info.height = glt->height;
708 		framebuffer_create_info.layers = 1;
709 		err = vkCreateFramebuffer(vulkan_globals.device, &framebuffer_create_info, NULL, &glt->frame_buffer);
710 		if (err != VK_SUCCESS)
711 			Sys_Error("vkCreateFramebuffer failed");
712 		GL_SetObjectName((uint64_t)glt->frame_buffer, VK_OBJECT_TYPE_FRAMEBUFFER, va("%s framebuffer", glt->name));
713 
714 		// Allocate and update descriptor for this texture
715 		glt->warp_write_descriptor_set = R_AllocateDescriptorSet(&vulkan_globals.single_texture_cs_write_set_layout);
716 		GL_SetObjectName((uint64_t)glt->warp_write_descriptor_set, VK_OBJECT_TYPE_DESCRIPTOR_SET, va("%s warp write desc set", glt->name));
717 
718 		VkDescriptorImageInfo output_image_info;
719 		memset(&output_image_info, 0, sizeof(output_image_info));
720 		output_image_info.imageView = glt->target_image_view;
721 		output_image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
722 
723 		VkWriteDescriptorSet warp_image_write;
724 		memset(&warp_image_write, 0, sizeof(warp_image_write));
725 		warp_image_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
726 		warp_image_write.dstBinding = 0;
727 		warp_image_write.dstArrayElement = 0;
728 		warp_image_write.descriptorCount = 1;
729 		warp_image_write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
730 		warp_image_write.dstSet = glt->warp_write_descriptor_set;
731 		warp_image_write.pImageInfo = &output_image_info;
732 
733 		vkUpdateDescriptorSets(vulkan_globals.device, 1, &warp_image_write, 0, NULL);
734 
735 		return;
736 	}
737 	else {
738 		glt->target_image_view = VK_NULL_HANDLE;
739 		glt->warp_write_descriptor_set = VK_NULL_HANDLE;
740 	}
741 
742 	glt->frame_buffer = VK_NULL_HANDLE;
743 
744 	// Upload
745 	VkBufferImageCopy regions[MAX_MIPS];
746 	memset(&regions, 0, sizeof(regions));
747 
748 	int staging_size = (glt->flags & TEXPREF_MIPMAP) ? TexMgr_DeriveStagingSize(mipwidth, mipheight) : (mipwidth * mipheight * 4);
749 
750 	VkBuffer staging_buffer;
751 	VkCommandBuffer command_buffer;
752 	int staging_offset;
753 	unsigned char * staging_memory = R_StagingAllocate(staging_size, 4, &command_buffer, &staging_buffer, &staging_offset);
754 
755 	int num_regions = 0;
756 	int mip_offset = 0;
757 
758 	if (glt->flags & TEXPREF_MIPMAP)
759 	{
760 		mipwidth = glt->width;
761 		mipheight = glt->height;
762 
763 		while (mipwidth >= 1 && mipheight >= 1)
764 		{
765 			memcpy(staging_memory + mip_offset, data, mipwidth * mipheight * 4);
766 			regions[num_regions].bufferOffset = staging_offset + mip_offset;
767 			regions[num_regions].imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
768 			regions[num_regions].imageSubresource.layerCount = 1;
769 			regions[num_regions].imageSubresource.mipLevel = num_regions;
770 			regions[num_regions].imageExtent.width = mipwidth;
771 			regions[num_regions].imageExtent.height = mipheight;
772 			regions[num_regions].imageExtent.depth = 1;
773 
774 			mip_offset += mipwidth * mipheight * 4;
775 			num_regions += 1;
776 
777 			if (mipwidth > 1 && mipheight > 1)
778 				TexMgr_Downsample(data, mipwidth, mipheight, mipwidth / 2, mipheight / 2);
779 
780 			mipwidth /= 2;
781 			mipheight /= 2;
782 		}
783 	}
784 	else
785 	{
786 		memcpy(staging_memory + mip_offset, data, mipwidth * mipheight * 4);
787 		regions[0].bufferOffset = staging_offset + mip_offset;
788 		regions[0].imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
789 		regions[0].imageSubresource.layerCount = 1;
790 		regions[0].imageSubresource.mipLevel = 0;
791 		regions[0].imageExtent.width = mipwidth;
792 		regions[0].imageExtent.height = mipheight;
793 		regions[0].imageExtent.depth = 1;
794 	}
795 
796 	VkImageMemoryBarrier image_memory_barrier;
797 	memset(&image_memory_barrier, 0, sizeof(image_memory_barrier));
798 	image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
799 	image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
800 	image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
801 	image_memory_barrier.image = glt->image;
802 	image_memory_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
803 	image_memory_barrier.subresourceRange.baseMipLevel = 0;
804 	image_memory_barrier.subresourceRange.levelCount = num_mips;
805 	image_memory_barrier.subresourceRange.baseArrayLayer = 0;
806 	image_memory_barrier.subresourceRange.layerCount = 1;
807 
808 	image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
809 	image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
810 	image_memory_barrier.srcAccessMask = 0;
811 	image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
812 	vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
813 
814 	vkCmdCopyBufferToImage(command_buffer, staging_buffer, glt->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, num_mips, regions);
815 
816 	image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
817 	image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
818 	image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
819 	image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
820 	vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
821 }
822 
823 /*
824 ================
825 TexMgr_LoadImage8 -- handles 8bit source data, then passes it to LoadImage32
826 ================
827 */
TexMgr_LoadImage8(gltexture_t * glt,byte * data)828 static void TexMgr_LoadImage8 (gltexture_t *glt, byte *data)
829 {
830 	GL_DeleteTexture(glt);
831 
832 	extern cvar_t gl_fullbrights;
833 	unsigned int *usepal;
834 	int i;
835 
836 	// HACK HACK HACK -- taken from tomazquake
837 	if (strstr(glt->name, "shot1sid") &&
838 	    glt->width == 32 && glt->height == 32 &&
839 	    CRC_Block(data, 1024) == 65393)
840 	{
841 		// This texture in b_shell1.bsp has some of the first 32 pixels painted white.
842 		// They are invisible in software, but look really ugly in GL. So we just copy
843 		// 32 pixels from the bottom to make it look nice.
844 		memcpy (data, data + 32*31, 32);
845 	}
846 
847 	// detect false alpha cases
848 	if (glt->flags & TEXPREF_ALPHA && !(glt->flags & TEXPREF_CONCHARS))
849 	{
850 		for (i = 0; i < (int) (glt->width * glt->height); i++)
851 			if (data[i] == 255) //transparent index
852 				break;
853 		if (i == (int) (glt->width * glt->height))
854 			glt->flags -= TEXPREF_ALPHA;
855 	}
856 
857 	// choose palette and padbyte
858 	if (glt->flags & TEXPREF_FULLBRIGHT)
859 	{
860 		if (glt->flags & TEXPREF_ALPHA)
861 			usepal = d_8to24table_fbright_fence;
862 		else
863 			usepal = d_8to24table_fbright;
864 	}
865 	else if (glt->flags & TEXPREF_NOBRIGHT && gl_fullbrights.value)
866 	{
867 		if (glt->flags & TEXPREF_ALPHA)
868 			usepal = d_8to24table_nobright_fence;
869 		else
870 			usepal = d_8to24table_nobright;
871 	}
872 	else if (glt->flags & TEXPREF_CONCHARS)
873 	{
874 		usepal = d_8to24table_conchars;
875 	}
876 	else
877 	{
878 		usepal = d_8to24table;
879 	}
880 
881 	// convert to 32bit
882 	data = (byte *)TexMgr_8to32(data, glt->width * glt->height, usepal);
883 
884 	// fix edges
885 	if (glt->flags & TEXPREF_ALPHA)
886 		TexMgr_AlphaEdgeFix (data, glt->width, glt->height);
887 
888 	// upload it
889 	TexMgr_LoadImage32 (glt, (unsigned *)data);
890 }
891 
892 /*
893 ================
894 TexMgr_LoadLightmap -- handles lightmap data
895 ================
896 */
TexMgr_LoadLightmap(gltexture_t * glt,byte * data)897 static void TexMgr_LoadLightmap (gltexture_t *glt, byte *data)
898 {
899 	TexMgr_LoadImage32(glt, (unsigned *)data);
900 }
901 
902 /*
903 ================
904 TexMgr_LoadImage -- the one entry point for loading all textures
905 ================
906 */
TexMgr_LoadImage(qmodel_t * owner,const char * name,int width,int height,enum srcformat format,byte * data,const char * source_file,src_offset_t source_offset,unsigned flags)907 gltexture_t *TexMgr_LoadImage (qmodel_t *owner, const char *name, int width, int height, enum srcformat format,
908 			       byte *data, const char *source_file, src_offset_t source_offset, unsigned flags)
909 {
910 	unsigned short crc;
911 	gltexture_t *glt;
912 	int mark;
913 
914 	if (isDedicated)
915 		return NULL;
916 
917 	// cache check
918 	switch (format)
919 	{
920 	case SRC_INDEXED:
921 		crc = CRC_Block(data, width * height);
922 		break;
923 	case SRC_LIGHTMAP:
924 		crc = CRC_Block(data, width * height * lightmap_bytes);
925 		break;
926 	case SRC_RGBA:
927 		crc = CRC_Block(data, width * height * 4);
928 		break;
929 	default: /* not reachable but avoids compiler warnings */
930 		crc = 0;
931 	}
932 	if ((flags & TEXPREF_OVERWRITE) && (glt = TexMgr_FindTexture (owner, name)))
933 	{
934 		if (glt->source_crc == crc)
935 			return glt;
936 	}
937 	else
938 		glt = TexMgr_NewTexture ();
939 
940 	// copy data
941 	glt->owner = owner;
942 	q_strlcpy (glt->name, name, sizeof(glt->name));
943 	glt->width = width;
944 	glt->height = height;
945 	glt->flags = flags;
946 	glt->shirt = -1;
947 	glt->pants = -1;
948 	q_strlcpy (glt->source_file, source_file, sizeof(glt->source_file));
949 	glt->source_offset = source_offset;
950 	glt->source_format = format;
951 	glt->source_width = width;
952 	glt->source_height = height;
953 	glt->source_crc = crc;
954 
955 	//upload it
956 	mark = Hunk_LowMark();
957 
958 	switch (glt->source_format)
959 	{
960 	case SRC_INDEXED:
961 		TexMgr_LoadImage8 (glt, data);
962 		break;
963 	case SRC_LIGHTMAP:
964 		TexMgr_LoadLightmap (glt, data);
965 		break;
966 	case SRC_RGBA:
967 		TexMgr_LoadImage32 (glt, (unsigned *)data);
968 		break;
969 	}
970 
971 	Hunk_FreeToLowMark(mark);
972 
973 	return glt;
974 }
975 
976 /*
977 ================================================================================
978 
979 	COLORMAPPING AND TEXTURE RELOADING
980 
981 ================================================================================
982 */
983 
984 /*
985 ================
986 TexMgr_ReloadImage -- reloads a texture, and colormaps it if needed
987 ================
988 */
TexMgr_ReloadImage(gltexture_t * glt,int shirt,int pants)989 void TexMgr_ReloadImage (gltexture_t *glt, int shirt, int pants)
990 {
991 	byte	translation[256];
992 	byte	*src, *dst, *data = NULL, *translated;
993 	int	mark, size, i;
994 //
995 // get source data
996 //
997 	mark = Hunk_LowMark ();
998 
999 	if (glt->source_file[0] && glt->source_offset) {
1000 		//lump inside file
1001 		FILE *f;
1002 		COM_FOpenFile(glt->source_file, &f, NULL);
1003 		if (!f) goto invalid;
1004 		fseek (f, glt->source_offset, SEEK_CUR);
1005 		size = glt->source_width * glt->source_height;
1006 		/* should be SRC_INDEXED, but no harm being paranoid:  */
1007 		if (glt->source_format == SRC_RGBA) {
1008 			size *= 4;
1009 		}
1010 		else if (glt->source_format == SRC_LIGHTMAP) {
1011 			size *= lightmap_bytes;
1012 		}
1013 		data = (byte *) Hunk_Alloc (size);
1014 		if (fread (data, 1, size, f) != size)
1015 			goto invalid;
1016 		fclose (f);
1017 	}
1018 	else if (glt->source_file[0] && !glt->source_offset) {
1019 		data = Image_LoadImage (glt->source_file, (int *)&glt->source_width, (int *)&glt->source_height); //simple file
1020 	}
1021 	else if (!glt->source_file[0] && glt->source_offset) {
1022 		data = (byte *) glt->source_offset; //image in memory
1023 	}
1024 	if (!data) {
1025 invalid:	Con_Printf ("TexMgr_ReloadImage: invalid source for %s\n", glt->name);
1026 		Hunk_FreeToLowMark(mark);
1027 		return;
1028 	}
1029 
1030 	glt->width = glt->source_width;
1031 	glt->height = glt->source_height;
1032 //
1033 // apply shirt and pants colors
1034 //
1035 // if shirt and pants are -1,-1, use existing shirt and pants colors
1036 // if existing shirt and pants colors are -1,-1, don't bother colormapping
1037 	if (shirt > -1 && pants > -1)
1038 	{
1039 		if (glt->source_format == SRC_INDEXED)
1040 		{
1041 			glt->shirt = shirt;
1042 			glt->pants = pants;
1043 		}
1044 		else
1045 			Con_Printf ("TexMgr_ReloadImage: can't colormap a non SRC_INDEXED texture: %s\n", glt->name);
1046 	}
1047 	if (glt->shirt > -1 && glt->pants > -1)
1048 	{
1049 		//create new translation table
1050 		for (i = 0; i < 256; i++)
1051 			translation[i] = i;
1052 
1053 		shirt = glt->shirt * 16;
1054 		if (shirt < 128)
1055 		{
1056 			for (i = 0; i < 16; i++)
1057 				translation[TOP_RANGE+i] = shirt + i;
1058 		}
1059 		else
1060 		{
1061 			for (i = 0; i < 16; i++)
1062 				translation[TOP_RANGE+i] = shirt+15-i;
1063 		}
1064 
1065 		pants = glt->pants * 16;
1066 		if (pants < 128)
1067 		{
1068 			for (i = 0; i < 16; i++)
1069 				translation[BOTTOM_RANGE+i] = pants + i;
1070 		}
1071 		else
1072 		{
1073 			for (i = 0; i < 16; i++)
1074 				translation[BOTTOM_RANGE+i] = pants+15-i;
1075 		}
1076 
1077 		//translate texture
1078 		size = glt->width * glt->height;
1079 		dst = translated = (byte *) Hunk_Alloc (size);
1080 		src = data;
1081 
1082 		for (i = 0; i < size; i++)
1083 			*dst++ = translation[*src++];
1084 
1085 		data = translated;
1086 	}
1087 //
1088 // upload it
1089 //
1090 	switch (glt->source_format)
1091 	{
1092 	case SRC_INDEXED:
1093 		TexMgr_LoadImage8 (glt, data);
1094 		break;
1095 	case SRC_LIGHTMAP:
1096 		TexMgr_LoadLightmap (glt, data);
1097 		break;
1098 	case SRC_RGBA:
1099 		TexMgr_LoadImage32 (glt, (unsigned *)data);
1100 		break;
1101 	}
1102 
1103 	Hunk_FreeToLowMark(mark);
1104 }
1105 
1106 /*
1107 ================
1108 TexMgr_ReloadNobrightImages -- reloads all texture that were loaded with the nobright palette.  called when gl_fullbrights changes
1109 ================
1110 */
TexMgr_ReloadNobrightImages(void)1111 void TexMgr_ReloadNobrightImages (void)
1112 {
1113 	gltexture_t *glt;
1114 
1115 	for (glt = active_gltextures; glt; glt = glt->next)
1116 		if (glt->flags & TEXPREF_NOBRIGHT)
1117 			TexMgr_ReloadImage(glt, -1, -1);
1118 }
1119 
1120 /*
1121 ================================================================================
1122 
1123 	TEXTURE BINDING / TEXTURE UNIT SWITCHING
1124 
1125 ================================================================================
1126 */
1127 
1128 typedef struct
1129 {
1130 	VkImage				image;
1131 	VkImageView			target_image_view;
1132 	VkImageView			image_view;
1133 	VkFramebuffer		frame_buffer;
1134 	VkDescriptorSet		descriptor_set;
1135 	VkDescriptorSet		warp_write_descriptor_set;
1136 	glheap_t *			heap;
1137 	glheapnode_t *		heap_node;
1138 } texture_garbage_t;
1139 
1140 static int current_garbage_index;
1141 static int num_garbage_textures[2];
1142 static texture_garbage_t texture_garbage[MAX_GLTEXTURES][2];
1143 
1144 /*
1145 ================
1146 TexMgr_CollectGarbage
1147 ================
1148 */
TexMgr_CollectGarbage(void)1149 void TexMgr_CollectGarbage (void)
1150 {
1151 	int num;
1152 	int i;
1153 	texture_garbage_t * garbage;
1154 
1155 	current_garbage_index = (current_garbage_index + 1) % 2;
1156 	num = num_garbage_textures[current_garbage_index];
1157 	for (i=0; i<num; ++i)
1158 	{
1159 		garbage = &texture_garbage[i][current_garbage_index];
1160 		if (garbage->frame_buffer != VK_NULL_HANDLE)
1161 			vkDestroyFramebuffer(vulkan_globals.device, garbage->frame_buffer, NULL);
1162 		if(garbage->target_image_view)
1163 			vkDestroyImageView(vulkan_globals.device, garbage->target_image_view, NULL);
1164 		vkDestroyImageView(vulkan_globals.device, garbage->image_view, NULL);
1165 		vkDestroyImage(vulkan_globals.device, garbage->image, NULL);
1166 		R_FreeDescriptorSet(garbage->descriptor_set, &vulkan_globals.single_texture_set_layout);
1167 		if (garbage->warp_write_descriptor_set)
1168 			R_FreeDescriptorSet(garbage->descriptor_set, &vulkan_globals.single_texture_cs_write_set_layout);
1169 
1170 		GL_FreeFromHeaps(num_texmgr_heaps, texmgr_heaps, garbage->heap, garbage->heap_node, &num_vulkan_tex_allocations);
1171 	}
1172 	num_garbage_textures[current_garbage_index] = 0;
1173 
1174 
1175 }
1176 
1177 /*
1178 ================
1179 GL_DeleteTexture
1180 ================
1181 */
GL_DeleteTexture(gltexture_t * texture)1182 static void GL_DeleteTexture (gltexture_t *texture)
1183 {
1184 	int garbage_index;
1185 	texture_garbage_t * garbage;
1186 
1187 	if (texture->image_view == VK_NULL_HANDLE)
1188 		return;
1189 
1190 	if (in_update_screen)
1191 	{
1192 		garbage_index = num_garbage_textures[current_garbage_index]++;
1193 		garbage = &texture_garbage[garbage_index][current_garbage_index];
1194 		garbage->image = texture->image;
1195 		garbage->target_image_view = texture->target_image_view;
1196 		garbage->image_view = texture->image_view;
1197 		garbage->frame_buffer = texture->frame_buffer;
1198 		garbage->descriptor_set = texture->descriptor_set;
1199 		garbage->warp_write_descriptor_set = texture->warp_write_descriptor_set;
1200 		garbage->heap = texture->heap;
1201 		garbage->heap_node = texture->heap_node;
1202 	}
1203 	else
1204 	{
1205 		GL_WaitForDeviceIdle();
1206 
1207 		if (texture->frame_buffer != VK_NULL_HANDLE)
1208 			vkDestroyFramebuffer(vulkan_globals.device, texture->frame_buffer, NULL);
1209 		if(texture->target_image_view)
1210 			vkDestroyImageView(vulkan_globals.device, texture->target_image_view, NULL);
1211 		vkDestroyImageView(vulkan_globals.device, texture->image_view, NULL);
1212 		vkDestroyImage(vulkan_globals.device, texture->image, NULL);
1213 		R_FreeDescriptorSet(texture->descriptor_set, &vulkan_globals.single_texture_set_layout);
1214 		if (texture->warp_write_descriptor_set)
1215 			R_FreeDescriptorSet(texture->warp_write_descriptor_set, &vulkan_globals.single_texture_cs_write_set_layout);
1216 
1217 		GL_FreeFromHeaps(num_texmgr_heaps, texmgr_heaps, texture->heap, texture->heap_node, &num_vulkan_tex_allocations);
1218 	}
1219 
1220 	texture->frame_buffer = VK_NULL_HANDLE;
1221 	texture->target_image_view = VK_NULL_HANDLE;
1222 	texture->image_view = VK_NULL_HANDLE;
1223 	texture->image = VK_NULL_HANDLE;
1224 	texture->heap = NULL;
1225 	texture->heap_node = NULL;
1226 }
1227