vkQuake2 doxygen  1.0 dev
vk_image.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 Copyright (C) 2018-2019 Krzysztof Kondrak
4 
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 
14 See the GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 
20 */
21 
22 #include "vk_local.h"
23 
26 int base_textureid; // gltextures[i] = base_textureid+i
27 // texture for storing raw image data (cinematics, endscreens, etc.)
29 
30 static byte intensitytable[256];
31 static unsigned char gammatable[256];
32 
35 
36 unsigned d_8to24table[256];
37 
38 uint32_t Vk_Upload8 (byte *data, int width, int height, qboolean mipmap, qboolean is_sky );
39 uint32_t Vk_Upload32 (unsigned *data, int width, int height, qboolean mipmap);
40 
41 // default global texture and lightmap samplers
44 
45 // internal helper
46 static VkImageAspectFlags getDepthStencilAspect(VkFormat depthFormat)
47 {
48  switch (depthFormat)
49  {
50  case VK_FORMAT_D32_SFLOAT_S8_UINT:
51  case VK_FORMAT_D24_UNORM_S8_UINT:
52  case VK_FORMAT_D16_UNORM_S8_UINT:
53  return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
54  default:
55  return VK_IMAGE_ASPECT_DEPTH_BIT;
56  }
57 }
58 
59 // internal helper
60 static void transitionImageLayout(const VkCommandBuffer *cmdBuffer, const VkQueue *queue, const qvktexture_t *texture, const VkImageLayout oldLayout, const VkImageLayout newLayout)
61 {
62  VkPipelineStageFlags srcStage = 0;
63  VkPipelineStageFlags dstStage = 0;
64 
65  VkImageMemoryBarrier imgBarrier = {
66  .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
67  .pNext = NULL,
68  .oldLayout = oldLayout,
69  .newLayout = newLayout,
70  .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
71  .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
72  .image = texture->image,
73  .subresourceRange.baseMipLevel = 0, // no mip mapping levels
74  .subresourceRange.baseArrayLayer = 0,
75  .subresourceRange.layerCount = 1,
76  .subresourceRange.levelCount = texture->mipLevels
77  };
78 
79  if (newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
80  {
81  imgBarrier.subresourceRange.aspectMask = getDepthStencilAspect(texture->format);
82  }
83  else
84  {
85  imgBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
86  }
87 
88  if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
89  {
90  imgBarrier.srcAccessMask = 0;
91  imgBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
92  srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
93  dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
94  }
95  // transiton that may occur when updating existing image
96  else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
97  {
98  imgBarrier.srcAccessMask = 0;
99  imgBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
100  srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
101  dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
102  }
103  else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
104  {
106  {
107  imgBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
108  imgBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
109  srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
110  dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
111  }
112  else
113  {
114  if (vk_device.transferQueue == *queue)
115  {
116  // if the image is exclusively shared, start queue ownership transfer process (release) - only for VK_SHARING_MODE_EXCLUSIVE
117  imgBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
118  imgBarrier.dstAccessMask = 0;
119  imgBarrier.srcQueueFamilyIndex = vk_device.transferFamilyIndex;
120  imgBarrier.dstQueueFamilyIndex = vk_device.gfxFamilyIndex;
121  srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
122  dstStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
123  }
124  else
125  {
126  // continuing queue transfer (acquisition) - this will only happen for VK_SHARING_MODE_EXCLUSIVE images
127  if (texture->sharingMode == VK_SHARING_MODE_EXCLUSIVE)
128  {
129  imgBarrier.srcAccessMask = 0;
130  imgBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
131  imgBarrier.srcQueueFamilyIndex = vk_device.transferFamilyIndex;
132  imgBarrier.dstQueueFamilyIndex = vk_device.gfxFamilyIndex;
133  srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
134  dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
135  }
136  else
137  {
138  imgBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
139  imgBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
140  srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
141  dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
142  }
143  }
144  }
145  }
146  else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
147  {
148  imgBarrier.srcAccessMask = 0;
149  imgBarrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
150  srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
151  dstStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
152  }
153  else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
154  {
155  imgBarrier.srcAccessMask = 0;
156  imgBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
157  srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
158  dstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
159  }
160  else
161  {
162  assert(0 && !"Invalid image stage!");
163  }
164 
165  vkCmdPipelineBarrier(*cmdBuffer, srcStage, dstStage, 0, 0, NULL, 0, NULL, 1, &imgBarrier);
166 }
167 
168 // internal helper
169 static void generateMipmaps(const VkCommandBuffer *cmdBuffer, const qvktexture_t *texture, uint32_t width, uint32_t height)
170 {
171  int32_t mipWidth = width;
172  int32_t mipHeight = height;
173  VkFilter mipFilter = vk_mip_nearfilter->value > 0 ? VK_FILTER_NEAREST : VK_FILTER_LINEAR;
174 
175  VkImageMemoryBarrier imgBarrier = {
176  .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
177  .pNext = NULL,
178  .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
179  .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
180  .image = texture->image,
181  .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
182  .subresourceRange.levelCount = 1,
183  .subresourceRange.baseArrayLayer = 0,
184  .subresourceRange.layerCount = 1
185  };
186 
187  // copy rescaled mip data between consecutive levels (each higher level is half the size of the previous level)
188  for (uint32_t i = 1; i < texture->mipLevels; ++i)
189  {
190  imgBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
191  imgBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
192  imgBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
193  imgBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
194  imgBarrier.subresourceRange.baseMipLevel = i - 1;
195 
196  vkCmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &imgBarrier);
197 
198  VkImageBlit blit = {
199  .srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
200  .srcSubresource.mipLevel = i - 1,
201  .srcSubresource.baseArrayLayer = 0,
202  .srcSubresource.layerCount = 1,
203  .srcOffsets[0] = { 0, 0, 0 },
204  .srcOffsets[1] = { mipWidth, mipHeight, 1 },
205  .dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
206  .dstSubresource.mipLevel = i,
207  .dstSubresource.baseArrayLayer = 0,
208  .dstSubresource.layerCount = 1,
209  .dstOffsets[0] = { 0, 0, 0 },
210  .dstOffsets[1] = { mipWidth > 1 ? mipWidth >> 1 : 1,
211  mipHeight > 1 ? mipHeight >> 1 : 1, 1 } // each mip level is half the size of the previous level
212  };
213 
214  // src image == dst image, because we're blitting between different mip levels of the same image
215  vkCmdBlitImage(*cmdBuffer, texture->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
216  texture->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, mipFilter);
217 
218  imgBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
219  imgBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
220  imgBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
221  imgBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
222 
223  vkCmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &imgBarrier);
224 
225  // avoid zero-sized mip levels
226  if (mipWidth > 1) mipWidth >>= 1;
227  if (mipHeight > 1) mipHeight >>= 1;
228  }
229 
230  imgBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
231  imgBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
232  imgBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
233  imgBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
234  imgBarrier.subresourceRange.baseMipLevel = texture->mipLevels - 1;
235 
236  vkCmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &imgBarrier);
237 }
238 
239 // internal helper
240 static void createTextureImage(qvktexture_t *dstTex, const unsigned char *data, uint32_t width, uint32_t height)
241 {
242  int unifiedTransferAndGfx = vk_device.transferQueue == vk_device.gfxQueue ? 1 : 0;
243  // assuming 32bit images
244  uint32_t imageSize = width * height * 4;
245 
246  VkBuffer staging_buffer;
247  VkCommandBuffer command_buffer;
248  uint32_t staging_offset;
249  void *imgData = QVk_GetStagingBuffer(imageSize, 4, &command_buffer, &staging_buffer, &staging_offset);
250  memcpy(imgData, data, (size_t)imageSize);
251 
252  VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
253  // set extra image usage flag if we're dealing with mipmapped image - will need it for copying data between mip levels
254  if (dstTex->mipLevels > 1)
255  imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
256 
257  VK_VERIFY(QVk_CreateImage(width, height, dstTex->format, VK_IMAGE_TILING_OPTIMAL, imageUsage, VMA_MEMORY_USAGE_GPU_ONLY, dstTex));
258 
259  transitionImageLayout(&command_buffer, &vk_device.transferQueue, dstTex, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
260  // copy buffer to image
261  VkBufferImageCopy region = {
262  .bufferOffset = staging_offset,
263  .bufferRowLength = 0,
264  .bufferImageHeight = 0,
265  .imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
266  .imageSubresource.mipLevel = 0,
267  .imageSubresource.baseArrayLayer = 0,
268  .imageSubresource.layerCount = 1,
269  .imageOffset = { 0, 0, 0 },
270  .imageExtent = { width, height, 1 }
271  };
272 
273  vkCmdCopyBufferToImage(command_buffer, staging_buffer, dstTex->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
274 
275  if (dstTex->mipLevels > 1)
276  {
277  // vkCmdBlitImage requires a queue with GRAPHICS_BIT present
278  generateMipmaps(&command_buffer, dstTex, width, height);
279  }
280  else
281  {
282  // for non-unified transfer and graphics, this step begins queue ownership transfer to graphics queue (for exclusive sharing only)
283  if (unifiedTransferAndGfx || dstTex->sharingMode == VK_SHARING_MODE_EXCLUSIVE)
284  transitionImageLayout(&command_buffer, &vk_device.transferQueue, dstTex, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
285 
286  if (!unifiedTransferAndGfx)
287  {
288  transitionImageLayout(&command_buffer, &vk_device.gfxQueue, dstTex, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
289  }
290  }
291 }
292 
293 VkResult QVk_CreateImageView(const VkImage *image, VkImageAspectFlags aspectFlags, VkImageView *imageView, VkFormat format, uint32_t mipLevels)
294 {
295  VkImageViewCreateInfo ivCreateInfo = {
296  .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
297  .pNext = NULL,
298  .flags = 0,
299  .image = *image,
300  .viewType = VK_IMAGE_VIEW_TYPE_2D,
301  .format = format,
302  .components.r = VK_COMPONENT_SWIZZLE_IDENTITY,
303  .components.g = VK_COMPONENT_SWIZZLE_IDENTITY,
304  .components.b = VK_COMPONENT_SWIZZLE_IDENTITY,
305  .components.a = VK_COMPONENT_SWIZZLE_IDENTITY,
306  .subresourceRange.aspectMask = aspectFlags,
307  .subresourceRange.baseArrayLayer = 0,
308  .subresourceRange.baseMipLevel = 0,
309  .subresourceRange.layerCount = 1,
310  .subresourceRange.levelCount = mipLevels
311  };
312 
313  return vkCreateImageView(vk_device.logical, &ivCreateInfo, NULL, imageView);
314 }
315 
316 VkResult QVk_CreateImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VmaMemoryUsage memUsage, qvktexture_t *texture)
317 {
318  VkImageCreateInfo imageInfo = {
319  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
320  .imageType = VK_IMAGE_TYPE_2D,
321  .extent.width = width,
322  .extent.height = height,
323  .extent.depth = 1,
324  .mipLevels = texture->mipLevels,
325  .arrayLayers = 1,
326  .format = format,
327  .tiling = tiling,
328  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
329  .usage = usage,
330  .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
331  .samples = texture->sampleCount,
332  .flags = 0
333  };
334 
335  uint32_t queueFamilies[] = { (uint32_t)vk_device.gfxFamilyIndex, (uint32_t)vk_device.transferFamilyIndex };
337  {
338  imageInfo.sharingMode = VK_SHARING_MODE_CONCURRENT;
339  imageInfo.queueFamilyIndexCount = 2;
340  imageInfo.pQueueFamilyIndices = queueFamilies;
341  }
342 
343  VmaAllocationCreateInfo vmallocInfo = {
344  .flags = texture->vmaFlags,
345  .usage = memUsage
346  };
347 
348  texture->sharingMode = imageInfo.sharingMode;
349  return vmaCreateImage(vk_malloc, &imageInfo, &vmallocInfo, &texture->image, &texture->allocation, &texture->allocInfo);
350 }
351 
352 void QVk_CreateDepthBuffer(VkSampleCountFlagBits sampleCount, qvktexture_t *depthBuffer)
353 {
354  depthBuffer->format = QVk_FindDepthFormat();
355  depthBuffer->sampleCount = sampleCount;
356  // On 64-bit builds, Intel drivers throw a warning:
357  // "Mapping an image with layout VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL can result in undefined behavior if this memory is used by the device. Only GENERAL or PREINITIALIZED should be used."
358  // Minor annoyance but we don't want any validation warnings, so we create dedicated allocation for depth buffer.
359  // more details: https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/issues/34
360  // Note that this is a false positive which in other cases could be ignored: https://gpuopen-librariesandsdks.github.io/VulkanMemoryAllocator/html/general_considerations.html#general_considerations_validation_layer_warnings
362 
363  VK_VERIFY(QVk_CreateImage(vk_swapchain.extent.width, vk_swapchain.extent.height, depthBuffer->format, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VMA_MEMORY_USAGE_GPU_ONLY, depthBuffer));
364  VK_VERIFY(QVk_CreateImageView(&depthBuffer->image, getDepthStencilAspect(depthBuffer->format), &depthBuffer->imageView, depthBuffer->format, depthBuffer->mipLevels));
365 }
366 
367 void QVk_CreateColorBuffer(VkSampleCountFlagBits sampleCount, qvktexture_t *colorBuffer, int extraFlags)
368 {
369  colorBuffer->format = vk_swapchain.format;
370  colorBuffer->sampleCount = sampleCount;
371  // On 64-bit builds, Intel drivers throw a warning:
372  // "Mapping an image with layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL can result in undefined behavior if this memory is used by the device. Only GENERAL or PREINITIALIZED should be used."
373  // Minor annoyance but we don't want any validation warnings, so we create dedicated allocation for color buffer.
374  // more details: https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/issues/34
375  // Note that this is a false positive which in other cases could be ignored: https://gpuopen-librariesandsdks.github.io/VulkanMemoryAllocator/html/general_considerations.html#general_considerations_validation_layer_warnings
377 
378  VK_VERIFY(QVk_CreateImage(vk_swapchain.extent.width, vk_swapchain.extent.height, colorBuffer->format, VK_IMAGE_TILING_OPTIMAL, extraFlags | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VMA_MEMORY_USAGE_GPU_ONLY, colorBuffer));
379  VK_VERIFY(QVk_CreateImageView(&colorBuffer->image, VK_IMAGE_ASPECT_COLOR_BIT, &colorBuffer->imageView, colorBuffer->format, colorBuffer->mipLevels));
380 }
381 
382 void QVk_CreateTexture(qvktexture_t *texture, const unsigned char *data, uint32_t width, uint32_t height, qvksampler_t samplerType)
383 {
385  VK_VERIFY(QVk_CreateImageView(&texture->image, VK_IMAGE_ASPECT_COLOR_BIT, &texture->imageView, texture->format, texture->mipLevels));
386 
387  // create descriptor set for the texture
388  VkDescriptorSetAllocateInfo dsAllocInfo = {
389  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
390  .pNext = NULL,
391  .descriptorPool = vk_descriptorPool,
392  .descriptorSetCount = 1,
393  .pSetLayouts = &vk_samplerDescSetLayout
394  };
395 
396  VK_VERIFY(vkAllocateDescriptorSets(vk_device.logical, &dsAllocInfo, &texture->descriptorSet));
397 
398  // attach sampler
399  QVk_UpdateTextureSampler(texture, samplerType);
400 }
401 
402 void QVk_UpdateTextureData(qvktexture_t *texture, const unsigned char *data, uint32_t offset_x, uint32_t offset_y, uint32_t width, uint32_t height)
403 {
404  int unifiedTransferAndGfx = vk_device.transferQueue == vk_device.gfxQueue ? 1 : 0;
405  // assuming 32bit images
406  uint32_t imageSize = width * height * 4;
407 
408  VkBuffer staging_buffer;
409  VkCommandBuffer command_buffer;
410  uint32_t staging_offset;
411  void *imgData = QVk_GetStagingBuffer(imageSize, 4, &command_buffer, &staging_buffer, &staging_offset);
412  memcpy(imgData, data, (size_t)imageSize);
413 
414  transitionImageLayout(&command_buffer, &vk_device.transferQueue, texture, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
415  // copy buffer to image
416  VkBufferImageCopy region = {
417  .bufferOffset = staging_offset,
418  .bufferRowLength = 0,
419  .bufferImageHeight = 0,
420  .imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
421  .imageSubresource.mipLevel = 0,
422  .imageSubresource.baseArrayLayer = 0,
423  .imageSubresource.layerCount = 1,
424  .imageOffset = { offset_x, offset_y, 0 },
425  .imageExtent = { width, height, 1 }
426  };
427 
428  vkCmdCopyBufferToImage(command_buffer, staging_buffer, texture->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
429 
430  if (texture->mipLevels > 1)
431  {
432  // vkCmdBlitImage requires a queue with GRAPHICS_BIT present
433  generateMipmaps(&command_buffer, texture, width, height);
434  }
435  else
436  {
437  // for non-unified transfer and graphics, this step begins queue ownership transfer to graphics queue (for exclusive sharing only)
438  if (unifiedTransferAndGfx || texture->sharingMode == VK_SHARING_MODE_EXCLUSIVE)
439  transitionImageLayout(&command_buffer, &vk_device.transferQueue, texture, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
440 
441  if (!unifiedTransferAndGfx)
442  {
443  transitionImageLayout(&command_buffer, &vk_device.gfxQueue, texture, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
444  }
445  }
446 }
447 
449 {
451  vkDeviceWaitIdle(vk_device.logical);
452 
453  if (texture->image != VK_NULL_HANDLE)
454  vmaDestroyImage(vk_malloc, texture->image, texture->allocation);
455  if (texture->imageView != VK_NULL_HANDLE)
456  vkDestroyImageView(vk_device.logical, texture->imageView, NULL);
457  if (texture->descriptorSet != VK_NULL_HANDLE)
458  vkFreeDescriptorSets(vk_device.logical, vk_descriptorPool, 1, &texture->descriptorSet);
459 
460  texture->image = VK_NULL_HANDLE;
461  texture->imageView = VK_NULL_HANDLE;
462  texture->descriptorSet = VK_NULL_HANDLE;
463 }
464 
465 void QVk_ReadPixels(uint8_t *dstBuffer, uint32_t width, uint32_t height)
466 {
467  qvkbuffer_t buff;
468  VkCommandBuffer cmdBuffer;
469  qvkbufferopts_t buffOpts = {
470  .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT,
471  .reqMemFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
472  .prefMemFlags = VK_MEMORY_PROPERTY_HOST_CACHED_BIT,
473  .vmaUsage = VMA_MEMORY_USAGE_CPU_ONLY,
474  // When taking a screenshot on Intel, the Linux driver may throw a warning:
475  // "Mapping an image with layout VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL can result in undefined behavior if this memory is used by the device. Only GENERAL or PREINITIALIZED should be used."
476  // Minor annoyance but we don't want any validation warnings, so we create dedicated allocation for the image buffer.
477  // more details: https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/issues/34
478  // Note that this is a false positive which in other cases could be ignored: https://gpuopen-librariesandsdks.github.io/VulkanMemoryAllocator/html/general_considerations.html#general_considerations_validation_layer_warnings
480  };
481 
482  VK_VERIFY(QVk_CreateBuffer(width * height * 4, &buff, buffOpts));
483  cmdBuffer = QVk_CreateCommandBuffer(&vk_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
484  VK_VERIFY(QVk_BeginCommand(&cmdBuffer));
485 
486  // transition the current swapchain image to be a source of data transfer to our buffer
487  extern int vk_activeBufferIdx;
488  VkImageMemoryBarrier imgBarrier = {
489  .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
490  .pNext = NULL,
491  .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
492  .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
493  .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
494  .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
495  .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
496  .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
498  .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
499  .subresourceRange.baseMipLevel = 0,
500  .subresourceRange.baseArrayLayer = 0,
501  .subresourceRange.layerCount = 1,
502  .subresourceRange.levelCount = 1
503  };
504 
505  vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &imgBarrier);
506 
507  VkBufferImageCopy region = {
508  .bufferOffset = 0,
509  .bufferRowLength = width,
510  .bufferImageHeight = height,
511  .imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
512  .imageSubresource.mipLevel = 0,
513  .imageSubresource.baseArrayLayer = 0,
514  .imageSubresource.layerCount = 1,
515  .imageOffset = { 0, 0, 0 },
516  .imageExtent = { width, height, 1 }
517  };
518 
519  // copy the swapchain image
520  vkCmdCopyImageToBuffer(cmdBuffer, vk_swapchain.images[vk_activeBufferIdx], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buff.buffer, 1, &region);
521  VK_VERIFY(vkDeviceWaitIdle(vk_device.logical));
522  QVk_SubmitCommand(&cmdBuffer, &vk_device.gfxQueue);
523 
524  // store image in destination buffer
525  memcpy(dstBuffer, (uint8_t *)buff.allocInfo.pMappedData, width * height * 4);
526 
527  QVk_FreeBuffer(&buff);
528 }
529 
530 /*
531 ===============
532 Vk_ImageList_f
533 ===============
534 */
535 void Vk_ImageList_f (void)
536 {
537  int i;
538  image_t *image;
539  int texels;
540 
541  ri.Con_Printf(PRINT_ALL, "------------------\n");
542  texels = 0;
543 
544  for (i = 0, image = vktextures; i < numvktextures; i++, image++)
545  {
546  if (image->vk_texture.image == VK_NULL_HANDLE)
547  continue;
548  texels += image->upload_width*image->upload_height;
549  switch (image->type)
550  {
551  case it_skin:
552  ri.Con_Printf(PRINT_ALL, "M");
553  break;
554  case it_sprite:
555  ri.Con_Printf(PRINT_ALL, "S");
556  break;
557  case it_wall:
558  ri.Con_Printf(PRINT_ALL, "W");
559  break;
560  case it_pic:
561  ri.Con_Printf(PRINT_ALL, "P");
562  break;
563  default:
564  ri.Con_Printf(PRINT_ALL, " ");
565  break;
566  }
567 
568  ri.Con_Printf(PRINT_ALL, " %3i %3i RGB: %s\n",
569  image->upload_width, image->upload_height, image->name);
570  }
571  ri.Con_Printf(PRINT_ALL, "Total texel count (not counting mipmaps): %i\n", texels);
572 }
573 
574 
575 /*
576 =============================================================================
577 
578  scrap allocation
579 
580  Allocate all the little status bar obejcts into a single texture
581  to crutch up inefficient hardware / drivers
582 
583 =============================================================================
584 */
585 
586 #define MAX_SCRAPS 1
587 #define BLOCK_WIDTH 256
588 #define BLOCK_HEIGHT 256
589 
592 // textures for storing scrap image data (tiny image atlas)
594 
595 // returns a texture number and the position inside it
596 int Scrap_AllocBlock (int w, int h, int *x, int *y)
597 {
598  int i, j;
599  int best, best2;
600  int texnum;
601 
602  for (texnum=0 ; texnum<MAX_SCRAPS ; texnum++)
603  {
604  best = BLOCK_HEIGHT;
605 
606  for (i=0 ; i<BLOCK_WIDTH-w ; i++)
607  {
608  best2 = 0;
609 
610  for (j=0 ; j<w ; j++)
611  {
612  if (scrap_allocated[texnum][i+j] >= best)
613  break;
614  if (scrap_allocated[texnum][i+j] > best2)
615  best2 = scrap_allocated[texnum][i+j];
616  }
617  if (j == w)
618  { // this is a valid spot
619  *x = i;
620  *y = best = best2;
621  }
622  }
623 
624  if (best + h > BLOCK_HEIGHT)
625  continue;
626 
627  for (i=0 ; i<w ; i++)
628  scrap_allocated[texnum][*x + i] = best + h;
629 
630  return texnum;
631  }
632 
633  return -1;
634 // Sys_Error ("Scrap_AllocBlock: full");
635 }
636 
637 typedef struct
638 {
639  char *name;
641 } vkmode_t;
642 
644  {"VK_NEAREST", S_NEAREST },
645  {"VK_LINEAR", S_LINEAR },
646  {"VK_MIPMAP_NEAREST", S_MIPMAP_NEAREST },
647  {"VK_MIPMAP_LINEAR", S_MIPMAP_LINEAR }
648 };
649 
650 #define NUM_VK_MODES (sizeof(modes) / sizeof (vkmode_t))
651 
652 /*
653  ===============
654  Vk_TextureMode
655  ===============
656  */
657 void Vk_TextureMode( char *string )
658 {
659  int i,j;
660  image_t *image;
661  static char prev_mode[32] = { "VK_MIPMAP_LINEAR" };
662 
663  for (i = 0; i < NUM_VK_MODES; i++)
664  {
665  if (!Q_stricmp(modes[i].name, string))
666  break;
667  }
668 
669  if (i == NUM_VK_MODES)
670  {
671  ri.Con_Printf(PRINT_ALL, "bad filter name (valid values: VK_NEAREST, VK_LINEAR, VK_MIPMAP_NEAREST, VK_MIPMAP_LINEAR)\n");
672  ri.Cvar_Set("vk_texturemode", prev_mode);
673  return;
674  }
675 
676  memcpy(prev_mode, string, strlen(string));
677  prev_mode[strlen(string)] = '\0';
678 
679  i += vk_aniso->value > 0 ? NUM_VK_MODES : 0;
681 
682  vkDeviceWaitIdle(vk_device.logical);
683  for (j = 0, image = vktextures; j < numvktextures; j++, image++)
684  {
685  // skip console characters - we want them unfiltered at all times
686  if (image->vk_texture.image != VK_NULL_HANDLE && Q_stricmp(image->name, "pics/conchars.pcx"))
688  }
689 
690  for (j = 0; j < MAX_SCRAPS; j++)
691  {
692  if (vk_scrapTextures[j].image != VK_NULL_HANDLE)
694  }
695 
696  if (vk_rawTexture.image != VK_NULL_HANDLE)
698 }
699 
700 /*
701  ===============
702  Vk_LmapTextureMode
703  ===============
704  */
705 void Vk_LmapTextureMode( char *string )
706 {
707  int i,j;
708  static char prev_mode[32] = { "VK_MIPMAP_LINEAR" };
709 
710  for (i = 0; i < NUM_VK_MODES; i++)
711  {
712  if (!Q_stricmp(modes[i].name, string))
713  break;
714  }
715 
716  if (i == NUM_VK_MODES)
717  {
718  ri.Con_Printf(PRINT_ALL, "bad filter name (valid values: VK_NEAREST, VK_LINEAR, VK_MIPMAP_NEAREST, VK_MIPMAP_LINEAR)\n");
719  ri.Cvar_Set("vk_lmaptexturemode", prev_mode);
720  return;
721  }
722 
723  memcpy(prev_mode, string, strlen(string));
724  prev_mode[strlen(string)] = '\0';
725 
726  i += vk_aniso->value > 0 ? NUM_VK_MODES : 0;
728 
729  vkDeviceWaitIdle(vk_device.logical);
730  for (j = 0; j < MAX_LIGHTMAPS*2; j++)
731  {
732  if (vk_state.lightmap_textures[j].image != VK_NULL_HANDLE)
734  }
735 }
736 
737 /*
738 =================================================================
739 
740 PCX LOADING
741 
742 =================================================================
743 */
744 
745 
746 /*
747 ==============
748 LoadPCX
749 ==============
750 */
751 void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height)
752 {
753  byte *raw;
754  pcx_t *pcx;
755  int x, y;
756  int len;
757  int dataByte, runLength;
758  byte *out, *pix;
759 
760  *pic = NULL;
761  *palette = NULL;
762 
763  //
764  // load the file
765  //
766  len = ri.FS_LoadFile (filename, (void **)&raw);
767  if (!raw)
768  {
769  ri.Con_Printf (PRINT_DEVELOPER, "Bad pcx file %s\n", filename);
770  return;
771  }
772 
773  //
774  // parse the PCX file
775  //
776  pcx = (pcx_t *)raw;
777 
778  pcx->xmin = LittleShort(pcx->xmin);
779  pcx->ymin = LittleShort(pcx->ymin);
780  pcx->xmax = LittleShort(pcx->xmax);
781  pcx->ymax = LittleShort(pcx->ymax);
782  pcx->hres = LittleShort(pcx->hres);
783  pcx->vres = LittleShort(pcx->vres);
786 
787  raw = &pcx->data;
788 
789  if (pcx->manufacturer != 0x0a
790  || pcx->version != 5
791  || pcx->encoding != 1
792  || pcx->bits_per_pixel != 8
793  || pcx->xmax >= 640
794  || pcx->ymax >= 480)
795  {
796  ri.Con_Printf (PRINT_ALL, "Bad pcx file %s\n", filename);
797  return;
798  }
799 
800  out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
801 
802  *pic = out;
803 
804  pix = out;
805 
806  if (palette)
807  {
808  *palette = malloc(768);
809  memcpy (*palette, (byte *)pcx + len - 768, 768);
810  }
811 
812  if (width)
813  *width = pcx->xmax+1;
814  if (height)
815  *height = pcx->ymax+1;
816 
817  for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1)
818  {
819  for (x=0 ; x<=pcx->xmax ; )
820  {
821  dataByte = *raw++;
822 
823  if((dataByte & 0xC0) == 0xC0)
824  {
825  runLength = dataByte & 0x3F;
826  dataByte = *raw++;
827  }
828  else
829  runLength = 1;
830 
831  while(runLength-- > 0)
832  pix[x++] = dataByte;
833  }
834 
835  }
836 
837  if ( raw - (byte *)pcx > len)
838  {
839  ri.Con_Printf (PRINT_DEVELOPER, "PCX file %s was malformed", filename);
840  free (*pic);
841  *pic = NULL;
842  }
843 
844  ri.FS_FreeFile (pcx);
845 }
846 
847 /*
848 =========================================================
849 
850 TARGA LOADING
851 
852 =========================================================
853 */
854 
855 typedef struct _TargaHeader {
856  unsigned char id_length, colormap_type, image_type;
857  unsigned short colormap_index, colormap_length;
858  unsigned char colormap_size;
859  unsigned short x_origin, y_origin, width, height;
860  unsigned char pixel_size, attributes;
861 } TargaHeader;
862 
863 
864 /*
865 =============
866 LoadTGA
867 =============
868 */
869 void LoadTGA (char *name, byte **pic, int *width, int *height)
870 {
871  int columns, rows, numPixels;
872  byte *pixbuf;
873  int row, column;
874  byte *buf_p;
875  byte *buffer;
876  int length;
877  TargaHeader targa_header;
878  byte *targa_rgba;
879  byte tmp[2];
880 
881  *pic = NULL;
882 
883  //
884  // load the file
885  //
886  length = ri.FS_LoadFile (name, (void **)&buffer);
887  if (!buffer)
888  {
889  ri.Con_Printf (PRINT_DEVELOPER, "Bad tga file %s\n", name);
890  return;
891  }
892 
893  buf_p = buffer;
894 
895  targa_header.id_length = *buf_p++;
896  targa_header.colormap_type = *buf_p++;
897  targa_header.image_type = *buf_p++;
898 
899  tmp[0] = buf_p[0];
900  tmp[1] = buf_p[1];
901  targa_header.colormap_index = LittleShort ( *((short *)tmp) );
902  buf_p+=2;
903  tmp[0] = buf_p[0];
904  tmp[1] = buf_p[1];
905  targa_header.colormap_length = LittleShort ( *((short *)tmp) );
906  buf_p+=2;
907  targa_header.colormap_size = *buf_p++;
908  targa_header.x_origin = LittleShort ( *((short *)buf_p) );
909  buf_p+=2;
910  targa_header.y_origin = LittleShort ( *((short *)buf_p) );
911  buf_p+=2;
912  targa_header.width = LittleShort ( *((short *)buf_p) );
913  buf_p+=2;
914  targa_header.height = LittleShort ( *((short *)buf_p) );
915  buf_p+=2;
916  targa_header.pixel_size = *buf_p++;
917  targa_header.attributes = *buf_p++;
918 
919  if (targa_header.image_type!=2
920  && targa_header.image_type!=10)
921  ri.Sys_Error (ERR_DROP, "LoadTGA: Only type 2 and 10 targa RGB images supported\n");
922 
923  if (targa_header.colormap_type !=0
924  || (targa_header.pixel_size!=32 && targa_header.pixel_size!=24))
925  ri.Sys_Error (ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
926 
927  columns = targa_header.width;
928  rows = targa_header.height;
929  numPixels = columns * rows;
930 
931  if (width)
932  *width = columns;
933  if (height)
934  *height = rows;
935 
936  targa_rgba = malloc (numPixels*4);
937  *pic = targa_rgba;
938 
939  if (targa_header.id_length != 0)
940  buf_p += targa_header.id_length; // skip TARGA image comment
941 
942  if (targa_header.image_type==2) { // Uncompressed, RGB images
943  for(row=rows-1; row>=0; row--) {
944  pixbuf = targa_rgba + row*columns*4;
945  for(column=0; column<columns; column++) {
946  unsigned char red,green,blue,alphabyte;
947  switch (targa_header.pixel_size) {
948  case 24:
949 
950  blue = *buf_p++;
951  green = *buf_p++;
952  red = *buf_p++;
953  *pixbuf++ = red;
954  *pixbuf++ = green;
955  *pixbuf++ = blue;
956  *pixbuf++ = 255;
957  break;
958  case 32:
959  blue = *buf_p++;
960  green = *buf_p++;
961  red = *buf_p++;
962  alphabyte = *buf_p++;
963  *pixbuf++ = red;
964  *pixbuf++ = green;
965  *pixbuf++ = blue;
966  *pixbuf++ = alphabyte;
967  break;
968  }
969  }
970  }
971  }
972  else if (targa_header.image_type==10) { // Runlength encoded RGB images
973  unsigned char red = 0,green = 0,blue = 0,alphabyte = 0,packetHeader,packetSize,j;
974  for(row=rows-1; row>=0; row--) {
975  pixbuf = targa_rgba + row*columns*4;
976  for(column=0; column<columns; ) {
977  packetHeader= *buf_p++;
978  packetSize = 1 + (packetHeader & 0x7f);
979  if (packetHeader & 0x80) { // run-length packet
980  switch (targa_header.pixel_size) {
981  case 24:
982  blue = *buf_p++;
983  green = *buf_p++;
984  red = *buf_p++;
985  alphabyte = 255;
986  break;
987  case 32:
988  blue = *buf_p++;
989  green = *buf_p++;
990  red = *buf_p++;
991  alphabyte = *buf_p++;
992  break;
993  }
994 
995  for(j=0;j<packetSize;j++) {
996  *pixbuf++=red;
997  *pixbuf++=green;
998  *pixbuf++=blue;
999  *pixbuf++=alphabyte;
1000  column++;
1001  if (column==columns) { // run spans across rows
1002  column=0;
1003  if (row>0)
1004  row--;
1005  else
1006  goto breakOut;
1007  pixbuf = targa_rgba + row*columns*4;
1008  }
1009  }
1010  }
1011  else { // non run-length packet
1012  for(j=0;j<packetSize;j++) {
1013  switch (targa_header.pixel_size) {
1014  case 24:
1015  blue = *buf_p++;
1016  green = *buf_p++;
1017  red = *buf_p++;
1018  *pixbuf++ = red;
1019  *pixbuf++ = green;
1020  *pixbuf++ = blue;
1021  *pixbuf++ = 255;
1022  break;
1023  case 32:
1024  blue = *buf_p++;
1025  green = *buf_p++;
1026  red = *buf_p++;
1027  alphabyte = *buf_p++;
1028  *pixbuf++ = red;
1029  *pixbuf++ = green;
1030  *pixbuf++ = blue;
1031  *pixbuf++ = alphabyte;
1032  break;
1033  }
1034  column++;
1035  if (column==columns) { // pixel packet run spans across rows
1036  column=0;
1037  if (row>0)
1038  row--;
1039  else
1040  goto breakOut;
1041  pixbuf = targa_rgba + row*columns*4;
1042  }
1043  }
1044  }
1045  }
1046  breakOut:;
1047  }
1048  }
1049 
1050  ri.FS_FreeFile (buffer);
1051 }
1052 
1053 
1054 /*
1055 ====================================================================
1056 
1057 IMAGE FLOOD FILLING
1058 
1059 ====================================================================
1060 */
1061 
1062 
1063 /*
1064 =================
1065 Mod_FloodFillSkin
1066 
1067 Fill background pixels so mipmapping doesn't have haloes
1068 =================
1069 */
1070 
1071 typedef struct
1072 {
1073  short x, y;
1074 } floodfill_t;
1075 
1076 // must be a power of 2
1077 #define FLOODFILL_FIFO_SIZE 0x1000
1078 #define FLOODFILL_FIFO_MASK (FLOODFILL_FIFO_SIZE - 1)
1079 
1080 #define FLOODFILL_STEP( off, dx, dy ) \
1081 { \
1082  if (pos[off] == fillcolor) \
1083  { \
1084  pos[off] = 255; \
1085  fifo[inpt].x = x + (dx), fifo[inpt].y = y + (dy); \
1086  inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; \
1087  } \
1088  else if (pos[off] != 255) fdc = pos[off]; \
1089 }
1090 
1091 void R_FloodFillSkin( byte *skin, int skinwidth, int skinheight )
1092 {
1093  byte fillcolor = *skin; // assume this is the pixel to fill
1095  int inpt = 0, outpt = 0;
1096  int filledcolor = -1;
1097  int i;
1098 
1099  if (filledcolor == -1)
1100  {
1101  filledcolor = 0;
1102  // attempt to find opaque black
1103  for (i = 0; i < 256; ++i)
1104  if (d_8to24table[i] == (255 << 0)) // alpha 1.0
1105  {
1106  filledcolor = i;
1107  break;
1108  }
1109  }
1110 
1111  // can't fill to filled color or to transparent color (used as visited marker)
1112  if ((fillcolor == filledcolor) || (fillcolor == 255))
1113  {
1114  //printf( "not filling skin from %d to %d\n", fillcolor, filledcolor );
1115  return;
1116  }
1117 
1118  fifo[inpt].x = 0, fifo[inpt].y = 0;
1119  inpt = (inpt + 1) & FLOODFILL_FIFO_MASK;
1120 
1121  while (outpt != inpt)
1122  {
1123  int x = fifo[outpt].x, y = fifo[outpt].y;
1124  int fdc = filledcolor;
1125  byte *pos = &skin[x + skinwidth * y];
1126 
1127  outpt = (outpt + 1) & FLOODFILL_FIFO_MASK;
1128 
1129  if (x > 0) FLOODFILL_STEP( -1, -1, 0 );
1130  if (x < skinwidth - 1) FLOODFILL_STEP( 1, 1, 0 );
1131  if (y > 0) FLOODFILL_STEP( -skinwidth, 0, -1 );
1132  if (y < skinheight - 1) FLOODFILL_STEP( skinwidth, 0, 1 );
1133  skin[x + skinwidth * y] = fdc;
1134  }
1135 }
1136 
1137 //=======================================================
1138 
1139 
1140 /*
1141 ================
1142 Vk_ResampleTexture
1143 ================
1144 */
1145 void Vk_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out, int outwidth, int outheight)
1146 {
1147  int i, j;
1148  unsigned *inrow, *inrow2;
1149  unsigned frac, fracstep;
1150  unsigned p1[1024], p2[1024];
1151  byte *pix1, *pix2, *pix3, *pix4;
1152 
1153  fracstep = inwidth*0x10000/outwidth;
1154 
1155  frac = fracstep>>2;
1156  for (i=0 ; i<outwidth ; i++)
1157  {
1158  p1[i] = 4*(frac>>16);
1159  frac += fracstep;
1160  }
1161  frac = 3*(fracstep>>2);
1162  for (i=0 ; i<outwidth ; i++)
1163  {
1164  p2[i] = 4*(frac>>16);
1165  frac += fracstep;
1166  }
1167 
1168  for (i=0 ; i<outheight ; i++, out += outwidth)
1169  {
1170  inrow = in + inwidth*(int)((i+0.25)*inheight/outheight);
1171  inrow2 = in + inwidth*(int)((i+0.75)*inheight/outheight);
1172 
1173  for (j=0 ; j<outwidth ; j++)
1174  {
1175  pix1 = (byte *)inrow + p1[j];
1176  pix2 = (byte *)inrow + p2[j];
1177  pix3 = (byte *)inrow2 + p1[j];
1178  pix4 = (byte *)inrow2 + p2[j];
1179  ((byte *)(out+j))[0] = (pix1[0] + pix2[0] + pix3[0] + pix4[0])>>2;
1180  ((byte *)(out+j))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2;
1181  ((byte *)(out+j))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2;
1182  ((byte *)(out+j))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2;
1183  }
1184  }
1185 }
1186 
1187 /*
1188 ================
1189 Vk_LightScaleTexture
1190 
1191 Scale up the pixel values in a texture to increase the
1192 lighting range
1193 ================
1194 */
1195 void Vk_LightScaleTexture (unsigned *in, int inwidth, int inheight, qboolean only_gamma )
1196 {
1197  if ( only_gamma )
1198  {
1199  int i, c;
1200  byte *p;
1201 
1202  p = (byte *)in;
1203 
1204  c = inwidth*inheight;
1205  for (i=0 ; i<c ; i++, p+=4)
1206  {
1207  p[0] = gammatable[p[0]];
1208  p[1] = gammatable[p[1]];
1209  p[2] = gammatable[p[2]];
1210  }
1211  }
1212  else
1213  {
1214  int i, c;
1215  byte *p;
1216 
1217  p = (byte *)in;
1218 
1219  c = inwidth*inheight;
1220  for (i=0 ; i<c ; i++, p+=4)
1221  {
1222  p[0] = gammatable[intensitytable[p[0]]];
1223  p[1] = gammatable[intensitytable[p[1]]];
1224  p[2] = gammatable[intensitytable[p[2]]];
1225  }
1226  }
1227 }
1228 
1229 /*
1230 ===============
1231 Vk_Upload32
1232 
1233 Returns number of mip levels
1234 ===============
1235 */
1237 unsigned int texBuffer[256 * 256];
1238 
1239 uint32_t Vk_Upload32 (unsigned *data, int width, int height, qboolean mipmap)
1240 {
1241  unsigned scaled[256 * 256];
1242  int scaled_width, scaled_height;
1243 
1244  for (scaled_width = 1; scaled_width < width; scaled_width <<= 1)
1245  ;
1246  if (vk_round_down->value && scaled_width > width && mipmap)
1247  scaled_width >>= 1;
1248  for (scaled_height = 1; scaled_height < height; scaled_height <<= 1)
1249  ;
1250  if (vk_round_down->value && scaled_height > height && mipmap)
1251  scaled_height >>= 1;
1252 
1253  // let people sample down the world textures for speed
1254  if (mipmap)
1255  {
1256  scaled_width >>= (int)vk_picmip->value;
1257  scaled_height >>= (int)vk_picmip->value;
1258  }
1259 
1260  // don't ever bother with >256 textures
1261  if (scaled_width > 256)
1262  scaled_width = 256;
1263  if (scaled_height > 256)
1264  scaled_height = 256;
1265 
1266  if (scaled_width < 1)
1267  scaled_width = 1;
1268  if (scaled_height < 1)
1269  scaled_height = 1;
1270 
1271  upload_width = scaled_width;
1272  upload_height = scaled_height;
1273 
1274  if (scaled_width * scaled_height > sizeof(scaled) / 4)
1275  ri.Sys_Error(ERR_DROP, "Vk_Upload32: too big");
1276 
1277  if (scaled_width == width && scaled_height == height)
1278  {
1279  if (!mipmap)
1280  {
1281  memcpy(texBuffer, data, scaled_width * scaled_height * 4);
1282  return 1;
1283  }
1284  memcpy(scaled, data, width*height * 4);
1285  }
1286  else
1287  Vk_ResampleTexture(data, width, height, scaled, scaled_width, scaled_height);
1288 
1289  Vk_LightScaleTexture(scaled, scaled_width, scaled_height, !mipmap);
1290 
1291  memcpy(texBuffer, scaled, sizeof(scaled));
1292  if (mipmap)
1293  {
1294  int miplevel = 1;
1295 
1296  while (scaled_width > 1 || scaled_height > 1)
1297  {
1298  scaled_width >>= 1;
1299  scaled_height >>= 1;
1300  if (scaled_width < 1)
1301  scaled_width = 1;
1302  if (scaled_height < 1)
1303  scaled_height = 1;
1304  miplevel++;
1305  }
1306 
1307  return miplevel;
1308  }
1309 
1310  return 1;
1311 }
1312 
1313 /*
1314 ===============
1315 Vk_Upload8
1316 
1317 Returns number of mip levels
1318 ===============
1319 */
1320 
1321 uint32_t Vk_Upload8 (byte *data, int width, int height, qboolean mipmap, qboolean is_sky )
1322 {
1323  static unsigned trans[512 * 256];
1324  int i, s;
1325  int p;
1326 
1327  s = width * height;
1328 
1329  if (s > sizeof(trans) / 4)
1330  ri.Sys_Error(ERR_DROP, "Vk_Upload8: too large");
1331 
1332  for (i = 0; i < s; i++)
1333  {
1334  p = data[i];
1335  trans[i] = d_8to24table[p];
1336 
1337  if (p == 255)
1338  { // transparent, so scan around for another color
1339  // to avoid alpha fringes
1340  // FIXME: do a full flood fill so mips work...
1341  if (i > width && data[i - width] != 255)
1342  p = data[i - width];
1343  else if (i < s - width && data[i + width] != 255)
1344  p = data[i + width];
1345  else if (i > 0 && data[i - 1] != 255)
1346  p = data[i - 1];
1347  else if (i < s - 1 && data[i + 1] != 255)
1348  p = data[i + 1];
1349  else
1350  p = 0;
1351  // copy rgb components
1352  ((byte *)&trans[i])[0] = ((byte *)&d_8to24table[p])[0];
1353  ((byte *)&trans[i])[1] = ((byte *)&d_8to24table[p])[1];
1354  ((byte *)&trans[i])[2] = ((byte *)&d_8to24table[p])[2];
1355  }
1356  }
1357 
1358  return Vk_Upload32(trans, width, height, mipmap);
1359 }
1360 
1361 
1362 /*
1363 ================
1364 Vk_LoadPic
1365 
1366 This is also used as an entry point for the generated r_notexture
1367 ================
1368 */
1369 image_t *Vk_LoadPic (char *name, byte *pic, int width, int height, imagetype_t type, int bits, qvksampler_t *samplerType)
1370 {
1371  image_t *image;
1372  int i;
1373 
1374  // find a free image_t
1375  for (i = 0, image = vktextures; i<numvktextures; i++, image++)
1376  {
1377  if (image->vk_texture.image == VK_NULL_HANDLE && !image->scrap)
1378  break;
1379  }
1380  if (i == numvktextures)
1381  {
1383  ri.Sys_Error(ERR_DROP, "MAX_VKTEXTURES");
1384  numvktextures++;
1385  }
1386  image = &vktextures[i];
1387 
1388  if (strlen(name) >= sizeof(image->name))
1389  ri.Sys_Error(ERR_DROP, "Draw_LoadPic: \"%s\" is too long", name);
1390  strcpy(image->name, name);
1392  // zero-clear Vulkan texture handle
1393  QVVKTEXTURE_CLEAR(image->vk_texture);
1394  image->width = width;
1395  image->height = height;
1396  image->type = type;
1397 
1398  if (type == it_skin && bits == 8)
1399  R_FloodFillSkin(pic, width, height);
1400 
1401  // load little pics into the scrap
1402  if (image->type == it_pic && bits == 8
1403  && image->width < 64 && image->height < 64)
1404  {
1405  int x, y;
1406  int i, j, k;
1407  int texnum;
1408 
1409  texnum = Scrap_AllocBlock(image->width, image->height, &x, &y);
1410  if (texnum == -1)
1411  goto nonscrap;
1412 
1413  // copy the texels into the scrap block
1414  k = 0;
1415  for (i = 0; i<image->height; i++)
1416  for (j = 0; j<image->width; j++, k++)
1417  scrap_texels[texnum][(y + i)*BLOCK_WIDTH + x + j] = pic[k];
1418  image->scrap = true;
1419  image->sl = (x + 0.01) / (float)BLOCK_WIDTH;
1420  image->sh = (x + image->width - 0.01) / (float)BLOCK_WIDTH;
1421  image->tl = (y + 0.01) / (float)BLOCK_WIDTH;
1422  image->th = (y + image->height - 0.01) / (float)BLOCK_WIDTH;
1423  image->upload_width = BLOCK_WIDTH;
1424  image->upload_height = BLOCK_HEIGHT;
1425 
1426  // update scrap data
1427  Vk_Upload8(scrap_texels[texnum], BLOCK_WIDTH, BLOCK_HEIGHT, false, false);
1428 
1429  if (vk_scrapTextures[texnum].image != VK_NULL_HANDLE)
1430  {
1431  QVk_UpdateTextureData(&vk_scrapTextures[texnum], (unsigned char*)texBuffer, 0, 0, image->upload_width, image->upload_height);
1432  }
1433  else
1434  {
1436  QVk_CreateTexture(&vk_scrapTextures[texnum], (unsigned char*)texBuffer, image->upload_width, image->upload_height, samplerType ? *samplerType : vk_current_sampler);
1437  QVk_DebugSetObjectName((uint64_t)vk_scrapTextures[texnum].image, VK_OBJECT_TYPE_IMAGE, va("Image: %s", name));
1438  QVk_DebugSetObjectName((uint64_t)vk_scrapTextures[texnum].imageView, VK_OBJECT_TYPE_IMAGE_VIEW, va("Image View: %s", name));
1439  QVk_DebugSetObjectName((uint64_t)vk_scrapTextures[texnum].descriptorSet, VK_OBJECT_TYPE_DESCRIPTOR_SET, va("Descriptor Set: %s", name));
1440  QVk_DebugSetObjectName((uint64_t)vk_scrapTextures[texnum].allocInfo.deviceMemory, VK_OBJECT_TYPE_DEVICE_MEMORY, "Memory: scrap texture");
1441  }
1442 
1443  image->vk_texture = vk_scrapTextures[texnum];
1444  }
1445  else
1446  {
1447  nonscrap:
1448  image->scrap = false;
1449  if (bits == 8)
1450  image->vk_texture.mipLevels = Vk_Upload8(pic, width, height, (image->type != it_pic && image->type != it_sky), image->type == it_sky);
1451  else
1452  image->vk_texture.mipLevels = Vk_Upload32((unsigned *)pic, width, height, (image->type != it_pic && image->type != it_sky));
1453 
1454  image->upload_width = upload_width; // after power of 2 and scales
1455  image->upload_height = upload_height;
1456  image->sl = 0;
1457  image->sh = 1;
1458  image->tl = 0;
1459  image->th = 1;
1460 
1461  QVk_CreateTexture(&image->vk_texture, (unsigned char*)texBuffer, image->upload_width, image->upload_height, samplerType ? *samplerType : vk_current_sampler);
1462  QVk_DebugSetObjectName((uint64_t)image->vk_texture.image, VK_OBJECT_TYPE_IMAGE, va("Image: %s", name));
1463  QVk_DebugSetObjectName((uint64_t)image->vk_texture.imageView, VK_OBJECT_TYPE_IMAGE_VIEW, va("Image View: %s", name));
1464  QVk_DebugSetObjectName((uint64_t)image->vk_texture.descriptorSet, VK_OBJECT_TYPE_DESCRIPTOR_SET, va("Descriptor Set: %s", name));
1465  QVk_DebugSetObjectName((uint64_t)image->vk_texture.allocInfo.deviceMemory, VK_OBJECT_TYPE_DEVICE_MEMORY, "Memory: game textures");
1466  }
1467 
1468  return image;
1469 }
1470 
1471 
1472 /*
1473 ================
1474 Vk_LoadWal
1475 ================
1476 */
1478 {
1479  miptex_t *mt;
1480  int width, height, ofs;
1481  image_t *image;
1482 
1483  ri.FS_LoadFile (name, (void **)&mt);
1484  if (!mt)
1485  {
1486  ri.Con_Printf (PRINT_ALL, "Vk_FindImage: can't load %s\n", name);
1487  return r_notexture;
1488  }
1489 
1490  width = LittleLong (mt->width);
1491  height = LittleLong (mt->height);
1492  ofs = LittleLong (mt->offsets[0]);
1493 
1494  image = Vk_LoadPic (name, (byte *)mt + ofs, width, height, it_wall, 8, NULL);
1495 
1496  ri.FS_FreeFile ((void *)mt);
1497 
1498  return image;
1499 }
1500 
1501 /*
1502 ===============
1503 Vk_FindImage
1504 
1505 Finds or loads the given image
1506 ===============
1507 */
1509 {
1510  image_t *image;
1511  int i, len;
1512  byte *pic, *palette;
1513  int width, height;
1514 
1515  if (!name)
1516  return NULL; // ri.Sys_Error (ERR_DROP, "Vk_FindImage: NULL name");
1517  len = (int)strlen(name);
1518  if (len<5)
1519  return NULL; // ri.Sys_Error (ERR_DROP, "Vk_FindImage: bad name: %s", name);
1520 
1521  // look for it
1522  for (i=0, image=vktextures ; i<numvktextures ; i++,image++)
1523  {
1524  if (!strcmp(name, image->name))
1525  {
1527  return image;
1528  }
1529  }
1530 
1531  //
1532  // load the pic from disk
1533  //
1534  pic = NULL;
1535  palette = NULL;
1536  if (!strcmp(name+len-4, ".pcx"))
1537  {
1538  LoadPCX (name, &pic, &palette, &width, &height);
1539  if (!pic)
1540  return NULL; // ri.Sys_Error (ERR_DROP, "Vk_FindImage: can't load %s", name);
1541  image = Vk_LoadPic (name, pic, width, height, type, 8, samplerType);
1542  }
1543  else if (!strcmp(name+len-4, ".wal"))
1544  {
1545  image = Vk_LoadWal (name);
1546  }
1547  else if (!strcmp(name+len-4, ".tga"))
1548  {
1549  LoadTGA (name, &pic, &width, &height);
1550  if (!pic)
1551  return NULL; // ri.Sys_Error (ERR_DROP, "Vk_FindImage: can't load %s", name);
1552  image = Vk_LoadPic (name, pic, width, height, type, 32, samplerType);
1553  }
1554  else
1555  return NULL; // ri.Sys_Error (ERR_DROP, "Vk_FindImage: bad extension on: %s", name);
1556 
1557 
1558  if (pic)
1559  free(pic);
1560  if (palette)
1561  free(palette);
1562 
1563  return image;
1564 }
1565 
1566 
1567 
1568 /*
1569 ===============
1570 R_RegisterSkin
1571 ===============
1572 */
1573 struct image_s *R_RegisterSkin (char *name)
1574 {
1575  return Vk_FindImage (name, it_skin, NULL);
1576 }
1577 
1578 
1579 /*
1580 ================
1581 Vk_FreeUnusedImages
1582 
1583 Any image that was not touched on this registration sequence
1584 will be freed.
1585 ================
1586 */
1588 {
1589  int i;
1590  image_t *image;
1591 
1592  // never free r_notexture or particle texture
1595 
1596  for (i = 0, image = vktextures; i < numvktextures; i++, image++)
1597  {
1599  continue; // used this sequence
1600  if (!image->registration_sequence)
1601  continue; // free image_t slot
1602  if (image->type == it_pic)
1603  continue; // don't free pics
1604  // free it
1605  QVk_ReleaseTexture(&image->vk_texture);
1606  memset(image, 0, sizeof(*image));
1607  }
1608 }
1609 
1610 
1611 /*
1612 ===============
1613 Draw_GetPalette
1614 ===============
1615 */
1617 {
1618  int i;
1619  int r, g, b;
1620  unsigned v;
1621  byte *pic, *pal;
1622  int width, height;
1623 
1624  // get the palette
1625 
1626  LoadPCX ("pics/colormap.pcx", &pic, &pal, &width, &height);
1627  if (!pal)
1628  ri.Sys_Error (ERR_FATAL, "Couldn't load pics/colormap.pcx");
1629 
1630  for (i=0 ; i<256 ; i++)
1631  {
1632  r = pal[i*3+0];
1633  g = pal[i*3+1];
1634  b = pal[i*3+2];
1635 
1636  v = (255<<24) + (r<<0) + (g<<8) + (b<<16);
1637  d_8to24table[i] = LittleLong(v);
1638  }
1639 
1640  d_8to24table[255] &= LittleLong(0xffffff); // 255 is transparent
1641 
1642  free (pic);
1643  free (pal);
1644 
1645  return 0;
1646 }
1647 
1648 
1649 /*
1650 ===============
1651 Vk_InitImages
1652 ===============
1653 */
1654 void Vk_InitImages (void)
1655 {
1656  int i, j;
1657  float g = vid_gamma->value;
1658 
1660 
1661  // init intensity conversions
1662  intensity = ri.Cvar_Get("intensity", "2", 0);
1663 
1664  if (intensity->value <= 1)
1665  ri.Cvar_Set("intensity", "1");
1666 
1668 
1669  Draw_GetPalette();
1670 
1671  for (i = 0; i < 256; i++)
1672  {
1673  if (g == 1)
1674  {
1675  gammatable[i] = i;
1676  }
1677  else
1678  {
1679  float inf;
1680 
1681  inf = 255 * pow((i + 0.5) / 255.5, g) + 0.5;
1682  if (inf < 0)
1683  inf = 0;
1684  if (inf > 255)
1685  inf = 255;
1686  gammatable[i] = inf;
1687  }
1688  }
1689 
1690  for (i = 0; i<256; i++)
1691  {
1692  j = i * intensity->value;
1693  if (j > 255)
1694  j = 255;
1695  intensitytable[i] = j;
1696  }
1697 }
1698 
1699 /*
1700 ===============
1701 Vk_ShutdownImages
1702 ===============
1703 */
1705 {
1706  int i;
1707  image_t *image;
1708 
1709  for (i = 0, image = vktextures; i<numvktextures; i++, image++)
1710  {
1711  if (!image->registration_sequence)
1712  continue; // free image_t slot
1713  // free it (scraps are stored in a separate Vulkan buffer)
1714  if (!image->scrap)
1715  QVk_ReleaseTexture(&image->vk_texture);
1716  memset(image, 0, sizeof(*image));
1717  }
1718 
1720 
1721  for(i = 0; i < MAX_SCRAPS; i++)
1723 
1724  for(i = 0; i < MAX_LIGHTMAPS*2; i++)
1726 }
1727 
Vk_LmapTextureMode
void Vk_LmapTextureMode(char *string)
Definition: vk_image.c:705
image_s::vk_texture
qvktexture_t vk_texture
Definition: vk_local.h:116
it_sprite
@ it_sprite
Definition: r_local.h:65
MAX_VKTEXTURES
#define MAX_VKTEXTURES
Definition: vk_local.h:122
QVk_DebugSetObjectName
#define QVk_DebugSetObjectName(a, b, c)
Definition: qvk.h:317
texBuffer
unsigned int texBuffer[256 *256]
Definition: vk_image.c:1237
qvkdevice_t::gfxQueue
VkQueue gfxQueue
Definition: qvk.h:43
height
GLsizei height
Definition: qgl_win.c:69
QVk_CreateDepthBuffer
void QVk_CreateDepthBuffer(VkSampleCountFlagBits sampleCount, qvktexture_t *depthBuffer)
Definition: vk_image.c:352
qvkdevice_t::logical
VkDevice logical
Definition: qvk.h:40
Vk_Upload32
uint32_t Vk_Upload32(unsigned *data, int width, int height, qboolean mipmap)
Definition: vk_image.c:1239
qvkbuffer_t::buffer
VkBuffer buffer
Definition: qvk.h:126
vk_activeBufferIdx
int vk_activeBufferIdx
Definition: vk_common.c:129
vk_local.h
LoadPCX
void LoadPCX(char *filename, byte **pic, byte **palette, int *width, int *height)
Definition: vk_image.c:751
LittleShort
short LittleShort(short l)
Definition: q_shared.c:946
int
CONST PIXELFORMATDESCRIPTOR int
Definition: qgl_win.c:35
green
GLfloat green
Definition: qgl_win.c:74
QVk_FindDepthFormat
VkFormat QVk_FindDepthFormat(void)
Definition: vk_common.c:267
Draw_GetPalette
int Draw_GetPalette(void)
Definition: vk_image.c:1616
vk_scrapTextures
qvktexture_t vk_scrapTextures[MAX_SCRAPS]
Definition: vk_image.c:593
image_s::th
float th
Definition: gl_local.h:96
_TargaHeader::y_origin
unsigned short y_origin
Definition: r_image.c:194
r_notexture
image_t * r_notexture
Definition: gl_rmain.c:44
qvktexture_t::format
VkFormat format
Definition: qvk.h:86
imagetype_t
imagetype_t
Definition: r_local.h:62
QVVKTEXTURE_INIT
#define QVVKTEXTURE_INIT
Definition: qvk.h:91
Vk_LoadPic
image_t * Vk_LoadPic(char *name, byte *pic, int width, int height, imagetype_t type, int bits, qvksampler_t *samplerType)
Definition: vk_image.c:1369
skinwidth
int skinwidth
Definition: r_polyse.c:127
QVk_GetStagingBuffer
uint8_t * QVk_GetStagingBuffer(VkDeviceSize size, int alignment, VkCommandBuffer *cmdBuffer, VkBuffer *buffer, uint32_t *dstOffset)
Definition: vk_common.c:2153
vkstate_t::lightmap_textures
qvktexture_t lightmap_textures[MAX_LIGHTMAPS *2]
Definition: vk_local.h:339
ri
refimport_t ri
Definition: r_main.c:25
pcx_t
Definition: qfiles.h:60
PRINT_DEVELOPER
#define PRINT_DEVELOPER
Definition: qcommon.h:752
MAX_SCRAPS
#define MAX_SCRAPS
Definition: vk_image.c:586
miptex_s
Definition: qfiles.h:198
v
GLdouble v
Definition: qgl_win.c:143
it_wall
@ it_wall
Definition: r_local.h:66
FLOODFILL_FIFO_MASK
#define FLOODFILL_FIFO_MASK
Definition: vk_image.c:1078
_TargaHeader::x_origin
unsigned short x_origin
Definition: r_image.c:194
VmaAllocationInfo::deviceMemory
VkDeviceMemory deviceMemory
Handle to Vulkan memory object.
Definition: vk_mem_alloc.h:2545
S_MIPMAP_NEAREST
@ S_MIPMAP_NEAREST
Definition: qvk.h:67
_TargaHeader::pixel_size
unsigned char pixel_size
Definition: r_image.c:195
R_RegisterSkin
struct image_s * R_RegisterSkin(char *name)
Definition: vk_image.c:1573
QVk_UpdateTextureSampler
VkSampler QVk_UpdateTextureSampler(qvktexture_t *texture, qvksampler_t samplerType)
Definition: vk_common.c:2225
refimport_t::FS_LoadFile
int(* FS_LoadFile)(char *name, void **buf)
Definition: ref.h:209
pix
static int pix
Definition: r_part.c:472
refimport_t::Cvar_Get
cvar_t *(* Cvar_Get)(char *name, char *value, int flags)
Definition: ref.h:216
pcx_t::version
char version
Definition: qfiles.h:63
pcx_t::data
unsigned char data
Definition: qfiles.h:74
qboolean
qboolean
Definition: q_shared.h:63
x
GLint GLenum GLint x
Definition: qgl_win.c:116
vk_aniso
static cvar_t * vk_aniso
Definition: vid_menu.c:44
qvktexture_t::vmaFlags
VmaAllocationCreateFlags vmaFlags
Definition: qvk.h:82
i
int i
Definition: q_shared.c:305
QVk_CreateTexture
void QVk_CreateTexture(qvktexture_t *texture, const unsigned char *data, uint32_t width, uint32_t height, qvksampler_t samplerType)
Definition: vk_image.c:382
vk_current_sampler
qvksampler_t vk_current_sampler
Definition: vk_image.c:42
buffer
GLenum GLfloat * buffer
Definition: qgl_win.c:151
vkmode_t
Definition: vk_image.c:637
Vk_Upload8
uint32_t Vk_Upload8(byte *data, int width, int height, qboolean mipmap, qboolean is_sky)
Definition: vk_image.c:1321
Vk_TextureMode
void Vk_TextureMode(char *string)
Definition: vk_image.c:657
qvkdevice_t::gfxFamilyIndex
int gfxFamilyIndex
Definition: qvk.h:46
refimport_t::Cvar_Set
cvar_t *(* Cvar_Set)(char *name, char *value)
Definition: ref.h:217
floodfill_t::x
short x
Definition: gl_image.c:755
_TargaHeader::image_type
unsigned char image_type
Definition: r_image.c:191
transitionImageLayout
static void transitionImageLayout(const VkCommandBuffer *cmdBuffer, const VkQueue *queue, const qvktexture_t *texture, const VkImageLayout oldLayout, const VkImageLayout newLayout)
Definition: vk_image.c:60
Scrap_AllocBlock
int Scrap_AllocBlock(int w, int h, int *x, int *y)
Definition: vk_image.c:596
width
GLint GLsizei width
Definition: qgl_win.c:115
VmaMemoryUsage
VmaMemoryUsage
Definition: vk_mem_alloc.h:2054
pcx_t::hres
unsigned short hres
Definition: qfiles.h:67
d_8to24table
unsigned d_8to24table[256]
Definition: vk_image.c:36
image_s::registration_sequence
int registration_sequence
Definition: r_local.h:77
createTextureImage
static void createTextureImage(qvktexture_t *dstTex, const unsigned char *data, uint32_t width, uint32_t height)
Definition: vk_image.c:240
type
GLenum type
Definition: qgl_win.c:72
vk_samplerDescSetLayout
VkDescriptorSetLayout vk_samplerDescSetLayout
Definition: vk_common.c:261
_TargaHeader::colormap_size
unsigned char colormap_size
Definition: r_image.c:193
qvktexture_t::sharingMode
VkSharingMode sharingMode
Definition: qvk.h:84
cvar_s
Definition: q_shared.h:324
BLOCK_WIDTH
#define BLOCK_WIDTH
Definition: vk_image.c:587
vkmode_t::name
char * name
Definition: vk_image.c:639
_TargaHeader::colormap_index
unsigned short colormap_index
Definition: r_image.c:192
QVk_ReleaseTexture
void QVk_ReleaseTexture(qvktexture_t *texture)
Definition: vk_image.c:448
vk_device
qvkdevice_t vk_device
Definition: vk_common.c:51
refimport_t::FS_FreeFile
void(* FS_FreeFile)(void *buf)
Definition: ref.h:210
j
GLint j
Definition: qgl_win.c:150
base_textureid
int base_textureid
Definition: vk_image.c:26
va
char * va(char *format,...)
Definition: q_shared.c:1050
Vk_FreeUnusedImages
void Vk_FreeUnusedImages(void)
Definition: vk_image.c:1587
qvktexture_t::descriptorSet
VkDescriptorSet descriptorSet
Definition: qvk.h:87
LoadTGA
void LoadTGA(char *name, byte **pic, int *width, int *height)
Definition: vk_image.c:869
refimport_t::Con_Printf
void(* Con_Printf)(int print_level, char *str,...)
Definition: ref.h:202
PRINT_ALL
#define PRINT_ALL
Definition: qcommon.h:751
VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT
@ VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT
Set this flag if the allocation should have its own memory block.
Definition: vk_mem_alloc.h:2114
pcx_t::ymin
unsigned short ymin
Definition: qfiles.h:66
vk_commandPool
VkCommandPool vk_commandPool
Definition: vk_common.c:95
scrap_texels
byte scrap_texels[MAX_SCRAPS][BLOCK_WIDTH *BLOCK_HEIGHT]
Definition: vk_image.c:591
image_s::scrap
qboolean scrap
Definition: gl_local.h:97
skin
cvar_t * skin
Definition: cl_main.c:80
qvktexture_t::image
VkImage image
Definition: qvk.h:79
miplevel
static int miplevel
Definition: r_edge.c:77
it_pic
@ it_pic
Definition: r_local.h:67
qvkswapchain_t::format
VkFormat format
Definition: qvk.h:55
qvkswapchain_t::extent
VkExtent2D extent
Definition: qvk.h:57
qvktexture_t::allocInfo
VmaAllocationInfo allocInfo
Definition: qvk.h:81
r
GLdouble GLdouble r
Definition: qgl_win.c:336
VMA_MEMORY_USAGE_CPU_ONLY
@ VMA_MEMORY_USAGE_CPU_ONLY
Memory will be mappable on host.
Definition: vk_mem_alloc.h:2086
numvktextures
int numvktextures
Definition: vk_image.c:25
LittleLong
int LittleLong(int l)
Definition: q_shared.c:948
image_s::height
int height
Definition: r_local.h:75
qvkbufferopts_t
Definition: qvk.h:142
qvktexture_t::sampleCount
VkSampleCountFlagBits sampleCount
Definition: qvk.h:85
qvksampler_t
qvksampler_t
Definition: qvk.h:63
_TargaHeader::colormap_length
unsigned short colormap_length
Definition: r_image.c:192
getDepthStencilAspect
static VkImageAspectFlags getDepthStencilAspect(VkFormat depthFormat)
Definition: vk_image.c:46
QVk_ReadPixels
void QVk_ReadPixels(uint8_t *dstBuffer, uint32_t width, uint32_t height)
Definition: vk_image.c:465
qvkbuffer_t
Definition: qvk.h:124
vkstate_t::inverse_intensity
float inverse_intensity
Definition: vk_local.h:332
vk_swapchain
qvkswapchain_t vk_swapchain
Definition: vk_common.c:63
refimport_t::Sys_Error
void(* Sys_Error)(int err_level, char *str,...)
Definition: ref.h:194
vktextures
image_t vktextures[MAX_VKTEXTURES]
Definition: vk_image.c:24
_TargaHeader::attributes
unsigned char attributes
Definition: r_image.c:195
pcx_t::ymax
unsigned short ymax
Definition: qfiles.h:66
cvar_s::value
float value
Definition: q_shared.h:331
r_particletexture
image_t * r_particletexture
Definition: gl_rmain.c:45
Vk_LightScaleTexture
void Vk_LightScaleTexture(unsigned *in, int inwidth, int inheight, qboolean only_gamma)
Definition: vk_image.c:1195
VMA_MEMORY_USAGE_GPU_ONLY
@ VMA_MEMORY_USAGE_GPU_ONLY
Memory will be used on device only, so fast access from the device is preferred.
Definition: vk_mem_alloc.h:2076
floodfill_t
Definition: gl_image.c:753
modes
vkmode_t modes[]
Definition: vk_image.c:643
vk_state
vkstate_t vk_state
Definition: vk_rmain.c:31
image_s::type
imagetype_t type
Definition: r_local.h:74
QVk_SubmitCommand
void QVk_SubmitCommand(const VkCommandBuffer *commandBuffer, const VkQueue *queue)
Definition: vk_cmd.c:35
Vk_FindImage
image_t * Vk_FindImage(char *name, imagetype_t type, qvksampler_t *samplerType)
Definition: vk_image.c:1508
pcx_t::encoding
char encoding
Definition: qfiles.h:64
NULL
#define NULL
Definition: q_shared.h:67
S_MIPMAP_LINEAR
@ S_MIPMAP_LINEAR
Definition: qvk.h:68
QVk_UpdateTextureData
void QVk_UpdateTextureData(qvktexture_t *texture, const unsigned char *data, uint32_t offset_x, uint32_t offset_y, uint32_t width, uint32_t height)
Definition: vk_image.c:402
upload_width
int upload_width
Definition: vk_image.c:1236
image_s::width
int width
Definition: r_local.h:75
intensitytable
static byte intensitytable[256]
Definition: vk_image.c:30
image_s::tl
float tl
Definition: gl_local.h:96
qvktexture_t::imageView
VkImageView imageView
Definition: qvk.h:83
pcx_t::palette_type
unsigned short palette_type
Definition: qfiles.h:72
image_s::name
char name[MAX_QPATH]
Definition: r_local.h:73
intensity
cvar_t * intensity
Definition: vk_image.c:33
ERR_DROP
#define ERR_DROP
Definition: qcommon.h:744
Q_stricmp
int Q_stricmp(char *s1, char *s2)
Definition: q_shared.c:1180
it_skin
@ it_skin
Definition: r_local.h:64
QVk_BeginCommand
VkResult QVk_BeginCommand(const VkCommandBuffer *commandBuffer)
Definition: vk_cmd.c:23
qvkbuffer_t::allocInfo
VmaAllocationInfo allocInfo
Definition: qvk.h:128
QVk_FreeBuffer
void QVk_FreeBuffer(qvkbuffer_t *buffer)
Definition: vk_buffer.c:106
pcx_t::bits_per_pixel
char bits_per_pixel
Definition: qfiles.h:65
vk_mip_nearfilter
cvar_t * vk_mip_nearfilter
Definition: vk_rmain.c:119
QVk_CreateCommandBuffer
VkCommandBuffer QVk_CreateCommandBuffer(const VkCommandPool *commandPool, VkCommandBufferLevel level)
Definition: vk_cmd.c:78
name
cvar_t * name
Definition: cl_main.c:79
VK_VERIFY
#define VK_VERIFY(x)
Definition: vk_local.h:59
QVk_CreateImageView
VkResult QVk_CreateImageView(const VkImage *image, VkImageAspectFlags aspectFlags, VkImageView *imageView, VkFormat format, uint32_t mipLevels)
Definition: vk_image.c:293
ERR_FATAL
#define ERR_FATAL
Definition: qcommon.h:743
qvktexture_t::mipLevels
uint32_t mipLevels
Definition: qvk.h:88
pcx_t::xmin
unsigned short xmin
Definition: qfiles.h:66
s
static fixed16_t s
Definition: r_scan.c:30
y
GLint y
Definition: qgl_win.c:115
BLOCK_HEIGHT
#define BLOCK_HEIGHT
Definition: vk_image.c:588
S_NEAREST
@ S_NEAREST
Definition: qvk.h:65
R_FloodFillSkin
void R_FloodFillSkin(byte *skin, int skinwidth, int skinheight)
Definition: vk_image.c:1091
vmaCreateImage
VkResult vmaCreateImage(VmaAllocator allocator, const VkImageCreateInfo *pImageCreateInfo, const VmaAllocationCreateInfo *pAllocationCreateInfo, VkImage *pImage, VmaAllocation *pAllocation, VmaAllocationInfo *pAllocationInfo)
Function similar to vmaCreateBuffer().
_TargaHeader
Definition: r_image.c:190
MAX_LIGHTMAPS
#define MAX_LIGHTMAPS
Definition: gl_rsurf.c:38
qvkswapchain_t::images
VkImage * images
Definition: qvk.h:58
VmaAllocationInfo::pMappedData
void * pMappedData
Pointer to the beginning of this allocation as mapped data.
Definition: vk_mem_alloc.h:2564
trans
static int trans[3]
Definition: r_polyse.c:928
image_s::upload_width
int upload_width
Definition: gl_local.h:92
Vk_ResampleTexture
void Vk_ResampleTexture(unsigned *in, int inwidth, int inheight, unsigned *out, int outwidth, int outheight)
Definition: vk_image.c:1145
image_s::sl
float sl
Definition: gl_local.h:96
vk_malloc
VmaAllocator vk_malloc
Definition: vk_common.c:48
vid_gamma
cvar_t * vid_gamma
Definition: vid_dll.c:43
qvkbufferopts_t::usage
VkBufferUsageFlags usage
Definition: qvk.h:144
vkmode_t::samplerType
qvksampler_t samplerType
Definition: vk_image.c:640
blue
GLfloat GLfloat blue
Definition: qgl_win.c:74
pcx_t::manufacturer
char manufacturer
Definition: qfiles.h:62
vk_picmip
static cvar_t * vk_picmip
Definition: vid_menu.c:50
_TargaHeader::colormap_type
unsigned char colormap_type
Definition: r_image.c:191
_TargaHeader::width
unsigned short width
Definition: r_image.c:194
S_LINEAR
@ S_LINEAR
Definition: qvk.h:66
vk_round_down
cvar_t * vk_round_down
Definition: vk_rmain.c:96
_TargaHeader::id_length
unsigned char id_length
Definition: r_image.c:191
Vk_LoadWal
image_t * Vk_LoadWal(char *name)
Definition: vk_image.c:1477
vk_descriptorPool
VkDescriptorPool vk_descriptorPool
Definition: vk_common.c:97
format
GLsizei GLenum format
Definition: qgl_win.c:131
Vk_InitImages
void Vk_InitImages(void)
Definition: vk_image.c:1654
pcx_t::vres
unsigned short vres
Definition: qfiles.h:67
qvkdevice_t::transferQueue
VkQueue transferQueue
Definition: qvk.h:45
vk_rawTexture
qvktexture_t vk_rawTexture
Definition: vk_image.c:28
FLOODFILL_STEP
#define FLOODFILL_STEP(off, dx, dy)
Definition: vk_image.c:1080
QVk_CreateColorBuffer
void QVk_CreateColorBuffer(VkSampleCountFlagBits sampleCount, qvktexture_t *colorBuffer, int extraFlags)
Definition: vk_image.c:367
FLOODFILL_FIFO_SIZE
#define FLOODFILL_FIFO_SIZE
Definition: vk_image.c:1077
_TargaHeader::height
unsigned short height
Definition: r_image.c:194
vmaDestroyImage
void vmaDestroyImage(VmaAllocator allocator, VkImage image, VmaAllocation allocation)
Destroys Vulkan image and frees allocated memory.
texture
GLuint texture
Definition: qgl_win.c:68
image_s::upload_height
int upload_height
Definition: gl_local.h:92
VMA_ALLOCATION_CREATE_MAPPED_BIT
@ VMA_ALLOCATION_CREATE_MAPPED_BIT
Set this flag to use a memory that will be persistently mapped and retrieve pointer to it.
Definition: vk_mem_alloc.h:2138
vk_current_lmap_sampler
qvksampler_t vk_current_lmap_sampler
Definition: vk_image.c:43
w
GLdouble GLdouble GLdouble w
Definition: qgl_win.c:291
QVk_CreateImage
VkResult QVk_CreateImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VmaMemoryUsage memUsage, qvktexture_t *texture)
Definition: vk_image.c:316
registration_sequence
int registration_sequence
Definition: r_model.c:44
TargaHeader
struct _TargaHeader TargaHeader
image_s
Definition: r_local.h:71
gammatable
static unsigned char gammatable[256]
Definition: vk_image.c:31
QVk_CreateBuffer
VkResult QVk_CreateBuffer(VkDeviceSize size, qvkbuffer_t *dstBuffer, const qvkbufferopts_t options)
Definition: vk_buffer.c:70
qvkdevice_t::transferFamilyIndex
int transferFamilyIndex
Definition: qvk.h:48
upload_height
int upload_height
Definition: vk_image.c:1236
pcx_t::xmax
unsigned short xmax
Definition: qfiles.h:66
VmaAllocationCreateInfo::flags
VmaAllocationCreateFlags flags
Use VmaAllocationCreateFlagBits enum.
Definition: vk_mem_alloc.h:2217
VmaAllocationCreateInfo
Definition: vk_mem_alloc.h:2214
qvktexture_t
Definition: qvk.h:77
floodfill_t::y
short y
Definition: gl_image.c:755
QVVKTEXTURE_CLEAR
#define QVVKTEXTURE_CLEAR(i)
Definition: qvk.h:104
QVk_SubmitStagingBuffers
void QVk_SubmitStagingBuffers(void)
Definition: vk_common.c:2216
scrap_allocated
int scrap_allocated[MAX_SCRAPS][BLOCK_WIDTH]
Definition: vk_image.c:590
generateMipmaps
static void generateMipmaps(const VkCommandBuffer *cmdBuffer, const qvktexture_t *texture, uint32_t width, uint32_t height)
Definition: vk_image.c:169
NUM_VK_MODES
#define NUM_VK_MODES
Definition: vk_image.c:650
Vk_ImageList_f
void Vk_ImageList_f(void)
Definition: vk_image.c:535
pcx_t::bytes_per_line
unsigned short bytes_per_line
Definition: qfiles.h:71
Vk_ShutdownImages
void Vk_ShutdownImages(void)
Definition: vk_image.c:1704
image_s::sh
float sh
Definition: gl_local.h:96
it_sky
@ it_sky
Definition: r_local.h:68