Quake II RTX doxygen  1.0 dev
god_rays.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 2019, NVIDIA CORPORATION. All rights reserved.
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18 
19 #include "shared/shared.h"
20 #include "vkpt.h"
21 #include "vk_util.h"
22 
23 static const uint32_t THREAD_GROUP_SIZE = 16;
24 static const uint32_t FILTER_THREAD_GROUP_SIZE = 16;
25 
26 struct
27 {
28  VkPipeline pipelines[2];
29  VkPipelineLayout pipeline_layout;
30  VkDescriptorSetLayout descriptor_set_layout;
31 
32  VkDescriptorPool descriptor_pool;
33  VkDescriptorSet descriptor_set;
34 
35  VkImageView shadow_image_view;
36  VkSampler shadow_sampler;
37 
38  cvar_t* intensity;
39  cvar_t* eccentricity;
40  cvar_t* enable;
41 } god_rays;
42 
43 static void create_image_views();
44 static void create_pipeline_layout();
45 static void create_pipelines();
46 static void create_descriptor_set();
47 static void update_descriptor_set();
48 
49 extern cvar_t *physical_sky_space;
50 
52 {
53  memset(&god_rays, 0, sizeof(god_rays));
54 
55  VkPhysicalDeviceProperties properties;
56  vkGetPhysicalDeviceProperties(qvk.physical_device, &properties);
57 
58  god_rays.intensity = Cvar_Get("gr_intensity", "2.0", 0);
59  god_rays.eccentricity = Cvar_Get("gr_eccentricity", "0.75", 0);
60  god_rays.enable = Cvar_Get("gr_enable", "1", 0);
61 
62  return VK_SUCCESS;
63 }
64 
66 {
67  vkDestroySampler(qvk.device, god_rays.shadow_sampler, NULL);
68  vkDestroyDescriptorPool(qvk.device, god_rays.descriptor_pool, NULL);
69 
70  return VK_SUCCESS;
71 }
72 
74 {
78 
79  // this is a noop outside a shader reload
81 
82  return VK_SUCCESS;
83 }
84 
86 {
87  for (size_t i = 0; i < LENGTH(god_rays.pipelines); i++) {
88  if (god_rays.pipelines[i]) {
89  vkDestroyPipeline(qvk.device, god_rays.pipelines[i], NULL);
90  god_rays.pipelines[i] = NULL;
91  }
92  }
93 
94  if (god_rays.pipeline_layout) {
95  vkDestroyPipelineLayout(qvk.device, god_rays.pipeline_layout, NULL);
96  god_rays.pipeline_layout = NULL;
97  }
98 
99  if (god_rays.descriptor_set_layout) {
100  vkDestroyDescriptorSetLayout(qvk.device, god_rays.descriptor_set_layout, NULL);
101  god_rays.descriptor_set_layout = NULL;
102  }
103 
104  return VK_SUCCESS;
105 }
106 
107 VkResult
109 {
112  return VK_SUCCESS;
113 }
114 
115 VkResult
117 {
118  return VK_SUCCESS;
119 }
120 
121 #define BARRIER_COMPUTE(cmd_buf, img) \
122  do { \
123  VkImageSubresourceRange subresource_range = { \
124  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, \
125  .baseMipLevel = 0, \
126  .levelCount = 1, \
127  .baseArrayLayer = 0, \
128  .layerCount = 1 \
129  }; \
130  IMAGE_BARRIER(cmd_buf, \
131  .image = img, \
132  .subresourceRange = subresource_range, \
133  .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT, \
134  .dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT, \
135  .oldLayout = VK_IMAGE_LAYOUT_GENERAL, \
136  .newLayout = VK_IMAGE_LAYOUT_GENERAL, \
137  ); \
138  } while(0)
139 
140 void vkpt_record_god_rays_trace_command_buffer(VkCommandBuffer command_buffer, int pass)
141 {
142  BARRIER_COMPUTE(command_buffer, qvk.images[VKPT_IMG_PT_GODRAYS_THROUGHPUT_DIST]);
143  BARRIER_COMPUTE(command_buffer, qvk.images[VKPT_IMG_ASVGF_COLOR]);
144 
145  vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, god_rays.pipelines[0]);
146 
147  VkDescriptorSet desc_sets[] = {
148  god_rays.descriptor_set,
152  };
153 
154  vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, god_rays.pipeline_layout, 0, LENGTH(desc_sets),
155  desc_sets, 0, NULL);
156 
157  vkCmdPushConstants(command_buffer, god_rays.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(int), &pass);
158 
159  uint32_t group_size = THREAD_GROUP_SIZE;
160  uint32_t group_num_x = (qvk.extent_render.width / (2 * qvk.device_count) + (group_size - 1)) / group_size;
161  uint32_t group_num_y = (qvk.extent_render.height / 2 + (group_size - 1)) / group_size;
162 
163  vkCmdDispatch(command_buffer, group_num_x, group_num_y, 1);
164 
165  BARRIER_COMPUTE(command_buffer, qvk.images[VKPT_IMG_PT_GODRAYS_THROUGHPUT_DIST]);
166  BARRIER_COMPUTE(command_buffer, qvk.images[VKPT_IMG_ASVGF_COLOR]);
167 }
168 
169 void vkpt_record_god_rays_filter_command_buffer(VkCommandBuffer command_buffer)
170 {
171  BARRIER_COMPUTE(command_buffer, qvk.images[VKPT_IMG_PT_TRANSPARENT]);
172 
173  const VkImageSubresourceRange subresource_range = {
174  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
175  .levelCount = 1,
176  .layerCount = 1
177  };
178 
179  vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, god_rays.pipelines[1]);
180 
181  VkDescriptorSet desc_sets[] = {
182  god_rays.descriptor_set,
186  };
187 
188  vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, god_rays.pipeline_layout, 0, LENGTH(desc_sets),
189  desc_sets, 0, NULL);
190 
191  int pass = 0;
192  vkCmdPushConstants(command_buffer, god_rays.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(int), &pass);
193 
194  uint32_t group_size = FILTER_THREAD_GROUP_SIZE;
195  uint32_t group_num_x = (qvk.extent_render.width / qvk.device_count + (group_size - 1)) / group_size;
196  uint32_t group_num_y = (qvk.extent_render.height + (group_size - 1)) / group_size;
197 
198  vkCmdDispatch(command_buffer, group_num_x, group_num_y, 1);
199 
200  BARRIER_COMPUTE(command_buffer, qvk.images[VKPT_IMG_PT_TRANSPARENT]);
201 }
202 
204  QVKUniformBuffer_t * ubo,
205  const aabb_t* world_aabb,
206  const float* proj,
207  const float* view,
208  const float* shadowmap_viewproj,
209  float shadowmap_depth_scale)
210 {
211  VectorAdd(world_aabb->mins, world_aabb->maxs, ubo->world_center);
212  VectorScale(ubo->world_center, 0.5f, ubo->world_center);
213  VectorSubtract(world_aabb->maxs, world_aabb->mins, ubo->world_size);
214  VectorScale(ubo->world_size, 0.5f, ubo->world_half_size_inv);
215  ubo->world_half_size_inv[0] = 1.f / ubo->world_half_size_inv[0];
216  ubo->world_half_size_inv[1] = 1.f / ubo->world_half_size_inv[1];
217  ubo->world_half_size_inv[2] = 1.f / ubo->world_half_size_inv[2];
218  ubo->shadow_map_depth_scale = shadowmap_depth_scale;
219 
220  ubo->god_rays_intensity = max(0.f, god_rays.intensity->value);
221  ubo->god_rays_eccentricity = god_rays.eccentricity->value;
222 
223  // Shadow parameters
224  memcpy(ubo->shadow_map_VP, shadowmap_viewproj, 16 * sizeof(float));
225 }
226 
227 static void create_image_views()
228 {
229  god_rays.shadow_image_view = vkpt_shadow_map_get_view();
230 
231  VkSamplerReductionModeCreateInfoEXT redutcion_create_info = {
232  .sType = VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT,
233  .reductionMode = VK_SAMPLER_REDUCTION_MODE_MIN_EXT
234  };
235 
236  const VkSamplerCreateInfo sampler_create_info = {
237  .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
238  .pNext = &redutcion_create_info,
239  .magFilter = VK_FILTER_LINEAR,
240  .minFilter = VK_FILTER_LINEAR,
241  .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST,
242  .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
243  .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
244  .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
245  .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE
246  };
247 
248  _VK(vkCreateSampler(qvk.device, &sampler_create_info, NULL, &god_rays.shadow_sampler));
249 }
250 
252 {
253  VkDescriptorSetLayoutBinding bindings[1] = { 0 };
254  bindings[0].binding = 0;
255  bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
256  bindings[0].descriptorCount = 1;
257  bindings[0].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
258 
259  const VkDescriptorSetLayoutCreateInfo set_layout_create_info = {
260  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
261  .bindingCount = LENGTH(bindings),
262  .pBindings = bindings
263  };
264 
265  _VK(vkCreateDescriptorSetLayout(qvk.device, &set_layout_create_info, NULL,
266  &god_rays.descriptor_set_layout));
267 
268 
269  VkDescriptorSetLayout desc_set_layouts[] = {
270  god_rays.descriptor_set_layout,
274  };
275 
276  VkPushConstantRange push_constant_range = {
277  .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
278  .offset = 0,
279  .size = sizeof(int),
280  };
281 
282  const VkPipelineLayoutCreateInfo layout_create_info = {
283  .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
284  .pSetLayouts = desc_set_layouts,
285  .setLayoutCount = LENGTH(desc_set_layouts),
286  .pushConstantRangeCount = 1,
287  .pPushConstantRanges = &push_constant_range
288  };
289 
290  _VK(vkCreatePipelineLayout(qvk.device, &layout_create_info, NULL,
291  &god_rays.pipeline_layout));
292 }
293 
294 static void create_pipelines()
295 {
296  const VkPipelineShaderStageCreateInfo shader = {
297  .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
298  .stage = VK_SHADER_STAGE_COMPUTE_BIT,
299  .module = qvk.shader_modules[QVK_MOD_GOD_RAYS_COMP],
300  .pName = "main"
301  };
302 
303  const VkPipelineShaderStageCreateInfo filter_shader = {
304  .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
305  .stage = VK_SHADER_STAGE_COMPUTE_BIT,
306  .module = qvk.shader_modules[QVK_MOD_GOD_RAYS_FILTER_COMP],
307  .pName = "main"
308  };
309 
310  const VkComputePipelineCreateInfo pipeline_create_infos[2] = {
311  {
312  .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
313  .stage = shader,
314  .layout = god_rays.pipeline_layout
315  },
316  {
317  .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
318  .stage = filter_shader,
319  .layout = god_rays.pipeline_layout
320  },
321  };
322 
323  _VK(vkCreateComputePipelines(qvk.device, VK_NULL_HANDLE, LENGTH(pipeline_create_infos), pipeline_create_infos,
324  NULL, god_rays.pipelines));
325 }
326 
328 {
329  const VkDescriptorPoolSize pool_sizes[] = {
330  { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 }
331  };
332 
333  const VkDescriptorPoolCreateInfo pool_create_info = {
334  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
335  .maxSets = 1,
336  .poolSizeCount = LENGTH(pool_sizes),
337  .pPoolSizes = pool_sizes
338  };
339 
340  _VK(vkCreateDescriptorPool(qvk.device, &pool_create_info, NULL, &god_rays.descriptor_pool));
341 
342  const VkDescriptorSetAllocateInfo allocate_info = {
343  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
344  .descriptorPool = god_rays.descriptor_pool,
345  .descriptorSetCount = 1,
346  .pSetLayouts = &god_rays.descriptor_set_layout
347  };
348 
349  _VK(vkAllocateDescriptorSets(qvk.device, &allocate_info, &god_rays.descriptor_set));
350 }
351 
352 
354 {
355  // if we end up here during init before we've called create_image_views(), punt --- we will be called again later
356  if (god_rays.shadow_image_view == NULL)
357  return;
358 
359  VkDescriptorImageInfo image_info = {
360  .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
361  .imageView = god_rays.shadow_image_view,
362  .sampler = god_rays.shadow_sampler
363  };
364 
365  VkWriteDescriptorSet writes[1] = {
366  {
367  .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
368  .dstSet = god_rays.descriptor_set,
369  .descriptorCount = 1,
370  .dstBinding = 0,
371  .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
372  .pImageInfo = &image_info
373  }
374  };
375 
376  vkUpdateDescriptorSets(qvk.device, LENGTH(writes), writes, 0, NULL);
377 }
378 
379 qboolean vkpt_god_rays_enabled(const sun_light_t* sun_light)
380 {
381  return god_rays.enable->integer
382  && god_rays.intensity->value > 0.f
383  && sun_light->visible
384  && !physical_sky_space->integer; // god rays look weird in space because they also appear outside of the station
385 }
QVK_s::desc_set_ubo
VkDescriptorSet desc_set_ubo
Definition: vkpt.h:226
sun_light_s
Definition: vkpt.h:414
QVKUniformBuffer_s
Definition: global_ubo.h:247
eccentricity
cvar_t * eccentricity
Definition: god_rays.c:39
vkpt_god_rays_destroy_pipelines
VkResult vkpt_god_rays_destroy_pipelines()
Definition: god_rays.c:85
QVK_s::device
VkDevice device
Definition: vkpt.h:172
vkpt_shadow_map_get_view
VkImageView vkpt_shadow_map_get_view()
Definition: shadow_map.c:203
FILTER_THREAD_GROUP_SIZE
static const uint32_t FILTER_THREAD_GROUP_SIZE
Definition: god_rays.c:24
Cvar_Get
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags)
Definition: cvar.c:257
enable
cvar_t * enable
Definition: god_rays.c:40
god_rays
struct @15 god_rays
vkpt.h
vkpt_initialize_god_rays
VkResult vkpt_initialize_god_rays()
Definition: god_rays.c:51
vkpt_record_god_rays_trace_command_buffer
void vkpt_record_god_rays_trace_command_buffer(VkCommandBuffer command_buffer, int pass)
Definition: god_rays.c:140
aabb_s::mins
vec3_t mins
Definition: vkpt.h:339
QVK_s::shader_modules
VkShaderModule shader_modules[NUM_QVK_SHADER_MODULES]
Definition: vkpt.h:223
QVK_s::physical_device
VkPhysicalDevice physical_device
Definition: vkpt.h:163
shadow_image_view
VkImageView shadow_image_view
Definition: god_rays.c:35
sun_light_s::visible
qboolean visible
Definition: vkpt.h:420
_VK
#define _VK(...)
Definition: vkpt.h:65
BARRIER_COMPUTE
#define BARRIER_COMPUTE(cmd_buf, img)
Definition: god_rays.c:121
QVK_s::desc_set_vertex_buffer
VkDescriptorSet desc_set_vertex_buffer
Definition: vkpt.h:241
vkpt_god_rays_update_images
VkResult vkpt_god_rays_update_images()
Definition: god_rays.c:108
THREAD_GROUP_SIZE
static const uint32_t THREAD_GROUP_SIZE
Definition: god_rays.c:23
vkpt_destroy_god_rays
VkResult vkpt_destroy_god_rays()
Definition: god_rays.c:65
vkpt_god_rays_prepare_ubo
void vkpt_god_rays_prepare_ubo(QVKUniformBuffer_t *ubo, const aabb_t *world_aabb, const float *proj, const float *view, const float *shadowmap_viewproj, float shadowmap_depth_scale)
Definition: god_rays.c:203
QVK_s::images
VkImage images[NUM_VKPT_IMAGES]
Definition: vkpt.h:231
update_descriptor_set
static void update_descriptor_set()
Definition: god_rays.c:353
create_descriptor_set
static void create_descriptor_set()
Definition: god_rays.c:327
vkpt_god_rays_noop
VkResult vkpt_god_rays_noop()
Definition: god_rays.c:116
descriptor_set
VkDescriptorSet descriptor_set
Definition: god_rays.c:33
pipelines
VkPipeline pipelines[2]
Definition: god_rays.c:28
LENGTH
#define LENGTH(a)
Definition: tent.c:228
vkpt_record_god_rays_filter_command_buffer
void vkpt_record_god_rays_filter_command_buffer(VkCommandBuffer command_buffer)
Definition: god_rays.c:169
physical_sky_space
cvar_t * physical_sky_space
Definition: physical_sky.c:57
create_pipelines
static void create_pipelines()
Definition: god_rays.c:294
create_pipeline_layout
static void create_pipeline_layout()
Definition: god_rays.c:251
descriptor_set_layout
VkDescriptorSetLayout descriptor_set_layout
Definition: god_rays.c:30
qvk
QVK_t qvk
Definition: main.c:377
vkpt_god_rays_create_pipelines
VkResult vkpt_god_rays_create_pipelines()
Definition: god_rays.c:73
create_image_views
static void create_image_views()
Definition: god_rays.c:227
vk_util.h
shadow_sampler
VkSampler shadow_sampler
Definition: god_rays.c:36
QVK_s::extent_render
VkExtent2D extent_render
Definition: vkpt.h:184
intensity
cvar_t * intensity
Definition: god_rays.c:38
aabb_s
Definition: vkpt.h:338
descriptor_pool
VkDescriptorPool descriptor_pool
Definition: god_rays.c:32
QVK_s::desc_set_layout_textures
VkDescriptorSetLayout desc_set_layout_textures
Definition: vkpt.h:228
QVK_s::desc_set_layout_ubo
VkDescriptorSetLayout desc_set_layout_ubo
Definition: vkpt.h:225
aabb_s::maxs
vec3_t maxs
Definition: vkpt.h:340
int
CONST PIXELFORMATDESCRIPTOR int
Definition: wgl.c:26
pipeline_layout
VkPipelineLayout pipeline_layout
Definition: god_rays.c:29
vkpt_god_rays_enabled
qboolean vkpt_god_rays_enabled(const sun_light_t *sun_light)
Definition: god_rays.c:379
qvk_get_current_desc_set_textures
VkDescriptorSet qvk_get_current_desc_set_textures()
Definition: main.c:1847
QVK_s::device_count
int device_count
Definition: vkpt.h:167
QVK_s::desc_set_layout_vertex_buffer
VkDescriptorSetLayout desc_set_layout_vertex_buffer
Definition: vkpt.h:240