1 /*
2 Copyright (C) 1996-2001 Id Software, Inc.
3 Copyright (C) 2002-2009 John Fitzgibbons and others
4 Copyright (C) 2010-2014 QuakeSpasm developers
5 Copyright (C) 2016 Axel Gneiting
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
16 See the GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 */
22 //gl_warp.c -- warping animation support
23
24 #include "quakedef.h"
25
26 extern cvar_t r_drawflat;
27
28 cvar_t r_waterquality = {"r_waterquality", "8", CVAR_NONE};
29 cvar_t r_waterwarp = {"r_waterwarp", "1", CVAR_ARCHIVE};
30 cvar_t r_waterwarpcompute = { "r_waterwarpcompute", "1", CVAR_ARCHIVE };
31
32 float turbsin[] =
33 {
34 #include "gl_warp_sin.h"
35 };
36
37 #define WARPCALC(s,t) ((s + turbsin[(int)((t*2)+(cl.time*(128.0/M_PI))) & 255]) * (1.0/64)) //johnfitz -- correct warp
38
39 //==============================================================================
40 //
41 // OLD-STYLE WATER
42 //
43 //==============================================================================
44
45 extern qmodel_t *loadmodel;
46
47 msurface_t *warpface;
48
49 cvar_t gl_subdivide_size = {"gl_subdivide_size", "128", CVAR_ARCHIVE};
50
BoundPoly(int numverts,float * verts,vec3_t mins,vec3_t maxs)51 void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
52 {
53 int i, j;
54 float *v;
55
56 mins[0] = mins[1] = mins[2] = FLT_MAX;
57 maxs[0] = maxs[1] = maxs[2] = -FLT_MAX;
58 v = verts;
59 for (i=0 ; i<numverts ; i++)
60 for (j=0 ; j<3 ; j++, v++)
61 {
62 if (*v < mins[j])
63 mins[j] = *v;
64 if (*v > maxs[j])
65 maxs[j] = *v;
66 }
67 }
68
SubdividePolygon(int numverts,float * verts)69 void SubdividePolygon (int numverts, float *verts)
70 {
71 int i, j, k;
72 vec3_t mins, maxs;
73 float m;
74 float *v;
75 vec3_t front[64], back[64];
76 int f, b;
77 float dist[64];
78 float frac;
79 glpoly_t *poly;
80 float *poly_vert;
81 float s, t;
82
83 if (numverts > 60)
84 Sys_Error ("numverts = %i", numverts);
85
86 BoundPoly (numverts, verts, mins, maxs);
87
88 for (i=0 ; i<3 ; i++)
89 {
90 m = (mins[i] + maxs[i]) * 0.5;
91 m = gl_subdivide_size.value * floor (m/gl_subdivide_size.value + 0.5);
92 if (maxs[i] - m < 8)
93 continue;
94 if (m - mins[i] < 8)
95 continue;
96
97 // cut it
98 v = verts + i;
99 for (j=0 ; j<numverts ; j++, v+= 3)
100 dist[j] = *v - m;
101
102 // wrap cases
103 dist[j] = dist[0];
104 v-=i;
105 VectorCopy (verts, v);
106
107 f = b = 0;
108 v = verts;
109 for (j=0 ; j<numverts ; j++, v+= 3)
110 {
111 if (dist[j] >= 0)
112 {
113 VectorCopy (v, front[f]);
114 f++;
115 }
116 if (dist[j] <= 0)
117 {
118 VectorCopy (v, back[b]);
119 b++;
120 }
121 if (dist[j] == 0 || dist[j+1] == 0)
122 continue;
123 if ( (dist[j] > 0) != (dist[j+1] > 0) )
124 {
125 // clip point
126 frac = dist[j] / (dist[j] - dist[j+1]);
127 for (k=0 ; k<3 ; k++)
128 front[f][k] = back[b][k] = v[k] + frac*(v[3+k] - v[k]);
129 f++;
130 b++;
131 }
132 }
133
134 SubdividePolygon (f, front[0]);
135 SubdividePolygon (b, back[0]);
136 return;
137 }
138
139 poly = (glpoly_t *) Hunk_Alloc (sizeof(glpoly_t) + (numverts-4) * VERTEXSIZE*sizeof(float));
140 poly->next = warpface->polys->next;
141 warpface->polys->next = poly;
142 poly->numverts = numverts;
143 for (i=0 ; i<numverts ; i++, verts+= 3)
144 {
145 poly_vert = &poly->verts[0][0] + (i * VERTEXSIZE);
146 VectorCopy (verts, poly_vert);
147 s = DotProduct (verts, warpface->texinfo->vecs[0]);
148 t = DotProduct (verts, warpface->texinfo->vecs[1]);
149 poly_vert[3] = s;
150 poly_vert[4] = t;
151 }
152 }
153
154 /*
155 ================
156 GL_SubdivideSurface
157 ================
158 */
GL_SubdivideSurface(msurface_t * fa)159 void GL_SubdivideSurface (msurface_t *fa)
160 {
161 vec3_t verts[64];
162 int i;
163 float *poly_vert;
164
165 warpface = fa;
166
167 //the first poly in the chain is the undivided poly for newwater rendering.
168 //grab the verts from that.
169 for (i=0; i<fa->polys->numverts; i++)
170 {
171 poly_vert = &fa->polys->verts[0][0] + (i * VERTEXSIZE);
172 VectorCopy (poly_vert, verts[i]);
173 }
174
175 SubdividePolygon (fa->polys->numverts, verts[0]);
176 }
177
178 //==============================================================================
179 //
180 // RENDER-TO-FRAMEBUFFER WATER
181 //
182 //==============================================================================
R_RasterWarpTexture(texture_t * tx,float warptess)183 static void R_RasterWarpTexture(texture_t *tx, float warptess) {
184 float x, y, x2;
185
186 VkRect2D render_area;
187 render_area.offset.x = 0;
188 render_area.offset.y = 0;
189 render_area.extent.width = WARPIMAGESIZE;
190 render_area.extent.height = WARPIMAGESIZE;
191
192 VkRenderPassBeginInfo render_pass_begin_info;
193 memset(&render_pass_begin_info, 0, sizeof(render_pass_begin_info));
194 render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
195 render_pass_begin_info.renderArea = render_area;
196 render_pass_begin_info.renderPass = vulkan_globals.warp_render_pass;
197 render_pass_begin_info.framebuffer = tx->warpimage->frame_buffer;
198
199 vkCmdBeginRenderPass(vulkan_globals.command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
200
201 //render warp
202 GL_SetCanvas(CANVAS_WARPIMAGE);
203 R_BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, vulkan_globals.raster_tex_warp_pipeline);
204 if (!r_lightmap_cheatsafe)
205 vkCmdBindDescriptorSets(vulkan_globals.command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vulkan_globals.basic_pipeline_layout.handle, 0, 1, &tx->gltexture->descriptor_set, 0, NULL);
206 else
207 vkCmdBindDescriptorSets(vulkan_globals.command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vulkan_globals.basic_pipeline_layout.handle, 0, 1, &whitetexture->descriptor_set, 0, NULL);
208
209 int num_verts = 0;
210 for (y = 0.0; y<128.01; y += warptess) // .01 for rounding errors
211 num_verts += 2;
212
213 for (x = 0.0; x<128.0; x = x2)
214 {
215 VkBuffer buffer;
216 VkDeviceSize buffer_offset;
217 basicvertex_t * vertices = (basicvertex_t*)R_VertexAllocate(num_verts * sizeof(basicvertex_t), &buffer, &buffer_offset);
218
219 int i = 0;
220 x2 = x + warptess;
221 for (y = 0.0; y<128.01; y += warptess) // .01 for rounding errors
222 {
223 vertices[i].position[0] = x;
224 vertices[i].position[1] = y;
225 vertices[i].position[2] = 0.0f;
226 vertices[i].texcoord[0] = WARPCALC(x, y);
227 vertices[i].texcoord[1] = 1.0f - WARPCALC(y, x);
228 vertices[i].color[0] = 255;
229 vertices[i].color[1] = 255;
230 vertices[i].color[2] = 255;
231 vertices[i].color[3] = 255;
232 i += 1;
233 vertices[i].position[0] = x2;
234 vertices[i].position[1] = y;
235 vertices[i].position[2] = 0.0f;
236 vertices[i].texcoord[0] = WARPCALC(x2, y);
237 vertices[i].texcoord[1] = 1.0f - WARPCALC(y, x2);
238 vertices[i].color[0] = 255;
239 vertices[i].color[1] = 255;
240 vertices[i].color[2] = 255;
241 vertices[i].color[3] = 255;
242 i += 1;
243 }
244
245 vkCmdBindVertexBuffers(vulkan_globals.command_buffer, 0, 1, &buffer, &buffer_offset);
246 vkCmdDraw(vulkan_globals.command_buffer, num_verts, 1, 0, 0);
247 }
248
249 vkCmdEndRenderPass(vulkan_globals.command_buffer);
250 }
251
252 /*
253 =============
254 R_ComputeWarpTexture
255 =============
256 */
R_ComputeWarpTexture(texture_t * tx,float warptess)257 static void R_ComputeWarpTexture(texture_t *tx, float warptess) {
258 //render warp
259 const float time = cl.time;
260 R_BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, vulkan_globals.cs_tex_warp_pipeline);
261 VkDescriptorSet sets[2] = { tx->gltexture->descriptor_set, tx->warpimage->warp_write_descriptor_set };
262 if (r_lightmap_cheatsafe)
263 sets[0] = whitetexture->descriptor_set;
264 vkCmdBindDescriptorSets(vulkan_globals.command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, vulkan_globals.cs_tex_warp_pipeline.layout.handle, 0, 2, sets, 0, NULL);
265 R_PushConstants(VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(float), &time);
266 vkCmdDispatch(vulkan_globals.command_buffer, WARPIMAGESIZE / 8, WARPIMAGESIZE / 8, 1);
267 }
268
269 /*
270 =============
271 R_UpdateWarpTextures -- johnfitz -- each frame, update warping textures
272 =============
273 */
274 static texture_t * warp_textures[MAX_GLTEXTURES];
275 static VkImageMemoryBarrier warp_image_barriers[MAX_GLTEXTURES];
276
R_UpdateWarpTextures(void)277 void R_UpdateWarpTextures (void)
278 {
279 GL_SetCanvas(CANVAS_NONE); // Invalidate canvas so push constants get set later
280
281 texture_t *tx;
282 int i, mip;
283 float warptess;
284
285 if (cl.paused)
286 return;
287
288 R_BeginDebugUtilsLabel ("Update Warp Textures");
289
290 warptess = 128.0/CLAMP (3.0, floor(r_waterquality.value), 64.0);
291
292 int num_textures = cl.worldmodel->numtextures;
293 int num_warp_textures = 0;
294
295 // Count warp texture & prepare barrier from undefined to GENERL if using compute warp
296 for (i = 0; i < num_textures; ++i)
297 {
298 if (!(tx = cl.worldmodel->textures[i]))
299 continue;
300
301 if (!tx->update_warp)
302 continue;
303
304 if (r_waterwarpcompute.value)
305 {
306 VkImageMemoryBarrier * image_barrier = &warp_image_barriers[num_warp_textures];
307 image_barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
308 image_barrier->pNext = NULL;
309 image_barrier->srcAccessMask = 0;
310 image_barrier->dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
311 image_barrier->oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
312 image_barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
313 image_barrier->srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
314 image_barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
315 image_barrier->image = tx->warpimage->image;
316 image_barrier->subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
317 image_barrier->subresourceRange.baseMipLevel = 0;
318 image_barrier->subresourceRange.levelCount = WARPIMAGEMIPS;
319 image_barrier->subresourceRange.baseArrayLayer = 0;
320 image_barrier->subresourceRange.layerCount = 1;
321 }
322
323 warp_textures[num_warp_textures] = tx;
324 num_warp_textures += 1;
325 }
326
327 // Transfer mips from UNDEFINED to GENERAL layout
328 if (r_waterwarpcompute.value)
329 vkCmdPipelineBarrier(vulkan_globals.command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, num_warp_textures, warp_image_barriers);
330
331 // Render warp to top mips
332 for (i = 0; i < num_warp_textures; ++i)
333 {
334 tx = warp_textures[i];
335
336 if (r_waterwarpcompute.value)
337 R_ComputeWarpTexture(tx, warptess);
338 else
339 R_RasterWarpTexture(tx, warptess);
340
341 VkImageMemoryBarrier * image_barrier = &warp_image_barriers[i];
342 image_barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
343 image_barrier->pNext = NULL;
344 image_barrier->srcAccessMask = 0;
345 image_barrier->dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
346 image_barrier->oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
347 image_barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
348 image_barrier->srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
349 image_barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
350 image_barrier->image = tx->warpimage->image;
351 image_barrier->subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
352 image_barrier->subresourceRange.baseMipLevel = 1;
353 image_barrier->subresourceRange.levelCount = WARPIMAGEMIPS - 1;
354 image_barrier->subresourceRange.baseArrayLayer = 0;
355 image_barrier->subresourceRange.layerCount = 1;
356 }
357
358 // Make sure that writes are done for top mips we just rendered to
359 VkMemoryBarrier memory_barrier;
360 memory_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
361 memory_barrier.pNext = NULL;
362 memory_barrier.srcAccessMask = r_waterwarpcompute.value ? VK_ACCESS_SHADER_WRITE_BIT : VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
363 memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
364
365 // Transfer all other mips from UNDEFINED to GENERAL layout
366 vkCmdPipelineBarrier(vulkan_globals.command_buffer, r_waterwarpcompute.value ? VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT : VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, &memory_barrier, 0, NULL, num_warp_textures, warp_image_barriers);
367
368 // Generate mip chains
369 for (mip = 1; mip < WARPIMAGEMIPS; ++mip)
370 {
371 int srcSize = WARPIMAGESIZE >> (mip - 1);
372 int dstSize = WARPIMAGESIZE >> mip;
373
374 for (i = 0; i < num_warp_textures; ++i)
375 {
376 tx = warp_textures[i];
377
378 VkImageBlit region;
379 memset(®ion, 0, sizeof(region));
380 region.srcOffsets[1].x = srcSize;
381 region.srcOffsets[1].y = srcSize;
382 region.srcOffsets[1].z = 1;
383 region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
384 region.srcSubresource.layerCount = 1;
385 region.srcSubresource.mipLevel = (mip - 1);
386 region.dstOffsets[1].x = dstSize;
387 region.dstOffsets[1].y = dstSize;
388 region.dstOffsets[1].z = 1;
389 region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
390 region.dstSubresource.layerCount = 1;
391 region.dstSubresource.mipLevel = mip;
392
393 vkCmdBlitImage(vulkan_globals.command_buffer, tx->warpimage->image, VK_IMAGE_LAYOUT_GENERAL, tx->warpimage->image, VK_IMAGE_LAYOUT_GENERAL, 1, ®ion, VK_FILTER_LINEAR);
394 }
395
396 if (mip < (WARPIMAGEMIPS - 1))
397 {
398 memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
399 memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
400 vkCmdPipelineBarrier(vulkan_globals.command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, &memory_barrier, 0, NULL, 0, NULL);
401 }
402 }
403
404 // Transfer all warp texture mips from GENERAL to SHADER_READ_ONLY_OPTIMAL
405 for (i = 0; i < num_warp_textures; ++i)
406 {
407 tx = warp_textures[i];
408
409 VkImageMemoryBarrier * image_barrier = &warp_image_barriers[i];
410 image_barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
411 image_barrier->pNext = NULL;
412 image_barrier->srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
413 image_barrier->dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
414 image_barrier->oldLayout = VK_IMAGE_LAYOUT_GENERAL;
415 image_barrier->newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
416 image_barrier->srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
417 image_barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
418 image_barrier->image = tx->warpimage->image;
419 image_barrier->subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
420 image_barrier->subresourceRange.baseMipLevel = 0;
421 image_barrier->subresourceRange.levelCount = WARPIMAGEMIPS;
422 image_barrier->subresourceRange.baseArrayLayer = 0;
423 image_barrier->subresourceRange.layerCount = 1;
424
425 tx->update_warp = false;
426 }
427
428 vkCmdPipelineBarrier(vulkan_globals.command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, num_warp_textures, warp_image_barriers);
429
430 //if warp render went down into sbar territory, we need to be sure to refresh it next frame
431 if (WARPIMAGESIZE + sb_lines > glheight)
432 Sbar_Changed ();
433
434 //if viewsize is less than 100, we need to redraw the frame around the viewport
435 scr_tileclear_updates = 0;
436
437 R_EndDebugUtilsLabel ();
438 }
439