OpenGothic
Open source reimplementation of Gothic I and II
Loading...
Searching...
No Matches
renderer.cpp
Go to the documentation of this file.
1#include "renderer.h"
2
3#include <Tempest/Color>
4#include <Tempest/Fence>
5#include <Tempest/Log>
6#include <Tempest/StorageImage>
7#include <cassert>
8
9#include "ui/inventorymenu.h"
10#include "ui/videowidget.h"
11#include "camera.h"
12#include "gothic.h"
13#include "utils/string_frm.h"
14
15using namespace Tempest;
16
17static const bool skyPathTrace = false;
18
19static uint32_t nextPot(uint32_t x) {
20 x--;
21 x |= x >> 1;
22 x |= x >> 2;
23 x |= x >> 4;
24 x |= x >> 8;
25 x |= x >> 16;
26 x++;
27 return x;
28 }
29
30static float smoothstep(float edge0, float edge1, float x) {
31 float t = std::min(std::max((x - edge0) / (edge1 - edge0), 0.f), 1.f);
32 return t * t * (3.f - 2.f * t);
33 };
34
35static float linearstep(float edge0, float edge1, float x) {
36 float t = std::min(std::max((x - edge0) / (edge1 - edge0), 0.f), 1.f);
37 return t;
38 };
39
40static Size tileCount(Size sz, int s) {
41 sz.w = (sz.w+s-1)/s;
42 sz.h = (sz.h+s-1)/s;
43 return sz;
44 }
45
46Renderer::Renderer(Tempest::Swapchain& swapchain)
47 : swapchain(swapchain) {
48 auto& device = Resources::device();
49
50 static const TextureFormat sfrm[] = {
51 TextureFormat::Depth16,
52 TextureFormat::Depth24x8,
53 TextureFormat::Depth32F,
54 };
55
56 for(auto& i:sfrm) {
57 if(device.properties().hasDepthFormat(i) && device.properties().hasSamplerFormat(i)) {
58 shadowFormat = i;
59 break;
60 }
61 }
62
63 static const TextureFormat zfrm[] = {
64 TextureFormat::Depth32F,
65 TextureFormat::Depth24x8,
66 TextureFormat::Depth16,
67 };
68 for(auto& i:zfrm) {
69 if(device.properties().hasDepthFormat(i) && device.properties().hasSamplerFormat(i)){
70 zBufferFormat = i;
71 break;
72 }
73 }
74
75 // crappy rasbery-pi like hardware
76 if(!device.properties().hasStorageFormat(sky.lutRGBAFormat))
77 sky.lutRGBAFormat = Tempest::TextureFormat::RGBA8;
78 if(!device.properties().hasStorageFormat(sky.lutRGBFormat))
79 sky.lutRGBFormat = Tempest::TextureFormat::RGBA8;
80
81 Log::i("GPU = ",device.properties().name);
82 Log::i("Depth format = ", Tempest::formatName(zBufferFormat), " Shadow format = ", Tempest::formatName(shadowFormat));
83
84 Gothic::inst().onSettingsChanged.bind(this,&Renderer::setupSettings);
85 Gothic::inst().toggleGi .bind(this, &Renderer::toggleGi);
86 Gothic::inst().toggleVsm .bind(this, &Renderer::toggleVsm);
87 Gothic::inst().toggleRtsm.bind(this, &Renderer::toggleRtsm);
88
89 settings.giEnabled = Gothic::options().doRtGi;
90 settings.vsmEnabled = Gothic::options().doVirtualShadow;
91 settings.rtsmEnabled = Gothic::options().doSoftwareShadow;
92 settings.swrEnabled = Gothic::options().swRenderingPreset>0;
93 settings.swrtEnabled = Gothic::options().doSoftwareRT;
94
95 sky.cloudsLut = device.image2d (sky.lutRGBAFormat, 2, 1);
96 sky.transLut = device.attachment(sky.lutRGBFormat, 256, 64);
97 sky.multiScatLut = device.attachment(sky.lutRGBFormat, 32, 32);
98 sky.viewLut = device.attachment(Tempest::TextureFormat::RGBA32F, 128, 64);
99 sky.viewCldLut = device.attachment(Tempest::TextureFormat::RGBA32F, 512, 256);
100 sky.irradianceLut = device.image2d(TextureFormat::RGBA32F, 3,2);
101
102 setupSettings();
103 }
104
106 Gothic::inst().onSettingsChanged.ubind(this,&Renderer::setupSettings);
107 }
108
110 auto& device = Resources::device();
111 device.waitIdle();
112 shaders.waitCompiler();
113
114 const auto res = internalResolution();
115 const uint32_t w = uint32_t(res.w);
116 const uint32_t h = uint32_t(res.h);
117
118 sceneLinear = device.attachment(TextureFormat::R11G11B10UF,w,h);
119
120 if(settings.aaEnabled) {
121 cmaa2.workingEdges = device.image2d(TextureFormat::R8, (w + 1) / 2, h);
122 cmaa2.shapeCandidates = device.ssbo(Tempest::Uninitialized, w * h / 4 * sizeof(uint32_t));
123 cmaa2.deferredBlendLocationList = device.ssbo(Tempest::Uninitialized, (w * h + 3) / 6 * sizeof(uint32_t));
124 cmaa2.deferredBlendItemList = device.ssbo(Tempest::Uninitialized, w * h * sizeof(uint32_t));
125 cmaa2.deferredBlendItemListHeads = device.image2d(TextureFormat::R32U, (w + 1) / 2, (h + 1) / 2);
126 cmaa2.controlBuffer = device.ssbo(nullptr, 5 * sizeof(uint32_t));
127 cmaa2.indirectBuffer = device.ssbo(nullptr, sizeof(DispatchIndirectCommand) + sizeof(DrawIndirectCommand));
128 }
129
130 zbuffer = device.zbuffer(zBufferFormat,w,h);
131 if(w!=swapchain.w() || h!=swapchain.h())
132 zbufferUi = device.zbuffer(zBufferFormat, swapchain.w(), swapchain.h()); else
133 zbufferUi = ZBuffer();
134
135 uint32_t pw = nextPot(w);
136 uint32_t ph = nextPot(h);
137
138 uint32_t hw = pw;
139 uint32_t hh = ph;
140 while(hw>64 || hh>64) {
141 hw = std::max(1u, (hw+1)/2u);
142 hh = std::max(1u, (hh+1)/2u);
143 }
144
145 hiz.atomicImg = device.properties().hasAtomicFormat(TextureFormat::R32U);
146 hiz.hiZ = device.image2d(TextureFormat::R16, hw, hh, true);
147 if(hiz.atomicImg) {
148 hiz.counter = device.image2d(TextureFormat::R32U, std::max(hw/4, 1u), std::max(hh/4, 1u), false);
149 } else {
150 hiz.counterBuf = device.ssbo(Tempest::Uninitialized, std::max(hw/4, 1u)*std::max(hh/4, 1u)*sizeof(uint32_t));
151 }
152
153 sceneOpaque = device.attachment(TextureFormat::R11G11B10UF,w,h);
154 sceneDepth = device.attachment(TextureFormat::R32F, w,h);
155
156 gbufDiffuse = device.attachment(TextureFormat::RGBA8,w,h);
157 gbufNormal = device.attachment(TextureFormat::R32U, w,h);
158
159 ssao.ssaoBuf = device.image2d(ssao.aoFormat, w, h);
160 ssao.ssaoBlur = device.image2d(ssao.aoFormat, w, h);
161
162 epipolar = decltype(epipolar)();
163 vsm = decltype(vsm)();
164 rtsm = decltype(rtsm)();
165
166 // software renderer
167 swr.outputImage = StorageImage();
168
169 // swrt
170 swrt.outputImage = StorageImage();
171
172 resetSkyFog();
173 prepareUniforms();
174 }
175
176void Renderer::setupSettings() {
177 settings.zEnvMappingEnabled = Gothic::settingsGetI("ENGINE","zEnvMappingEnabled")!=0;
178 settings.zCloudShadowScale = Gothic::settingsGetI("ENGINE","zCloudShadowScale") !=0;
179 settings.zFogRadial = Gothic::settingsGetI("RENDERER_D3D","zFogRadial")!=0;
180
181 settings.zVidBrightness = Gothic::settingsGetF("VIDEO","zVidBrightness");
182 settings.zVidContrast = Gothic::settingsGetF("VIDEO","zVidContrast");
183 settings.zVidGamma = Gothic::settingsGetF("VIDEO","zVidGamma");
184
185 settings.sunSize = Gothic::settingsGetF("SKY_OUTDOOR","zSunSize");
186 settings.moonSize = Gothic::settingsGetF("SKY_OUTDOOR","zMoonSize");
187 if(settings.sunSize<=1)
188 settings.sunSize = 200;
189 if(settings.moonSize<=1)
190 settings.moonSize = 400;
191
192 auto prevVidResIndex = settings.vidResIndex;
193 settings.vidResIndex = Gothic::inst().settingsGetF("INTERNAL","vidResIndex");
194 settings.aaEnabled = (Gothic::options().aaPreset>0) && (settings.vidResIndex==0);
195
196 // direct lighting
197 if(settings.rtsmEnabled)
198 shadow.directLightPso = &shaders.rtsmDirectLight;
199 else if(settings.vsmEnabled)
200 shadow.directLightPso = &shaders.vsmDirectLight; //TODO: naming
201 else if(Gothic::options().doRayQuery && Resources::device().properties().descriptors.nonUniformIndexing &&
202 settings.shadowResolution>0)
203 shadow.directLightPso = &shaders.directLightRq;
204 else if(settings.shadowResolution>0)
205 shadow.directLightPso = &shaders.directLightSh;
206 else
207 shadow.directLightPso = &shaders.directLight;
208
209 // point-lights
210 if(settings.vsmEnabled)
211 lights.directLightPso = &shaders.lightsVsm;
212 else if(Gothic::options().doRayQuery && Resources::device().properties().descriptors.nonUniformIndexing)
213 lights.directLightPso = &shaders.lightsRq;
214 else
215 lights.directLightPso = &shaders.lights;
216
217 if(prevVidResIndex!=settings.vidResIndex) {
219 }
220 resetSkyFog();
221 resetShadowmap();
222
223 prepareUniforms();
224 }
225
226void Renderer::toggleGi() {
227 auto& device = Resources::device();
228 if(!Gothic::options().doRayQuery)
229 return;
230
231 auto prop = device.properties();
232 if(prop.tex2d.maxSize<4096 || !prop.hasStorageFormat(R11G11B10UF) || !prop.hasStorageFormat(R16))
233 return;
234
235 settings.giEnabled = !settings.giEnabled;
236 gi.fisrtFrame = true;
237
238 device.waitIdle();
239 if(auto wview = Gothic::inst().worldView()) {
240 wview->resetRendering();
241 }
242 if(settings.giEnabled) {
243 // need a projective shadow, for gi to
244 resetShadowmap();
245 }
246 resetGiData();
247 prepareUniforms();
248 }
249
250void Renderer::toggleVsm() {
252 return;
253
254 settings.vsmEnabled = !settings.vsmEnabled;
255
256 auto& device = Resources::device();
257 device.waitIdle();
258
259 setupSettings();
261 if(auto wview = Gothic::inst().worldView()) {
262 wview->resetRendering();
263 }
264 }
265
266void Renderer::toggleRtsm() {
268 return;
269
270 settings.rtsmEnabled = !settings.rtsmEnabled;
271
272 auto& device = Resources::device();
273 device.waitIdle();
274
275 setupSettings();
277 if(auto wview = Gothic::inst().worldView()) {
278 wview->resetRendering();
279 }
280 }
281
283 gi.fisrtFrame = true;
284 sky.lutIsInitialized = false;
285 shaders.waitCompiler();
286
288 resetSkyFog();
289 prepareUniforms();
290 }
291
292void Renderer::updateCamera(const Camera& camera) {
293 proj = camera.projective();
294 viewProj = camera.viewProj();
295 viewProjLwc = camera.viewProjLwc();
296
297 if(auto wview=Gothic::inst().worldView()) {
298 for(size_t i=0; i<Resources::ShadowLayers; ++i)
299 shadowMatrix[i] = camera.viewShadow(wview->mainLight().dir(),i);
300 shadowMatrixVsm = camera.viewShadowVsm(wview->mainLight().dir());
301 }
302
303 auto zNear = camera.zNear();
304 auto zFar = camera.zFar();
305 clipInfo.x = zNear*zFar;
306 clipInfo.y = zNear-zFar;
307 clipInfo.z = zFar;
308 }
309
310bool Renderer::requiresTlas() const {
311 if(!Gothic::options().doRayQuery)
312 return false;
313
314 if(settings.giEnabled)
315 return true;
316 if(!(settings.rtsmEnabled || settings.vsmEnabled))
317 return true;
318 return false;
319 }
320
321StorageImage& Renderer::usesImage3d(Tempest::StorageImage& ret, Tempest::TextureFormat frm, uint32_t w, uint32_t h, uint32_t d, bool mips) {
322 if(ret.format()==frm && uint32_t(ret.w())==w && uint32_t(ret.h())==h && uint32_t(ret.d())==d && bool(ret.mipCount()>1)==mips)
323 return ret;
324 Resources::recycle(std::move(ret));
325 ret = Resources::device().image3d(frm, w, h, d, mips);
326 return ret;
327 }
328
329StorageImage& Renderer::usesImage2d(Tempest::StorageImage& ret, Tempest::TextureFormat frm, uint32_t w, uint32_t h, bool mips) {
330 if(ret.format()==frm && uint32_t(ret.w())==w && uint32_t(ret.h())==h && ret.d()==1 && bool(ret.mipCount()>1)==mips)
331 return ret;
332 Resources::recycle(std::move(ret));
333 ret = Resources::device().image2d(frm, w, h, mips);
334 return ret;
335 }
336
337StorageImage& Renderer::usesImage2d(Tempest::StorageImage& ret, Tempest::TextureFormat frm, Tempest::Size size, bool mips) {
338 if(ret.format()==frm && ret.size()==size && ret.d()==1 && (ret.mipCount()>1)==mips)
339 return ret;
340 Resources::recycle(std::move(ret));
341 ret = Resources::device().image2d(frm, size, mips);
342 return ret;
343 }
344
345ZBuffer& Renderer::usesZBuffer(Tempest::ZBuffer& ret, Tempest::TextureFormat frm, uint32_t w, uint32_t h) {
346 if(textureCast<Texture2d&>(ret).format()==frm && uint32_t(ret.w())==w && uint32_t(ret.h())==h)
347 return ret;
348 Resources::recycle(std::move(ret));
349 ret = Resources::device().zbuffer(frm, w, h);
350 return ret;
351 }
352
353StorageBuffer& Renderer::usesSsbo(Tempest::StorageBuffer& ret, size_t size) {
354 if(ret.byteSize()==size)
355 return ret;
356 Resources::recycle(std::move(ret));
357 ret = Resources::device().ssbo(Uninitialized, size);
358 return ret;
359 }
360
361StorageBuffer& Renderer::usesScratch(Tempest::StorageBuffer& ret, size_t size) {
362 if(ret.byteSize()>=size)
363 return ret;
364 Resources::recycle(std::move(ret));
365 ret = Resources::device().ssbo(Uninitialized, size);
366 return ret;
367 }
368
369void Renderer::prepareUniforms() {
370 auto wview = Gothic::inst().worldView();
371 if(wview==nullptr)
372 return;
373
374 const Texture2d* sh[Resources::ShadowLayers] = {};
375 for(size_t i=0; i<Resources::ShadowLayers; ++i)
376 if(!shadowMap[i].isEmpty()) {
377 sh[i] = &textureCast<const Texture2d&>(shadowMap[i]);
378 }
379 wview->setShadowMaps(sh);
380 wview->setVirtualShadowMap(settings.vsmEnabled, vsm.pageData, vsm.pageTbl, vsm.pageHiZ, vsm.pageList);
381
382 wview->setHiZ(textureCast<const Texture2d&>(hiz.hiZ));
383 wview->setGbuffer(textureCast<const Texture2d&>(gbufDiffuse), textureCast<const Texture2d&>(gbufNormal));
384 wview->setSceneImages(textureCast<const Texture2d&>(sceneOpaque), textureCast<const Texture2d&>(sceneDepth), zbuffer);
385 }
386
387void Renderer::resetShadowmap() {
388 auto& device = Resources::device();
389
390 for(int i=0; i<Resources::ShadowLayers; ++i)
391 Resources::recycle(std::move(shadowMap[i]));
392
393 for(int i=0; i<Resources::ShadowLayers; ++i) {
394 if(settings.vsmEnabled && !(settings.giEnabled && i==1) && !(sky.quality==PathTrace && i==1) && !(settings.rtsmEnabled && i==1))
395 continue; //TODO: support vsm in gi code
396 if(settings.rtsmEnabled && !(settings.giEnabled && i==1) && !(sky.quality!=None && i==1))
397 continue; //TODO: support vsm in gi code
398 shadowMap[i] = device.zbuffer(shadowFormat, settings.shadowResolution, settings.shadowResolution);
399 }
400 }
401
402void Renderer::resetSkyFog() {
403 auto& device = Resources::device();
404
405 const auto res = internalResolution();
406 const uint32_t w = uint32_t(res.w);
407 const uint32_t h = uint32_t(res.h);
408
409 {
410 auto q = Quality::VolumetricLQ;
411 if(!settings.zFogRadial) {
412 q = Quality::VolumetricLQ;
413 } else {
414 q = Quality::VolumetricHQ;
415 // q = Quality::Epipolar;
416 }
417
418 if(skyPathTrace)
419 q = PathTrace;
420
421 if(sky.quality==q && (sky.occlusionLut.isEmpty() || sky.occlusionLut.size()==res)) {
422 return;
423 }
424
425 sky.quality = q;
426 }
427
428 Resources::recycle(std::move(sky.fogLut3D));
429 Resources::recycle(std::move(sky.fogLut3DMs));
430 Resources::recycle(std::move(sky.occlusionLut));
431
432 sky.lutIsInitialized = false;
433
434 switch(sky.quality) {
435 case None:
436 case VolumetricLQ:
437 sky.fogLut3D = device.image3d(sky.lutRGBAFormat, 160, 90, 64);
438 sky.occlusionLut = StorageImage();
439 break;
440 case VolumetricHQ:
441 // fogLut and oclussion are decupled
442 sky.fogLut3D = device.image3d(sky.lutRGBFormat, 128,64,32);
443 sky.fogLut3DMs = device.image3d(sky.lutRGBAFormat, 128,64,32);
444 sky.occlusionLut = device.image2d(TextureFormat::R32U, w, h);
445 break;
446 case Epipolar:
447 sky.fogLut3D = device.image3d(sky.lutRGBFormat, 128,64,32);
448 sky.fogLut3DMs = device.image3d(sky.lutRGBAFormat, 128,64,32);
449 sky.occlusionLut = device.image2d(TextureFormat::R32U, w, h); //TODO: remove
450 break;
451 case PathTrace:
452 break;
453 }
454 }
455
456void Renderer::prepareSky(Tempest::Encoder<Tempest::CommandBuffer>& cmd, WorldView& wview) {
457 auto& scene = wview.sceneGlobals();
458
459 cmd.setDebugMarker("Sky LUT");
460 if(!sky.lutIsInitialized) {
461 sky.lutIsInitialized = true;
462
463 cmd.setFramebuffer({});
464 cmd.setBinding(0, sky.cloudsLut);
465 cmd.setBinding(5, *wview.sky().cloudsDay() .lay[0], Sampler::trillinear());
466 cmd.setBinding(6, *wview.sky().cloudsDay() .lay[1], Sampler::trillinear());
467 cmd.setBinding(7, *wview.sky().cloudsNight().lay[0], Sampler::trillinear());
468 cmd.setBinding(8, *wview.sky().cloudsNight().lay[1], Sampler::trillinear());
469 cmd.setPipeline(shaders.cloudsLut);
470 cmd.dispatchThreads(size_t(sky.cloudsLut.w()), size_t(sky.cloudsLut.h()));
471
472 auto sz = Vec2(float(sky.transLut.w()), float(sky.transLut.h()));
473 cmd.setFramebuffer({{sky.transLut, Tempest::Discard, Tempest::Preserve}});
474 cmd.setBinding(5, *wview.sky().cloudsDay() .lay[0], Sampler::trillinear());
475 cmd.setBinding(6, *wview.sky().cloudsDay() .lay[1], Sampler::trillinear());
476 cmd.setBinding(7, *wview.sky().cloudsNight().lay[0], Sampler::trillinear());
477 cmd.setBinding(8, *wview.sky().cloudsNight().lay[1], Sampler::trillinear());
478 cmd.setPushData(&sz, sizeof(sz));
479 cmd.setPipeline(shaders.skyTransmittance);
480 cmd.draw(nullptr, 0, 3);
481
482 sz = Vec2(float(sky.multiScatLut.w()), float(sky.multiScatLut.h()));
483 cmd.setFramebuffer({{sky.multiScatLut, Tempest::Discard, Tempest::Preserve}});
484 cmd.setBinding(0, sky.transLut, Sampler::bilinear(ClampMode::ClampToEdge));
485 cmd.setPushData(&sz, sizeof(sz));
486 cmd.setPipeline(shaders.skyMultiScattering);
487 cmd.draw(nullptr, 0, 3);
488 }
489
490 auto sz = Vec2(float(sky.viewLut.w()), float(sky.viewLut.h()));
491 cmd.setFramebuffer({{sky.viewLut, Tempest::Discard, Tempest::Preserve}});
492 cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]);
493 cmd.setBinding(1, sky.transLut, Sampler::bilinear(ClampMode::ClampToEdge));
494 cmd.setBinding(2, sky.multiScatLut, Sampler::bilinear(ClampMode::ClampToEdge));
495 cmd.setBinding(3, sky.cloudsLut, Sampler::bilinear(ClampMode::ClampToEdge));
496 cmd.setPushData(&sz, sizeof(sz));
497 cmd.setPipeline(shaders.skyViewLut);
498 cmd.draw(nullptr, 0, 3);
499
500 sz = Vec2(float(sky.viewCldLut.w()), float(sky.viewCldLut.h()));
501 cmd.setFramebuffer({{sky.viewCldLut, Tempest::Discard, Tempest::Preserve}});
502 cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]);
503 cmd.setBinding(1, sky.viewLut);
504 cmd.setBinding(2, *wview.sky().cloudsDay() .lay[0], Sampler::trillinear());
505 cmd.setBinding(3, *wview.sky().cloudsDay() .lay[1], Sampler::trillinear());
506 cmd.setBinding(4, *wview.sky().cloudsNight().lay[0], Sampler::trillinear());
507 cmd.setBinding(5, *wview.sky().cloudsNight().lay[1], Sampler::trillinear());
508 cmd.setPushData(&sz, sizeof(sz));
509 cmd.setPipeline(shaders.skyViewCldLut);
510 cmd.draw(nullptr, 0, 3);
511 }
512
513void Renderer::draw(Encoder<CommandBuffer>& cmd, uint8_t cmdId, size_t imgId,
514 VectorImage::Mesh& uiLayer, VectorImage::Mesh& numOverlay,
515 InventoryMenu& inventory, VideoWidget& video) {
516 auto& result = swapchain[imgId];
517
518 if(!video.isActive()) {
519 draw(result, cmd, cmdId);
520 } else {
521 cmd.setFramebuffer({{result, Vec4(), Tempest::Preserve}});
522 }
523 cmd.setFramebuffer({{result, Tempest::Preserve, Tempest::Preserve}});
524 cmd.setDebugMarker("UI");
525 uiLayer.draw(cmd);
526
527 if(inventory.isOpen()!=InventoryMenu::State::Closed) {
528 auto& zb = (zbufferUi.isEmpty() ? zbuffer : zbufferUi);
529 cmd.setFramebuffer({{result, Tempest::Preserve, Tempest::Preserve}},{zb, 1.f, Tempest::Preserve});
530 cmd.setDebugMarker("Inventory");
531 inventory.draw(cmd);
532
533 cmd.setFramebuffer({{result, Tempest::Preserve, Tempest::Preserve}});
534 cmd.setDebugMarker("Inventory-counters");
535 numOverlay.draw(cmd);
536 }
537 }
538
539void Renderer::dbgDraw(Tempest::Painter& p) {
540 static bool dbg = false;
541 if(!dbg)
542 return;
543
544 std::vector<const Texture2d*> tex;
545 //tex.push_back(&textureCast(swr.outputImage));
546 //tex.push_back(&textureCast(hiz.hiZ));
547 //tex.push_back(&textureCast(hiz.smProj));
548 //tex.push_back(&textureCast(hiz.hiZSm1));
549 //tex.push_back(&textureCast(shadowMap[1]));
550 //tex.push_back(&textureCast<const Texture2d&>(shadowMap[0]));
551 //tex.push_back(&textureCast<const Texture2d&>(vsm.pageData));
552 tex.push_back(&textureCast<const Texture2d&>(swrt.outputImage));
553
554 static int size = 400;
555 int left = 10;
556 for(auto& t:tex) {
557 p.setBrush(Brush(*t,Painter::NoBlend,ClampMode::ClampToBorder));
558 auto sz = Size(p.brush().w(),p.brush().h());
559 if(sz.isEmpty())
560 continue;
561 while(sz.w<size && sz.h<size) {
562 sz.w *= 2;
563 sz.h *= 2;
564 }
565 while(sz.w>size*2 || sz.h>size*2) {
566 sz.w = (sz.w+1)/2;
567 sz.h = (sz.h+1)/2;
568 }
569 p.drawRect(left,50,sz.w,sz.h,
570 0,0,p.brush().w(),p.brush().h());
571 left += (sz.w+10);
572 }
573 }
574
575void Renderer::draw(Tempest::Attachment& result, Encoder<CommandBuffer>& cmd, uint8_t fId) {
576 auto wview = Gothic::inst().worldView();
577 auto camera = Gothic::inst().camera();
578 if(wview==nullptr || camera==nullptr) {
579 cmd.setFramebuffer({{result, Vec4(), Tempest::Preserve}});
580 return;
581 }
582
583 if(requiresTlas())
584 wview->updateRtScene();
585 wview->updateLights();
586
587 updateCamera(*camera);
588
589 static bool updFr = true;
590 if(updFr){
591 if(wview->mainLight().dir().y>Camera::minShadowY) {
592 frustrum[SceneGlobals::V_Shadow0].make(shadowMatrix[0],shadowMap[0].w(),shadowMap[0].h());
593 frustrum[SceneGlobals::V_Shadow1].make(shadowMatrix[1],shadowMap[1].w(),shadowMap[1].h());
594 } else {
595 frustrum[SceneGlobals::V_Shadow0].clear();
596 frustrum[SceneGlobals::V_Shadow1].clear();
597 }
598 frustrum[SceneGlobals::V_Main].make(viewProj,zbuffer.w(),zbuffer.h());
599 frustrum[SceneGlobals::V_HiZ] = frustrum[SceneGlobals::V_Main];
600 frustrum[SceneGlobals::V_Vsm] = frustrum[SceneGlobals::V_Shadow1]; //TODO: remove
601 wview->updateFrustrum(frustrum);
602 }
603
604 wview->preFrameUpdate(*camera,Gothic::inst().world()->tickCount(),fId);
605 wview->prepareGlobals(cmd,fId);
606
607 wview->visibilityPass(cmd, 0);
608 prepareSky(cmd,*wview);
609
610 drawHiZ (cmd, *wview);
611 buildHiZ(cmd);
612
613 wview->visibilityPass(cmd, 1);
614 drawGBuffer(cmd,fId,*wview);
615
616 drawShadowMap(cmd,fId,*wview);
617 prepareEpipolar(cmd, *wview);
618
619 drawVsm(cmd, *wview);
620 drawSwr(cmd, *wview);
621 drawRtsm(cmd, *wview);
622 drawRtsmOmni(cmd, *wview);
623
624 drawSwRT(cmd, *wview);
625
626 prepareIrradiance(cmd,*wview);
627 prepareExposure(cmd,*wview);
628 prepareSSAO(cmd,*wview);
629 prepareFog (cmd,*wview);
630 prepareGi (cmd,*wview);
631
632 cmd.setFramebuffer({{sceneLinear, Tempest::Discard, Tempest::Preserve}}, {zbuffer, Tempest::Readonly});
633 drawShadowResolve(cmd,*wview);
634 drawAmbient(cmd,*wview);
635 drawLights(cmd,*wview);
636 drawSky(cmd,*wview);
637
638 stashSceneAux(cmd);
639
640 drawGWater(cmd, *wview);
641
642 cmd.setFramebuffer({{sceneLinear, Tempest::Preserve, Tempest::Preserve}}, {zbuffer, Tempest::Preserve, Tempest::Preserve});
643 cmd.setDebugMarker("Sun&Moon");
644 drawSunMoon(cmd, *wview);
645 cmd.setDebugMarker("Translucent");
646 wview->drawTranslucent(cmd, fId);
647
648 drawProbesDbg(cmd, *wview);
649 drawProbesHitDbg(cmd);
650 drawVsmDbg(cmd, *wview);
651 drawSwrDbg(cmd, *wview);
652 drawRtsmDbg(cmd, *wview);
653
654 cmd.setFramebuffer({{sceneLinear, Tempest::Preserve, Tempest::Preserve}});
655 drawReflections(cmd, *wview);
656 if(camera->isInWater()) {
657 cmd.setDebugMarker("Underwater");
658 drawUnderwater(cmd, *wview);
659 } else {
660 cmd.setDebugMarker("Fog");
661 drawFog(cmd, *wview);
662 }
663
664 if(settings.aaEnabled) {
665 cmd.setDebugMarker("CMAA2 & Tonemapping");
666 drawCMAA2(result, cmd, *wview);
667 } else {
668 cmd.setDebugMarker("Tonemapping");
669 drawTonemapping(result, cmd, *wview);
670 }
671
672 wview->postFrameupdate();
673 }
674
675void Renderer::drawTonemapping(Attachment& result, Encoder<CommandBuffer>& cmd, const WorldView& wview) {
676 struct Push {
677 float brightness = 0;
678 float contrast = 1;
679 float gamma = 1.f/2.2f;
680 float mul = 1;
681 };
682
683 Push p;
684 p.brightness = (settings.zVidBrightness - 0.5f)*0.1f;
685 p.contrast = std::max(1.5f - settings.zVidContrast, 0.01f);
686 p.gamma = p.gamma/std::max(2.0f*settings.zVidGamma, 0.01f);
687
688 static float mul = 0.f;
689 if(mul>0)
690 p.mul = mul;
691
692 auto& pso = (settings.vidResIndex==0) ? shaders.tonemapping : shaders.tonemappingUpscale;
693 cmd.setFramebuffer({ {result, Tempest::Discard, Tempest::Preserve} });
694 cmd.setBinding(0, wview.sceneGlobals().uboGlobal[SceneGlobals::V_Main]);
695 cmd.setBinding(1, sceneLinear, Sampler::nearest(ClampMode::ClampToEdge)); // Lanczos upscale requires nearest sampling
696 cmd.setPushData(p);
697 cmd.setPipeline(pso);
698 cmd.draw(nullptr, 0, 3);
699 }
700
701void Renderer::drawCMAA2(Tempest::Attachment& result, Tempest::Encoder<Tempest::CommandBuffer>& cmd, const WorldView& wview) {
702 auto& pso = shaders.cmaa2EdgeColor2x2Presets[Gothic::options().aaPreset];
703 const IVec3 inputGroupSize = pso.workGroupSize();
704 const IVec3 outputGroupSize = inputGroupSize - IVec3(2, 2, 0);
705 const uint32_t groupCountX = uint32_t((sceneLinear.w() + outputGroupSize.x * 2 - 1) / (outputGroupSize.x * 2));
706 const uint32_t groupCountY = uint32_t((sceneLinear.h() + outputGroupSize.y * 2 - 1) / (outputGroupSize.y * 2));
707
708 cmd.setFramebuffer({});
709 cmd.setBinding(0, sceneLinear, Sampler::bilinear(ClampMode::ClampToEdge));
710 cmd.setBinding(1, cmaa2.workingEdges);
711 cmd.setBinding(2, cmaa2.shapeCandidates);
712 cmd.setBinding(3, cmaa2.deferredBlendLocationList);
713 cmd.setBinding(4, cmaa2.deferredBlendItemList);
714 cmd.setBinding(5, cmaa2.deferredBlendItemListHeads);
715 cmd.setBinding(6, cmaa2.controlBuffer);
716 cmd.setBinding(7, cmaa2.indirectBuffer);
717
718 // detect edges
719 cmd.setPipeline(pso);
720 cmd.dispatch(groupCountX, groupCountY, 1);
721
722 // process candidates pass
723 cmd.setPipeline(shaders.cmaa2ProcessCandidates);
724 cmd.dispatchIndirect(cmaa2.indirectBuffer, 0);
725
726 // deferred color apply
727 struct Push {
728 float brightness = 0;
729 float contrast = 1;
730 float gamma = 1.f/2.2f;
731 float mul = 1;
732 };
733
734 Push p;
735 p.brightness = (settings.zVidBrightness - 0.5f)*0.1f;
736 p.contrast = std::max(1.5f - settings.zVidContrast, 0.01f);
737 p.gamma = p.gamma/std::max(2.0f*settings.zVidGamma, 0.01f);
738
739 static float mul = 0.f;
740 if(mul>0)
741 p.mul = mul;
742
743 auto& psoTone = (settings.vidResIndex==0) ? shaders.tonemapping : shaders.tonemappingUpscale;
744 cmd.setFramebuffer({{result, Tempest::Discard, Tempest::Preserve}});
745 cmd.setBinding(0, wview.sceneGlobals().uboGlobal[SceneGlobals::V_Main]);
746 cmd.setBinding(1, sceneLinear, Sampler::nearest());
747 cmd.setPushData(&p, sizeof(p));
748 cmd.setPipeline(psoTone);
749 cmd.draw(nullptr, 0, 3);
750
751 cmd.setBinding(0, sceneLinear);
752 cmd.setBinding(1, cmaa2.workingEdges);
753 cmd.setBinding(2, cmaa2.shapeCandidates);
754 cmd.setBinding(3, cmaa2.deferredBlendLocationList);
755 cmd.setBinding(4, cmaa2.deferredBlendItemList);
756 cmd.setBinding(5, cmaa2.deferredBlendItemListHeads);
757 cmd.setBinding(6, cmaa2.controlBuffer);
758 cmd.setPushData(&p, sizeof(p));
759 cmd.setPipeline(shaders.cmaa2DeferredColorApply2x2);
760 cmd.drawIndirect(cmaa2.indirectBuffer, 3*sizeof(uint32_t));
761 }
762
763void Renderer::drawFog(Tempest::Encoder<Tempest::CommandBuffer>& cmd, const WorldView& wview) {
764 auto& scene = wview.sceneGlobals();
765
766 switch(sky.quality) {
767 case None:
768 case VolumetricLQ: {
769 cmd.setBinding(0, sky.fogLut3D, Sampler::bilinear(ClampMode::ClampToEdge));
770 cmd.setBinding(1, sky.fogLut3D, Sampler::bilinear(ClampMode::ClampToEdge));
771 cmd.setBinding(2, zbuffer, Sampler::nearest()); // NOTE: wanna here depthFetch from gles2
772 cmd.setBinding(3, scene.uboGlobal[SceneGlobals::V_Main]);
773 cmd.setPipeline(shaders.fog);
774 break;
775 }
776 case VolumetricHQ: {
777 cmd.setBinding(0, sky.fogLut3D, Sampler::bilinear(ClampMode::ClampToEdge));
778 cmd.setBinding(1, sky.fogLut3DMs, Sampler::bilinear(ClampMode::ClampToEdge));
779 cmd.setBinding(2, zbuffer, Sampler::nearest());
780 cmd.setBinding(3, scene.uboGlobal[SceneGlobals::V_Main]);
781 cmd.setBinding(4, sky.occlusionLut);
782 cmd.setPipeline(shaders.fog3dHQ);
783 break;
784 }
785 case Epipolar: {
786 //cmd.setBinding(0, sky.fogLut3D, Sampler::bilinear(ClampMode::ClampToEdge));
787 cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]);
788 cmd.setBinding(1, zbuffer, Sampler::nearest());
789 cmd.setBinding(2, vsm.fogDbg, Sampler::bilinear(ClampMode::ClampToEdge));
790 cmd.setBinding(3, epipolar.epipoles);
791 cmd.setBinding(4, sky.fogLut3DMs, Sampler::bilinear(ClampMode::ClampToEdge));
792 cmd.setPipeline(shaders.vsmFog);
793 break;
794 }
795 case PathTrace:
796 return;
797 }
798 cmd.draw(nullptr, 0, 3);
799 }
800
801void Renderer::drawSunMoon(Tempest::Encoder<Tempest::CommandBuffer>& cmd, const WorldView& wview) {
802 drawSunMoon(cmd, wview, false);
803 drawSunMoon(cmd, wview, true);
804 }
805
806void Renderer::drawSunMoon(Tempest::Encoder<Tempest::CommandBuffer>& cmd, const WorldView& wview, bool isSun) {
807 auto& scene = wview.sceneGlobals();
808 auto& sun = wview.sky().sunLight();
809 auto m = scene.viewProject();
810 auto d = sun.dir();
811
812 if(!isSun) {
813 // fixed pos for now
814 d = Vec3::normalize({-1,1,0});
815 }
816
817 auto dx = d;
818 float w = 0;
819 m.project(dx.x, dx.y, dx.z, w);
820
821 if(dx.z<=0)
822 return;
823
824 struct Push {
825 Tempest::Vec2 pos;
826 Tempest::Vec2 size;
827 Tempest::Vec3 sunDir;
828 float GSunIntensity = 0;
829 Tempest::Matrix4x4 viewProjectInv;
830 uint32_t isSun = 0;
831 } push;
832 push.pos = Vec2(dx.x,dx.y)/dx.z;
833 push.size.x = 2.f/float(zbuffer.w());
834 push.size.y = 2.f/float(zbuffer.h());
835
836 const float GSunIntensity = wview.sky().sunIntensity();
837 const float GMoonIntensity = wview.sky().moonIntensity();
838
839 const float scale = internalResolutionScale();
840 const float sunSize = settings.sunSize * scale;
841 const float moonSize = settings.moonSize * scale;
842 const float intencity = isSun ? 0.07f : 0.4f;
843
844 push.size *= isSun ? sunSize : (moonSize*0.25f);
845 push.GSunIntensity = isSun ? (GSunIntensity*intencity) : (GMoonIntensity*intencity);
846 push.isSun = isSun ? 1 : 0;
847 push.sunDir = d;
848 push.viewProjectInv = scene.viewProjectLwcInv();
849
850 // HACK
851 if(isSun) {
852 float day = sun.dir().y;
853 float stp = linearstep(-0.07f, 0.03f, day);
854 push.GSunIntensity *= stp*stp*4.f;
855 } else {
856 push.GSunIntensity *= wview.sky().isNight();
857 }
858 // push.GSunIntensity *= exposure;
859
860 cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]);
861 cmd.setBinding(1, isSun ? wview.sky().sunImage() : wview.sky().moonImage());
862 cmd.setBinding(2, sky.transLut, Sampler::bilinear(ClampMode::ClampToEdge));
863 cmd.setPushData(push);
864 cmd.setPipeline(shaders.sun);
865 cmd.draw(nullptr, 0, 6);
866 }
867
868void Renderer::drawSwRT(Tempest::Encoder<Tempest::CommandBuffer>& cmd, const WorldView& wview) {
869 if(!settings.swrtEnabled)
870 return;
871
872 const auto& scene = wview.sceneGlobals();
873 const auto& bvh = wview.landscape().bvh();
874 const auto originLwc = scene.originLwc;
875
876 if(swrt.outputImage.size()!=zbuffer.size()) {
877 Resources::recycle(std::move(swrt.outputImage));
878 auto& device = Resources::device();
879 // swrt.outputImage = device.image2d(TextureFormat::R32U, zbuffer.size());
880 swrt.outputImage = device.image2d(TextureFormat::RGBA8, zbuffer.size());
881 }
882
883 cmd.setFramebuffer({});
884 cmd.setDebugMarker("Raytracing");
885 //cmd.setPipeline(shaders.swRaytracing8);
886 cmd.setPipeline(shaders.swRaytracing);
887 cmd.setPushData(&originLwc, sizeof(originLwc));
888 cmd.setBinding(0, swrt.outputImage);
889 cmd.setBinding(1, scene.uboGlobal[SceneGlobals::V_Main]);
890 cmd.setBinding(2, gbufDiffuse);
891 cmd.setBinding(3, gbufNormal);
892 cmd.setBinding(4, zbuffer);
893 cmd.setBinding(5, bvh);
894
895 cmd.dispatchThreads(swrt.outputImage.size());
896 }
897
898void Renderer::stashSceneAux(Encoder<CommandBuffer>& cmd) {
899 auto& device = Resources::device();
900 if(!device.properties().hasSamplerFormat(zBufferFormat))
901 return;
902 cmd.setFramebuffer({{sceneOpaque, Tempest::Discard, Tempest::Preserve}, {sceneDepth, Tempest::Discard, Tempest::Preserve}});
903 cmd.setDebugMarker("Stash scene");
904 cmd.setBinding(0, sceneLinear,Sampler::nearest());
905 cmd.setBinding(1, zbuffer, Sampler::nearest());
906 cmd.setPipeline(shaders.stash);
907 cmd.draw(nullptr, 0, 3);
908 }
909
910void Renderer::drawVsmDbg(Tempest::Encoder<Tempest::CommandBuffer>& cmd, const WorldView& wview) {
911 static bool enable = false;
912 if(!enable || !settings.vsmEnabled)
913 return;
914
915 cmd.setFramebuffer({{sceneLinear, Tempest::Preserve, Tempest::Preserve}});
916 cmd.setDebugMarker("VSM-dbg");
917 cmd.setBinding(0, wview.sceneGlobals().uboGlobal[SceneGlobals::V_Main]);
918 cmd.setBinding(1, gbufDiffuse, Sampler::nearest());
919 cmd.setBinding(2, gbufNormal, Sampler::nearest());
920 cmd.setBinding(3, zbuffer, Sampler::nearest());
921 cmd.setBinding(4, vsm.pageTbl);
922 cmd.setBinding(5, vsm.pageList);
923 cmd.setBinding(6, vsm.pageData);
924 cmd.setBinding(8, wview.sceneGlobals().vsmDbg);
925 cmd.setPushData(&settings.vsmMipBias, sizeof(settings.vsmMipBias));
926 cmd.setPipeline(shaders.vsmDbg);
927 cmd.draw(nullptr, 0, 3);
928 }
929
930void Renderer::drawSwrDbg(Tempest::Encoder<Tempest::CommandBuffer>& cmd, const WorldView& wview) {
931 static bool enable = true;
932 if(!enable || !settings.swrEnabled)
933 return;
934
935 cmd.setFramebuffer({{sceneLinear, Tempest::Preserve, Tempest::Preserve}});
936 cmd.setDebugMarker("SWR-dbg");
937 cmd.setBinding(0, swr.outputImage);
938 cmd.setBinding(1, wview.sceneGlobals().uboGlobal[SceneGlobals::V_Main]);
939 cmd.setBinding(2, gbufDiffuse, Sampler::nearest());
940 cmd.setBinding(3, gbufNormal, Sampler::nearest());
941 cmd.setBinding(4, zbuffer, Sampler::nearest());
942 cmd.setPipeline(shaders.swRenderingDbg);
943 cmd.draw(nullptr, 0, 3);
944 }
945
946void Renderer::drawRtsmDbg(Tempest::Encoder<Tempest::CommandBuffer>& cmd, const WorldView& wview) {
947 static bool enable = false;
948 if(!enable || !settings.rtsmEnabled)
949 return;
950
951 cmd.setFramebuffer({{sceneLinear, Tempest::Preserve, Tempest::Preserve}});
952 cmd.setDebugMarker("RTSM-dbg");
953#if 1
954 cmd.setBinding(0, rtsm.dbg32);
955#else
956 cmd.setBinding(0, rtsm.primBins);
957 cmd.setBinding(1, rtsm.posList);
958 cmd.setBinding(2, rtsm.pages);
959#endif
960 cmd.setPipeline(shaders.rtsmDbg);
961 cmd.draw(nullptr, 0, 3);
962 }
963
964void Renderer::resetGiData() {
965 if(!settings.giEnabled)
966 return;
967 if(!gi.hashTable.isEmpty())
968 return;
969
970 auto& device = Resources::device();
971 const uint32_t maxProbes = gi.maxProbes;
972
973 gi.hashTable = device.ssbo(nullptr, 2'097'152*sizeof(uint32_t)); // 8MB
974 gi.voteTable = device.ssbo(nullptr, gi.hashTable.byteSize());
975 gi.probes = device.ssbo(nullptr, maxProbes*32 + 64); // probes and header
976 gi.freeList = device.ssbo(nullptr, maxProbes*sizeof(uint32_t) + sizeof(int32_t));
977 gi.probesGBuffDiff = device.image2d(TextureFormat::RGBA8, gi.atlasDim*16, gi.atlasDim*16); // 16x16 tile
978 gi.probesGBuffNorm = device.image2d(TextureFormat::RGBA8, gi.atlasDim*16, gi.atlasDim*16);
979 gi.probesGBuffRayT = device.image2d(TextureFormat::R16, gi.atlasDim*16, gi.atlasDim*16);
980 gi.probesLighting = device.image2d(TextureFormat::R11G11B10UF, gi.atlasDim*3, gi.atlasDim*2);
981 gi.probesLightingPrev = device.image2d(TextureFormat::R11G11B10UF, uint32_t(gi.probesLighting.w()), uint32_t(gi.probesLighting.h()));
982 gi.fisrtFrame = true;
983 }
984
985void Renderer::drawHiZ(Encoder<CommandBuffer>& cmd, WorldView& view) {
986 cmd.setDebugMarker("HiZ-occluders");
987 cmd.setFramebuffer({}, {zbuffer, 1.f, Tempest::Preserve});
988 view.drawHiZ(cmd);
989 }
990
991void Renderer::buildHiZ(Tempest::Encoder<Tempest::CommandBuffer>& cmd) {
992 assert(hiz.hiZ.w()<=128 && hiz.hiZ.h()<=128); // shader limitation
993
994 cmd.setDebugMarker("HiZ-mip");
995 cmd.setFramebuffer({});
996 cmd.setBinding(0, zbuffer, Sampler::nearest(ClampMode::ClampToEdge));
997 cmd.setBinding(1, hiz.hiZ);
998 cmd.setPipeline(shaders.hiZPot);
999 cmd.dispatch(size_t(hiz.hiZ.w()), size_t(hiz.hiZ.h()));
1000
1001 const uint32_t maxBind = 8, mip = hiz.hiZ.mipCount();
1002 const uint32_t w = uint32_t(hiz.hiZ.w()), h = uint32_t(hiz.hiZ.h());
1003 if(hiz.atomicImg) {
1004 cmd.setBinding(0, hiz.counter, Sampler::nearest(), 0);
1005 } else {
1006 cmd.setBinding(0, hiz.counterBuf);
1007 }
1008 for(uint32_t i=0; i<maxBind; ++i)
1009 cmd.setBinding(1+i, hiz.hiZ, Sampler::nearest(), std::min(i, mip-1));
1010 cmd.setPushData(&mip, sizeof(mip));
1011 cmd.setPipeline(shaders.hiZMip);
1012 cmd.dispatchThreads(w,h);
1013 }
1014
1015void Renderer::drawVsm(Tempest::Encoder<Tempest::CommandBuffer>& cmd, WorldView& wview) {
1016 if(!settings.vsmEnabled)
1017 return;
1018
1019 static bool omniLights = true;
1020 const bool directLight = !settings.rtsmEnabled;
1021 const bool doVirtualFog = directLight && sky.quality!=VolumetricLQ && sky.quality!=PathTrace;
1022
1023 auto& scene = wview.sceneGlobals();
1024 auto& sceneUbo = scene.uboGlobal[SceneGlobals::V_Main];
1025 auto& lightsSsbo = wview.lights().lightsSsbo();
1026
1027 auto& vsmDbg = usesImage2d(vsm.vsmDbg, TextureFormat::R32U, zbuffer.size());
1028 auto& pageTbl = usesImage3d(vsm.pageTbl, TextureFormat::R32U, 32, 32, 16);
1029 auto& pageHiZ = usesImage3d(vsm.pageHiZ, TextureFormat::R32U, 32, 32, 16);
1030 auto& pageData = usesZBuffer(vsm.pageData, shadowFormat, 8192, 8192);
1031
1032 auto pageCount = uint32_t(vsm.pageData.w()/VSM_PAGE_SIZE) * uint32_t(vsm.pageData.h()/VSM_PAGE_SIZE);
1033 auto& pageList = usesSsbo(vsm.pageList, shaders.vsmClear.sizeofBuffer(0, pageCount));
1034 auto& pageListTmp = usesSsbo(vsm.pageListTmp, shaders.vsmAllocPages.sizeofBuffer(3, pageCount));
1035
1036 const uint32_t lightsTotal = omniLights ? uint32_t(wview.lights().size()) : 0;
1037 const size_t numOmniPages = lightsTotal*6;
1038 auto& pageTblOmni = usesSsbo(vsm.pageTblOmni, shaders.vsmClearOmni.sizeofBuffer(0, numOmniPages));
1039 auto& visibleLights = usesSsbo(vsm.visibleLights, shaders.vsmClearOmni.sizeofBuffer(1, lightsTotal ));
1040
1042
1043 cmd.setFramebuffer({});
1044 cmd.setDebugMarker("VSM-pages");
1045 cmd.setBinding(0, pageList);
1046 cmd.setBinding(1, pageTbl);
1047 cmd.setBinding(2, pageHiZ);
1048 cmd.setPipeline(shaders.vsmClear);
1049 cmd.dispatchThreads(size_t(pageTbl.w()), size_t(pageTbl.h()), size_t(pageTbl.d()));
1050
1051 if(omniLights) {
1052 cmd.setBinding(0, pageTblOmni);
1053 cmd.setBinding(1, visibleLights);
1054 cmd.setPipeline(shaders.vsmClearOmni);
1055 cmd.dispatchThreads(numOmniPages);
1056
1057 struct Push { float znear; uint32_t lightsTotal; } push = {};
1058 push.znear = scene.znear;
1059 push.lightsTotal = lightsTotal;
1060 cmd.setBinding(0, sceneUbo);
1061 cmd.setBinding(1, lightsSsbo);
1062 cmd.setBinding(2, visibleLights);
1063 cmd.setBinding(3, *scene.hiZ);
1064 cmd.setPushData(push);
1065 cmd.setPipeline(shaders.vsmCullLights);
1066 cmd.dispatchThreads(wview.lights().size());
1067 }
1068
1069 if(directLight) {
1070 cmd.setBinding(0, sceneUbo);
1071 cmd.setBinding(1, gbufDiffuse, Sampler::nearest());
1072 cmd.setBinding(2, gbufNormal, Sampler::nearest());
1073 cmd.setBinding(3, zbuffer, Sampler::nearest());
1074 cmd.setBinding(4, pageTbl);
1075 cmd.setBinding(5, pageHiZ);
1076 cmd.setPushData(settings.vsmMipBias);
1077 cmd.setPipeline(shaders.vsmMarkPages);
1078 cmd.dispatchThreads(zbuffer.size());
1079 }
1080
1081 if(omniLights) {
1082 struct Push { Vec3 originLwc; float znear; float vsmMipBias; } push = {};
1083 push.originLwc = scene.originLwc;
1084 push.znear = scene.znear;
1085 push.vsmMipBias = settings.vsmMipBias;
1086 cmd.setBinding(0, sceneUbo);
1087 cmd.setBinding(1, gbufDiffuse, Sampler::nearest());
1088 cmd.setBinding(2, gbufNormal, Sampler::nearest());
1089 cmd.setBinding(3, zbuffer, Sampler::nearest());
1090 cmd.setBinding(4, lightsSsbo);
1091 cmd.setBinding(5, visibleLights);
1092 cmd.setBinding(6, pageTblOmni);
1093 cmd.setBinding(7, vsmDbg);
1094 cmd.setPushData(&push, sizeof(push));
1095 cmd.setPipeline(shaders.vsmMarkOmniPages);
1096 cmd.dispatchThreads(zbuffer.size());
1097
1098 cmd.setBinding(0, pageTblOmni);
1099 cmd.setPushData(&lightsTotal, sizeof(lightsTotal));
1100 cmd.setPipeline(shaders.vsmPostprocessOmni);
1101 cmd.dispatchThreads(wview.lights().size());
1102 }
1103
1104 // sky&fog
1105 if(doVirtualFog) {
1106 cmd.setDebugMarker("VSM-pages-epipolar");
1107 cmd.setBinding(0, epipolar.epTrace);
1108 cmd.setBinding(1, sceneUbo);
1109 cmd.setBinding(2, epipolar.epipoles);
1110 cmd.setBinding(3, pageTbl);
1111 cmd.setBinding(4, pageHiZ);
1112 cmd.setPipeline(shaders.vsmFogPages);
1113 cmd.dispatchThreads(epipolar.epTrace.size());
1114 }
1115
1116 cmd.setDebugMarker("VSM-pages-alloc");
1117 if(true) {
1118 // clump
1119 cmd.setBinding(0, pageList);
1120 cmd.setBinding(1, pageTbl);
1121 cmd.setPipeline(shaders.vsmClumpPages);
1122 cmd.dispatchThreads(size_t(pageTbl.w()), size_t(pageTbl.h()), size_t(pageTbl.d()));
1123 }
1124
1125 cmd.setBinding(0, pageList);
1126 cmd.setBinding(1, pageTbl);
1127 cmd.setBinding(2, pageTblOmni);
1128 cmd.setBinding(3, pageListTmp);
1129 cmd.setBinding(4, scene.vsmDbg);
1130 // list
1131 cmd.setPipeline(shaders.vsmListPages);
1132 if(omniLights)
1133 cmd.dispatch(size_t(pageTbl.d() + 1)); else
1134 cmd.dispatch(size_t(pageTbl.d()));
1135
1136 cmd.setPipeline(shaders.vsmAllocPages);
1137 cmd.dispatch(1);
1138
1139 // hor-merge
1140 cmd.setPipeline(shaders.vsmMergePages);
1141 cmd.dispatch(1);
1142
1143 cmd.setDebugMarker("VSM-visibility");
1144 wview.visibilityVsm(cmd);
1145
1146 cmd.setDebugMarker("VSM-rendering");
1147 cmd.setFramebuffer({}, {pageData, 0.f, Tempest::Preserve});
1148 wview.drawVsm(cmd);
1149 }
1150
1151void Renderer::drawRtsm(Tempest::Encoder<Tempest::CommandBuffer>& cmd, WorldView& wview) {
1152 if(!settings.rtsmEnabled)
1153 return;
1154
1155 const int RTSM_BIN_SIZE = 32;
1156 const int RTSM_SMALL_TILE = 32;
1157 const int RTSM_LARGE_TILE = 128;
1158
1159 const auto& shaders = Shaders::inst();
1160 const auto& scene = wview.sceneGlobals();
1161 const auto& clusters = wview.clusters();
1162 const auto& drawCmd = wview.drawCommands();
1163 const auto& buckets = wview.drawBuckets();
1164 const auto& instanceSsbo = wview.instanceSsbo();
1165 const auto& sceneUbo = scene.uboGlobal[SceneGlobals::V_Vsm];
1166
1167 const auto largeTiles = tileCount(scene.zbuffer->size(), RTSM_LARGE_TILE);
1168 const auto smallTiles = tileCount(scene.zbuffer->size(), RTSM_SMALL_TILE);
1169 const auto binTiles = tileCount(scene.zbuffer->size(), RTSM_BIN_SIZE);
1170 const auto maxMeshlets = drawCmd.maxMeshlets();
1171
1172 // alloc resources
1173 auto& posList = usesScratch(rtsm.posList, 64*1024*1024); // arbitrary
1174 auto& outputImage = usesImage2d(rtsm.outputImage, TextureFormat::R8, zbuffer.size());
1175 auto& pages = usesImage3d(rtsm.pages, TextureFormat::R32U, 32, 32, 16);
1176 auto& meshTiles = usesImage2d(rtsm.meshTiles, TextureFormat::RG32U, smallTiles);
1177 auto& primTiles = usesImage2d(rtsm.primTiles, TextureFormat::RG32U, binTiles);
1178 auto& visList = usesSsbo (rtsm.visList, shaders.rtsmClear.sizeofBuffer(1, maxMeshlets));
1179
1180 auto& dbg32 = usesImage2d(rtsm.dbg32, TextureFormat::R32U, tileCount(zbuffer.size(), 32));
1181 auto& dbg16 = usesImage2d(rtsm.dbg16, TextureFormat::R32U, tileCount(zbuffer.size(), 16));
1182
1183 cmd.setDebugMarker("RTSM-rendering");
1184 cmd.setFramebuffer({});
1185
1186 // clear
1187 {
1188 cmd.setBinding(0, pages);
1189 cmd.setBinding(1, visList);
1190 cmd.setBinding(2, posList);
1191
1192 cmd.setPipeline(shaders.rtsmClear);
1193 cmd.dispatchThreads(size_t(pages.w()), size_t(pages.h()), size_t(pages.d()));
1194 }
1195
1196 // global cull
1197 {
1198 struct Push { uint32_t meshletCount; } push = {};
1199 push.meshletCount = uint32_t(clusters.size());
1200 cmd.setPushData(push);
1201
1202 if(sky.quality==VolumetricHQ) {
1203 cmd.setBinding(0, epipolar.epTrace);
1204 cmd.setBinding(1, sceneUbo);
1205 cmd.setBinding(2, epipolar.epipoles);
1206 cmd.setBinding(3, pages);
1207 cmd.setPipeline(shaders.rtsmFogPages);
1208 cmd.dispatchThreads(epipolar.epTrace.size());
1209 }
1210
1211 cmd.setBinding(0, outputImage);
1212 cmd.setBinding(1, sceneUbo);
1213 cmd.setBinding(2, gbufDiffuse);
1214 cmd.setBinding(3, gbufNormal);
1215 cmd.setBinding(4, zbuffer);
1216 cmd.setBinding(5, clusters.ssbo());
1217 cmd.setBinding(6, visList);
1218 cmd.setBinding(7, pages);
1219
1220 cmd.setPipeline(shaders.rtsmPages);
1221 cmd.dispatchThreads(scene.zbuffer->size());
1222
1223 cmd.setBinding(0, pages);
1224 cmd.setPipeline(shaders.rtsmHiZ);
1225 cmd.dispatch(1);
1226
1227 cmd.setBinding(7, posList);
1228 cmd.setPipeline(shaders.rtsmCulling);
1229 cmd.dispatchThreads(push.meshletCount);
1230 }
1231
1232 // position
1233 {
1234 struct Push { Vec3 originLwc; } push = {};
1235 push.originLwc = scene.originLwc;
1236
1237 cmd.setPushData(push);
1238 cmd.setBinding(0, posList);
1239 cmd.setBinding(1, sceneUbo);
1240 cmd.setBinding(2, visList);
1241
1242 cmd.setBinding(5, clusters.ssbo());
1243 cmd.setBinding(6, instanceSsbo);
1244 cmd.setBinding(7, buckets.ssbo());
1245 cmd.setBinding(8, buckets.ibo());
1246 cmd.setBinding(9, buckets.vbo());
1247 cmd.setBinding(10, buckets.morphId());
1248 cmd.setBinding(11, buckets.morph());
1249
1250 cmd.setPipeline(shaders.rtsmPosition);
1251 cmd.dispatchIndirect(visList,0);
1252 }
1253
1254 // binning
1255 {
1256 cmd.setBinding(0, outputImage);
1257 cmd.setBinding(1, sceneUbo);
1258 cmd.setBinding(2, gbufNormal);
1259 cmd.setBinding(3, zbuffer);
1260 cmd.setBinding(4, posList);
1261 cmd.setBinding(5, meshTiles);
1262 cmd.setBinding(6, primTiles);
1263 cmd.setBinding(9, dbg32);
1264
1265 // meshlets
1266 cmd.setPipeline(shaders.rtsmMeshletCull);
1267 cmd.dispatch(largeTiles);
1268
1269 // primitives
1270 cmd.setPipeline(shaders.rtsmPrimCull);
1271 cmd.dispatch(smallTiles);
1272 }
1273
1274 // raster
1275 {
1276 cmd.setBinding(0, outputImage);
1277 cmd.setBinding(1, sceneUbo);
1278 cmd.setBinding(2, gbufNormal);
1279 cmd.setBinding(3, zbuffer);
1280 cmd.setBinding(4, posList);
1281 cmd.setBinding(5, meshTiles);
1282 cmd.setBinding(6, primTiles);
1283 cmd.setBinding(7, buckets.textures());
1284 cmd.setBinding(8, Sampler::trillinear());
1285 cmd.setBinding(9, dbg16);
1286
1287 cmd.setPipeline(shaders.rtsmRaster);
1288 cmd.dispatchThreads(outputImage.size());
1289 }
1290 }
1291
1292void Renderer::drawRtsmOmni(Tempest::Encoder<Tempest::CommandBuffer>& cmd, WorldView& wview) {
1293 if(!settings.rtsmEnabled)
1294 return;
1295
1296 static bool omniLights = true;
1297 if(!omniLights)
1298 return;
1299
1300 //const uint32_t RTSM_SMALL_TILE = 32;
1301 const uint32_t RTSM_LIGHT_TILE = 64;
1302
1303 const auto& shaders = Shaders::inst();
1304 const auto& scene = wview.sceneGlobals();
1305 const auto& sceneUbo = scene.uboGlobal[SceneGlobals::V_Main];
1306 const auto& clusters = wview.clusters();
1307 const auto& drawCmd = wview.drawCommands();
1308 const auto& buckets = wview.drawBuckets();
1309 const auto& instanceSsbo = wview.instanceSsbo();
1310 const auto& lightsSsbo = wview.lights().lightsSsbo();
1311 const auto maxMeshlets = drawCmd.maxMeshlets();
1312 const auto lightsTotal = uint32_t(wview.lights().size());
1313
1314 // alloc resources, for omni-lights
1315 auto& posList = usesScratch(rtsm.posList, 64*1024*1024); // arbitrary
1316 auto& outputImageClr = usesImage2d(rtsm.outputImageClr, TextureFormat::R11G11B10UF, zbuffer.size());
1317 auto& lightTiles = usesImage2d(rtsm.lightTiles, TextureFormat::RG32U, tileCount(scene.zbuffer->size(), RTSM_LIGHT_TILE));
1318 auto& lightBins = usesImage2d(rtsm.lightBins, TextureFormat::RG32U, lightsTotal, 1u);
1319 auto& primTilesOmni = usesImage2d(rtsm.primTilesOmni, TextureFormat::R32U, tileCount(zbuffer.size(), RTSM_LIGHT_TILE));
1320 auto& drawTasks = usesSsbo (rtsm.drawTasks, 4*sizeof(uint32_t));
1321 auto& visList = usesSsbo (rtsm.visList, shaders.rtsmClearOmni.sizeofBuffer(1, maxMeshlets));
1322 auto& visibleLights = usesSsbo (rtsm.visibleLights, shaders.rtsmClearOmni.sizeofBuffer(2, lightsTotal));
1323
1324 auto& dbg64 = usesImage2d(rtsm.dbg64, TextureFormat::R32U, tileCount(zbuffer.size(), 64));
1325 auto& dbg16 = usesImage2d(rtsm.dbg16, TextureFormat::R32U, tileCount(zbuffer.size(), 16));
1326
1327 cmd.setDebugMarker("RTSM-rendering-omni");
1328 cmd.setFramebuffer({});
1329 // clear
1330 {
1331 struct Push { uint32_t meshletCount; } push = {};
1332 push.meshletCount = uint32_t(clusters.size());
1333
1334 cmd.setPushData(push);
1335 cmd.setBinding(0, posList);
1336 cmd.setBinding(1, visList);
1337 cmd.setBinding(2, visibleLights);
1338 cmd.setPipeline(shaders.rtsmClearOmni);
1339 cmd.dispatchThreads(1);
1340 }
1341
1342 // cull lights
1343 {
1344 struct Push { float znear; uint32_t lightsTotal; } push = {};
1345 push.znear = scene.znear;
1346 push.lightsTotal = lightsTotal;
1347
1348 cmd.setPushData(push);
1349 cmd.setBinding(0, sceneUbo);
1350 cmd.setBinding(1, lightsSsbo);
1351 cmd.setBinding(2, visibleLights);
1352 cmd.setBinding(3, visList);
1353 cmd.setBinding(4, hiz.hiZ);
1354 cmd.setBinding(5, clusters.ssbo());
1355 cmd.setBinding(6, posList);
1356
1357 cmd.setPipeline(shaders.rtsmCullLights);
1358 cmd.dispatchThreads(lightsTotal);
1359 }
1360
1361 // lights
1362 {
1363 struct Push { Vec3 originLwc; float znear; } push = {};
1364 push.originLwc = scene.originLwc;
1365 push.znear = scene.znear;
1366
1367 cmd.setPushData(push);
1368 cmd.setBinding(0, lightTiles);
1369 cmd.setBinding(1, sceneUbo);
1370 cmd.setBinding(2, gbufNormal);
1371 cmd.setBinding(3, zbuffer);
1372 cmd.setBinding(4, posList);
1373 cmd.setBinding(5, lightsSsbo);
1374 cmd.setBinding(6, visibleLights);
1375 //
1376 cmd.setBinding(9, rtsm.dbg64);
1377
1378 cmd.setPipeline(shaders.rtsmLightsOmni);
1379 cmd.dispatch(lightTiles.size());
1380
1381 cmd.setPipeline(shaders.rtsmBboxesOmni);
1382 cmd.dispatchThreads(zbuffer.size());
1383
1384 cmd.setPipeline(shaders.rtsmCompactOmni);
1385 cmd.dispatch(lightTiles.size());
1386
1387 cmd.setPipeline(shaders.rtsmCompactLights);
1388 cmd.dispatchThreads(lightsTotal);
1389 }
1390
1391 // meshlet culling
1392 {
1393 struct Push { float znear; uint32_t meshletCount; } push = {};
1394 push.znear = scene.znear;
1395 push.meshletCount = uint32_t(clusters.size());
1396
1397 cmd.setPushData(push);
1398 cmd.setBinding(0, posList);
1399 cmd.setBinding(1, sceneUbo);
1400 cmd.setBinding(2, rtsm.visList);
1401 cmd.setBinding(3, lightsSsbo);
1402 cmd.setBinding(4, visibleLights);
1403 cmd.setBinding(5, clusters.ssbo());
1404
1405 cmd.setPipeline(shaders.rtsmCullingOmni);
1406 cmd.dispatchThreads(push.meshletCount);
1407 }
1408
1409 // position
1410 {
1411 struct Push { Vec3 originLwc; } push = {};
1412 push.originLwc = scene.originLwc;
1413
1414 cmd.setPushData(push);
1415 cmd.setBinding(0, posList);
1416 cmd.setBinding(1, sceneUbo);
1417 cmd.setBinding(2, visList);
1418 //
1419 cmd.setBinding(5, clusters.ssbo());
1420 cmd.setBinding(6, instanceSsbo);
1421 cmd.setBinding(7, buckets.ssbo());
1422 cmd.setBinding(8, buckets.ibo());
1423 cmd.setBinding(9, buckets.vbo());
1424 cmd.setBinding(10, buckets.morphId());
1425 cmd.setBinding(11, buckets.morph());
1426
1427 cmd.setPipeline(shaders.rtsmPositionOmni);
1428 cmd.dispatchIndirect(visList, 0);
1429 }
1430
1431 // per-light meshlets, primitives
1432 {
1433 struct Push { Vec3 originLwc; float znear; } push = {};
1434 push.originLwc = scene.originLwc;
1435 push.znear = scene.znear;
1436
1437 cmd.setBinding(0, sceneUbo);
1438 cmd.setBinding(1, lightsSsbo);
1439 cmd.setBinding(2, visibleLights);
1440 cmd.setBinding(3, lightBins);
1441 cmd.setBinding(4, clusters.ssbo());
1442 cmd.setBinding(5, posList);
1443
1444 cmd.setPipeline(shaders.rtsmMeshletOmni);
1445 cmd.dispatchIndirect(visibleLights, 0);
1446
1447 cmd.setPipeline(shaders.rtsmBackfaceOmni);
1448 cmd.dispatchIndirect(visibleLights, 0);
1449 }
1450
1451 // in tile primitives
1452 {
1453 struct Push { Vec3 originLwc; float znear; } push = {};
1454 push.originLwc = scene.originLwc;
1455 push.znear = scene.znear;
1456 cmd.setPushData(push);
1457 cmd.setBinding(0, lightTiles);
1458 cmd.setBinding(1, sceneUbo);
1459 cmd.setBinding(2, gbufNormal);
1460 cmd.setBinding(3, zbuffer);
1461 cmd.setBinding(4, posList);
1462 cmd.setBinding(5, lightsSsbo);
1463 cmd.setBinding(6, lightBins);
1464 cmd.setBinding(7, primTilesOmni);
1465 cmd.setBinding(8, drawTasks);
1466 cmd.setBinding(9, dbg64);
1467
1468 cmd.setPipeline(shaders.rtsmTaskOmni);
1469 cmd.dispatch(1);
1470
1471 cmd.setPipeline(shaders.rtsmPrimOmni);
1472 cmd.dispatchIndirect(drawTasks, 0);
1473 }
1474
1475 // raster
1476 {
1477 struct Push { Vec3 originLwc; } push = {};
1478 push.originLwc = scene.originLwc;
1479
1480 cmd.setPushData(push);
1481 cmd.setBinding(0, outputImageClr);
1482 cmd.setBinding(1, sceneUbo);
1483 cmd.setBinding(2, gbufNormal);
1484 cmd.setBinding(3, zbuffer);
1485 cmd.setBinding(4, posList);
1486 cmd.setBinding(5, lightsSsbo);
1487 cmd.setBinding(6, primTilesOmni);
1488 cmd.setBinding(7, buckets.textures());
1489 cmd.setBinding(8, Sampler::trillinear());
1490 cmd.setBinding(9, dbg16);
1491
1492 cmd.setPipeline(shaders.rtsmRasterOmni);
1493 cmd.dispatchThreads(outputImageClr.size());
1494 }
1495
1496 //TODO: swrt ?
1497 if(0) {
1498 // raster (ref)
1499 struct Push { Vec3 originLwc; } push = {};
1500 push.originLwc = scene.originLwc;
1501 cmd.setPushData(push);
1502 cmd.setBinding(0, outputImageClr);
1503 cmd.setBinding(1, sceneUbo);
1504 cmd.setBinding(2, gbufNormal);
1505 cmd.setBinding(3, zbuffer);
1506 cmd.setBinding(4, posList);
1507 cmd.setBinding(5, lightsSsbo);
1508 cmd.setBinding(6, visibleLights);
1509 cmd.setBinding(7, lightBins);
1510 cmd.setBinding(9, dbg16);
1511
1512 cmd.setPipeline(shaders.rtsmRenderingOmni);
1513 cmd.dispatchThreads(outputImageClr.size());
1514 }
1515 }
1516
1517void Renderer::drawSwr(Tempest::Encoder<Tempest::CommandBuffer>& cmd, WorldView& wview) {
1518 if(!settings.swrEnabled)
1519 return;
1520
1521 const auto& scene = wview.sceneGlobals();
1522 const auto& clusters = wview.clusters();
1523 const auto& buckets = wview.drawBuckets();
1524 const auto& instanceSsbo = wview.instanceSsbo();
1525
1526 auto& outputImage = usesImage2d(swr.outputImage, TextureFormat::R32U, zbuffer.size());
1527
1528 cmd.setFramebuffer({});
1529 cmd.setDebugMarker("SW-rendering");
1530
1531 struct Push { uint32_t firstMeshlet; uint32_t meshletCount; float znear; } push = {};
1532 push.firstMeshlet = 0;
1533 push.meshletCount = uint32_t(clusters.size());
1534 push.znear = scene.znear;
1535
1536 cmd.setBinding(0, outputImage);
1537 cmd.setBinding(1, scene.uboGlobal[SceneGlobals::V_Main]);
1538 cmd.setBinding(2, *scene.gbufNormals);
1539 cmd.setBinding(3, *scene.zbuffer);
1540 cmd.setBinding(4, clusters.ssbo());
1541 cmd.setBinding(5, buckets.ibo());
1542 cmd.setBinding(6, buckets.vbo());
1543 cmd.setBinding(7, buckets.textures());
1544 cmd.setBinding(8, Sampler::bilinear());
1545
1546 auto* pso = &Shaders::inst().swRendering;
1547 switch(Gothic::options().swRenderingPreset) {
1548 case 1: {
1549 cmd.setPushData(&push, sizeof(push));
1550 cmd.setPipeline(*pso);
1551 //cmd.dispatch(10);
1552 cmd.dispatch(clusters.size());
1553 break;
1554 }
1555 case 2: {
1556 IVec2 tileSize = IVec2(128);
1557 int tileX = (outputImage.w()+tileSize.x-1)/tileSize.x;
1558 int tileY = (outputImage.h()+tileSize.y-1)/tileSize.y;
1559 cmd.setPushData(&push, sizeof(push));
1560 cmd.setPipeline(*pso);
1561 cmd.dispatch(size_t(tileX), size_t(tileY)); //outputImage.size());
1562 break;
1563 }
1564 case 3: {
1565 cmd.setBinding(9, *scene.lights);
1566 cmd.setBinding(10, instanceSsbo);
1567 cmd.setPushData(&push, sizeof(push));
1568 cmd.setPipeline(*pso);
1569 cmd.dispatchThreads(outputImage.size());
1570 break;
1571 }
1572 }
1573 }
1574
1575void Renderer::drawGBuffer(Encoder<CommandBuffer>& cmd, uint8_t fId, WorldView& view) {
1576 cmd.setDebugMarker("GBuffer");
1577 cmd.setFramebuffer({{gbufDiffuse, Tempest::Vec4(), Tempest::Preserve},
1578 {gbufNormal, Tempest::Vec4(), Tempest::Preserve}},
1579 {zbuffer, Tempest::Preserve, Tempest::Preserve});
1580 view.drawGBuffer(cmd,fId);
1581 }
1582
1583void Renderer::drawGWater(Encoder<CommandBuffer>& cmd, WorldView& view) {
1584 static bool water = true;
1585 if(!water)
1586 return;
1587
1588 cmd.setFramebuffer({{sceneLinear, Tempest::Preserve, Tempest::Preserve},
1589 {gbufDiffuse, Vec4(0,0,0,0), Tempest::Preserve},
1590 {gbufNormal, Vec4(0,0,0,0), Tempest::Preserve}},
1591 {zbuffer, Tempest::Preserve, Tempest::Preserve});
1592 // cmd.setFramebuffer({{sceneLinear, Tempest::Preserve, Tempest::Preserve}},
1593 // {zbuffer, Tempest::Preserve, Tempest::Preserve});
1594 cmd.setDebugMarker("GWater");
1595 view.drawWater(cmd);
1596 }
1597
1598void Renderer::drawReflections(Encoder<CommandBuffer>& cmd, const WorldView& wview) {
1599 auto& pso = settings.zEnvMappingEnabled ? shaders.waterReflectionSSR : shaders.waterReflection;
1600
1601 cmd.setDebugMarker("Reflections");
1602 cmd.setBinding(0, wview.sceneGlobals().uboGlobal[SceneGlobals::V_Main]);
1603 cmd.setBinding(1, sceneOpaque, Sampler::bilinear(ClampMode::ClampToEdge));
1604 cmd.setBinding(2, gbufDiffuse, Sampler::nearest (ClampMode::ClampToEdge));
1605 cmd.setBinding(3, gbufNormal, Sampler::nearest (ClampMode::ClampToEdge));
1606 cmd.setBinding(4, zbuffer, Sampler::nearest (ClampMode::ClampToEdge));
1607 cmd.setBinding(5, sceneDepth, Sampler::nearest (ClampMode::ClampToEdge));
1608 cmd.setBinding(6, sky.viewCldLut);
1609 cmd.setPipeline(pso);
1610 if(Gothic::options().doMeshShading) {
1611 cmd.dispatchMeshThreads(gbufDiffuse.size());
1612 } else {
1613 cmd.draw(nullptr, 0, 3);
1614 }
1615 }
1616
1617void Renderer::drawUnderwater(Encoder<CommandBuffer>& cmd, const WorldView& wview) {
1618 cmd.setBinding(0, wview.sceneGlobals().uboGlobal[SceneGlobals::V_Main]);
1619 cmd.setBinding(1, zbuffer);
1620
1621 cmd.setPipeline(shaders.underwaterT);
1622 cmd.draw(nullptr, 0, 3);
1623 cmd.setPipeline(shaders.underwaterS);
1624 cmd.draw(nullptr, 0, 3);
1625 }
1626
1627void Renderer::drawShadowMap(Encoder<CommandBuffer>& cmd, uint8_t fId, WorldView& view) {
1628 for(uint8_t i=0; i<Resources::ShadowLayers; ++i) {
1629 if(shadowMap[i].isEmpty())
1630 continue;
1631 cmd.setDebugMarker(string_frm("ShadowMap #",i));
1632 cmd.setFramebuffer({}, {shadowMap[i], 0.f, Tempest::Preserve});
1633 if(view.mainLight().dir().y > Camera::minShadowY)
1634 view.drawShadow(cmd,fId,i);
1635 }
1636 }
1637
1638void Renderer::drawShadowResolve(Encoder<CommandBuffer>& cmd, const WorldView& wview) {
1639 static bool light = true;
1640 if(!light)
1641 return;
1642
1643 auto& scene = wview.sceneGlobals();
1644 cmd.setDebugMarker(settings.vsmEnabled ? "DirectSunLight-VSM" : "DirectSunLight");
1645
1646 auto originLwc = scene.originLwc;
1647 cmd.setPushData(&originLwc, sizeof(originLwc));
1648 cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]);
1649 cmd.setBinding(1, gbufDiffuse, Sampler::nearest());
1650 cmd.setBinding(2, gbufNormal, Sampler::nearest());
1651 cmd.setBinding(3, zbuffer, Sampler::nearest());
1652 if(shadow.directLightPso==&shaders.vsmDirectLight) {
1653 cmd.setBinding(4, vsm.pageTbl);
1654 cmd.setBinding(5, vsm.pageList);
1655 cmd.setBinding(6, vsm.pageData);
1656 cmd.setBinding(8, scene.vsmDbg);
1657 }
1658 else if(shadow.directLightPso==&shaders.directLightRq) {
1659 for(size_t r=0; r<Resources::ShadowLayers; ++r) {
1660 if(shadowMap[r].isEmpty())
1661 continue;
1662 cmd.setBinding(4+r, shadowMap[r], Resources::shadowSampler());
1663 }
1664 cmd.setBinding(6, scene.rtScene.tlas);
1665 cmd.setBinding(7, Sampler::bilinear());
1666 cmd.setBinding(8, scene.rtScene.tex);
1667 cmd.setBinding(9, scene.rtScene.vbo);
1668 cmd.setBinding(10,scene.rtScene.ibo);
1669 cmd.setBinding(11,scene.rtScene.rtDesc);
1670 }
1671 else if(shadow.directLightPso==&shaders.rtsmDirectLight) {
1672 cmd.setBinding(4, rtsm.outputImage);
1673 cmd.setBinding(5, rtsm.outputImageClr.isEmpty() ? Resources::fallbackBlack() : textureCast<Texture2d&>(rtsm.outputImageClr));
1674 }
1675 else {
1676 for(size_t r=0; r<Resources::ShadowLayers; ++r) {
1677 if(shadowMap[r].isEmpty())
1678 continue;
1679 cmd.setBinding(4+r, shadowMap[r], Resources::shadowSampler());
1680 }
1681 }
1682
1683 cmd.setPipeline(*shadow.directLightPso);
1684 if(settings.vsmEnabled) {
1685 cmd.setPushData(settings.vsmMipBias);
1686 cmd.setPipeline(*shadow.directLightPso);
1687 }
1688 cmd.draw(nullptr, 0, 3);
1689 }
1690
1691void Renderer::drawLights(Encoder<CommandBuffer>& cmd, const WorldView& wview) {
1692 static bool light = true;
1693 if(!light)
1694 return;
1695
1696 if(settings.rtsmEnabled && !rtsm.outputImageClr.isEmpty())
1697 return;
1698
1699 auto& scene = wview.sceneGlobals();
1700 cmd.setDebugMarker("Point lights");
1701
1702 cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]);
1703 cmd.setBinding(1, gbufDiffuse, Sampler::nearest());
1704 cmd.setBinding(2, gbufNormal, Sampler::nearest());
1705 cmd.setBinding(3, zbuffer, Sampler::nearest());
1706 cmd.setBinding(4, wview.lights().lightsSsbo());
1707 if(lights.directLightPso==&shaders.lightsVsm) {
1708 cmd.setBinding(5, vsm.pageTblOmni);
1709 cmd.setBinding(6, vsm.pageData);
1710 }
1711 if(lights.directLightPso==&shaders.lightsRq) {
1712 cmd.setBinding(6, scene.rtScene.tlas);
1713 cmd.setBinding(7, Sampler::bilinear());
1714 cmd.setBinding(8, scene.rtScene.tex);
1715 cmd.setBinding(9, scene.rtScene.vbo);
1716 cmd.setBinding(10,scene.rtScene.ibo);
1717 cmd.setBinding(11,scene.rtScene.rtDesc);
1718 }
1719
1720 auto originLwc = scene.originLwc;
1721 auto& ibo = Resources::cubeIbo();
1722 cmd.setPushData(&originLwc, sizeof(originLwc));
1723 cmd.setPipeline(*lights.directLightPso);
1724 cmd.draw(nullptr,ibo, 0,ibo.size(), 0,wview.lights().size());
1725 }
1726
1727void Renderer::drawSky(Encoder<CommandBuffer>& cmd, const WorldView& wview) {
1728 auto& scene = wview.sceneGlobals();
1729
1730 cmd.setDebugMarker("Sky");
1731 if(sky.quality==PathTrace) {
1732 cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]);
1733 cmd.setBinding(1, sky.transLut, Sampler::bilinear(ClampMode::ClampToEdge));
1734 cmd.setBinding(2, sky.multiScatLut, Sampler::bilinear(ClampMode::ClampToEdge));
1735 cmd.setBinding(3, sky.cloudsLut, Sampler::bilinear(ClampMode::ClampToEdge));
1736 cmd.setBinding(4, zbuffer, Sampler::nearest());
1737 cmd.setBinding(5, shadowMap[1], Resources::shadowSampler());
1738 cmd.setPipeline(shaders.skyPathTrace);
1739 cmd.draw(nullptr, 0, 3);
1740 return;
1741 }
1742
1743 auto& skyShader = sky.quality==VolumetricLQ ? shaders.sky : shaders.skySep;
1744 cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]);
1745 cmd.setBinding(1, sky.transLut, Sampler::bilinear(ClampMode::ClampToEdge));
1746 cmd.setBinding(2, sky.multiScatLut, Sampler::bilinear(ClampMode::ClampToEdge));
1747 cmd.setBinding(3, sky.viewLut, Sampler::bilinear(ClampMode::ClampToEdge));
1748 cmd.setBinding(4, sky.fogLut3D);
1749 if(sky.quality!=VolumetricLQ)
1750 cmd.setBinding(5, sky.fogLut3DMs, Sampler::bilinear(ClampMode::ClampToEdge));
1751 cmd.setBinding(6, *wview.sky().cloudsDay() .lay[0], Sampler::trillinear());
1752 cmd.setBinding(7, *wview.sky().cloudsDay() .lay[1], Sampler::trillinear());
1753 cmd.setBinding(8, *wview.sky().cloudsNight().lay[0], Sampler::trillinear());
1754 cmd.setBinding(9, *wview.sky().cloudsNight().lay[1], Sampler::trillinear());
1755 cmd.setPipeline(skyShader);
1756 cmd.draw(nullptr, 0, 3);
1757 }
1758
1759void Renderer::prepareSSAO(Encoder<CommandBuffer>& cmd, WorldView& wview) {
1760 if(!settings.zCloudShadowScale)
1761 return;
1762 // ssao
1763 struct PushSsao {
1764 Matrix4x4 proj;
1765 Matrix4x4 projInv;
1766 } push;
1767 push.proj = proj;
1768 push.projInv = proj;
1769 push.projInv.inverse();
1770
1771 cmd.setFramebuffer({});
1772 cmd.setDebugMarker("SSAO");
1773
1774 cmd.setBinding(0, ssao.ssaoBuf);
1775 cmd.setBinding(1, wview.sceneGlobals().uboGlobal[SceneGlobals::V_Main]);
1776 cmd.setBinding(2, gbufDiffuse, Sampler::nearest(ClampMode::ClampToEdge));
1777 cmd.setBinding(3, gbufNormal, Sampler::nearest(ClampMode::ClampToEdge));
1778 cmd.setBinding(4, zbuffer, Sampler::nearest(ClampMode::ClampToEdge));
1779 cmd.setPushData(&push, sizeof(push));
1780 cmd.setPipeline(shaders.ssao);
1781 cmd.dispatchThreads(ssao.ssaoBuf.size());
1782
1783 cmd.setBinding(0, ssao.ssaoBlur);
1784 cmd.setBinding(1, wview.sceneGlobals().uboGlobal[SceneGlobals::V_Main]);
1785 cmd.setBinding(2, ssao.ssaoBuf);
1786 cmd.setBinding(3, zbuffer, Sampler::nearest(ClampMode::ClampToEdge));
1787 cmd.setPipeline(shaders.ssaoBlur);
1788 cmd.dispatchThreads(ssao.ssaoBuf.size());
1789 }
1790
1791void Renderer::prepareFog(Encoder<Tempest::CommandBuffer>& cmd, WorldView& wview) {
1792 auto& scene = wview.sceneGlobals();
1793 auto& device = Resources::device();
1794
1795 cmd.setDebugMarker("Fog-LUTs");
1796 if(sky.quality!=PathTrace) {
1797 auto& shader = sky.quality==VolumetricLQ ? shaders.fogViewLut3d : shaders.fogViewLutSep;
1798 cmd.setFramebuffer({});
1799 cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]);
1800 cmd.setBinding(1, sky.transLut, Sampler::bilinear(ClampMode::ClampToEdge));
1801 cmd.setBinding(2, sky.multiScatLut, Sampler::bilinear(ClampMode::ClampToEdge));
1802 cmd.setBinding(3, sky.cloudsLut, Sampler::bilinear(ClampMode::ClampToEdge));
1803 cmd.setBinding(4, sky.fogLut3D);
1804 if(sky.quality==VolumetricHQ || sky.quality==Epipolar)
1805 cmd.setBinding(5, sky.fogLut3DMs, Sampler::bilinear(ClampMode::ClampToEdge));
1806 cmd.setPipeline(shader);
1807 cmd.dispatchThreads(uint32_t(sky.fogLut3D.w()), uint32_t(sky.fogLut3D.h()));
1808 }
1809
1810 if(settings.vsmEnabled && (sky.quality==VolumetricHQ || sky.quality==Epipolar)) {
1811 cmd.setFramebuffer({});
1812 cmd.setDebugMarker("VSM-epipolar-fog");
1813 cmd.setBinding(0, epipolar.epTrace);
1814 cmd.setBinding(1, wview.sceneGlobals().uboGlobal[SceneGlobals::V_Main]);
1815 cmd.setBinding(2, epipolar.epipoles);
1816 cmd.setBinding(3, vsm.pageTbl);
1817 cmd.setBinding(4, vsm.pageData);
1818 cmd.setPipeline(shaders.vsmFogShadow);
1819 cmd.dispatchThreads(epipolar.epTrace.size());
1820 }
1821
1822 switch(sky.quality) {
1823 case None:
1824 case VolumetricLQ:
1825 break;
1826 case VolumetricHQ: {
1827 if(settings.vsmEnabled && !settings.rtsmEnabled) {
1828 cmd.setFramebuffer({});
1829 cmd.setBinding(0, sky.occlusionLut);
1830 cmd.setBinding(1, epipolar.epTrace);
1831 cmd.setBinding(2, wview.sceneGlobals().uboGlobal[SceneGlobals::V_Main]);
1832 cmd.setBinding(3, epipolar.epipoles);
1833 cmd.setBinding(4, zbuffer);
1834 cmd.setPipeline(shaders.fogEpipolarOcclusion);
1835 cmd.dispatchThreads(zbuffer.size());
1836 } else {
1837 cmd.setFramebuffer({});
1838 cmd.setBinding(2, zbuffer, Sampler::nearest());
1839 cmd.setBinding(3, scene.uboGlobal[SceneGlobals::V_Main]);
1840 cmd.setBinding(4, sky.occlusionLut);
1841 cmd.setBinding(5, shadowMap[1], Resources::shadowSampler());
1842 cmd.setPipeline(shaders.fogOcclusion);
1843 cmd.dispatchThreads(sky.occlusionLut.size());
1844 }
1845 break;
1846 }
1847 case Epipolar:{
1848 // experimental
1849 if(vsm.fogDbg.isEmpty())
1850 vsm.fogDbg = device.image2d(sky.lutRGBFormat, 1024, 2*1024);
1851 cmd.setFramebuffer({});
1852 cmd.setDebugMarker("VSM-trace");
1853 cmd.setBinding(0, vsm.fogDbg);
1854 cmd.setBinding(1, epipolar.epTrace);
1855 cmd.setBinding(2, wview.sceneGlobals().uboGlobal[SceneGlobals::V_Main]);
1856 cmd.setBinding(3, epipolar.epipoles);
1857 cmd.setBinding(4, zbuffer);
1858 cmd.setBinding(5, sky.transLut, Sampler::bilinear(ClampMode::ClampToEdge));
1859 cmd.setBinding(6, sky.cloudsLut, Sampler::bilinear(ClampMode::ClampToEdge));
1860 cmd.setBinding(7, sky.fogLut3DMs, Sampler::bilinear(ClampMode::ClampToEdge));
1861 cmd.setPipeline(shaders.vsmFogTrace);
1862 cmd.dispatchThreads(epipolar.epTrace.size());
1863 break;
1864 }
1865 case PathTrace: {
1866 break;
1867 }
1868 }
1869 }
1870
1871void Renderer::prepareEpipolar(Tempest::Encoder<Tempest::CommandBuffer>& cmd, WorldView& wview) {
1872 const bool doVolumetricFog = sky.quality!=VolumetricLQ && sky.quality!=PathTrace;
1873 if(!doVolumetricFog || (!settings.vsmEnabled && !settings.rtsmEnabled))
1874 return;
1875
1876 auto& scene = wview.sceneGlobals();
1877
1878 auto& epTrace = usesImage2d(epipolar.epTrace, TextureFormat::R16, 1024, 2*1024);
1879 auto& epipoles = usesSsbo (epipolar.epipoles, shaders.fogEpipolarVsm.sizeofBuffer(3, size_t(epipolar.epTrace.h())));
1880
1881 cmd.setDebugMarker("Fog-epipolar");
1882 cmd.setFramebuffer({});
1883 cmd.setBinding(0, sky.occlusionLut);
1884 cmd.setBinding(1, epTrace);
1885 cmd.setBinding(2, scene.uboGlobal[SceneGlobals::V_Main]);
1886 cmd.setBinding(3, epipoles);
1887 cmd.setBinding(4, zbuffer);
1888 if(settings.vsmEnabled)
1889 cmd.setPipeline(shaders.fogEpipolarVsm);
1890 else if(settings.rtsmEnabled)
1891 cmd.setPipeline(shaders.fogEpipolarVsm);
1892 cmd.dispatch(uint32_t(epTrace.h()));
1893 }
1894
1895void Renderer::prepareIrradiance(Encoder<CommandBuffer>& cmd, WorldView& wview) {
1896 auto& scene = wview.sceneGlobals();
1897
1898 cmd.setDebugMarker("Irradiance");
1899 cmd.setFramebuffer({});
1900 cmd.setBinding(0, sky.irradianceLut);
1901 cmd.setBinding(1, scene.uboGlobal[SceneGlobals::V_Main]);
1902 cmd.setBinding(2, sky.viewCldLut);
1903 cmd.setPipeline(shaders.irradiance);
1904 cmd.dispatch(1);
1905 }
1906
1907void Renderer::prepareGi(Encoder<CommandBuffer>& cmd, WorldView& wview) {
1908 if(!settings.giEnabled || !settings.zCloudShadowScale) {
1909 return;
1910 }
1911
1912 const size_t maxHash = gi.hashTable.byteSize()/sizeof(uint32_t);
1913
1914 auto& scene = wview.sceneGlobals();
1915
1916 cmd.setFramebuffer({});
1917 if(gi.fisrtFrame) {
1918 cmd.setDebugMarker("GI-Init");
1919 cmd.setBinding(0, gi.voteTable);
1920 cmd.setBinding(1, gi.hashTable);
1921 cmd.setBinding(2, gi.probes);
1922 cmd.setBinding(3, gi.freeList);
1923 cmd.setPipeline(shaders.probeInit);
1924 cmd.dispatch(1);
1925 cmd.setPipeline(shaders.probeClearHash);
1926 cmd.dispatchThreads(maxHash);
1927
1928 cmd.setBinding(0, gi.probesLighting);
1929 cmd.setBinding(1, Resources::fallbackBlack());
1930 cmd.setPipeline(shaders.copyImg);
1931 cmd.dispatchThreads(gi.probesLighting.size());
1932 gi.fisrtFrame = false;
1933 }
1934
1935 static bool alloc = true;
1936 cmd.setDebugMarker("GI-Alloc");
1937 cmd.setBinding(0, gi.voteTable);
1938 cmd.setBinding(1, gi.hashTable);
1939 cmd.setBinding(2, gi.probes);
1940 cmd.setBinding(3, gi.freeList);
1941 cmd.setPipeline(shaders.probeClear);
1942 cmd.dispatchThreads(maxHash);
1943
1944 if(alloc) {
1945 cmd.setBinding(0, wview.sceneGlobals().uboGlobal[SceneGlobals::V_Main]);
1946 cmd.setBinding(1, gbufDiffuse, Sampler::nearest());
1947 cmd.setBinding(2, gbufNormal, Sampler::nearest());
1948 cmd.setBinding(3, zbuffer, Sampler::nearest());
1949 cmd.setBinding(4, gi.voteTable);
1950 cmd.setBinding(5, gi.hashTable);
1951 cmd.setBinding(6, gi.probes);
1952 cmd.setBinding(7, gi.freeList);
1953 cmd.setPipeline(shaders.probeVote);
1954 cmd.dispatchThreads(sceneDepth.size());
1955
1956 cmd.setBinding(0, gi.voteTable);
1957 cmd.setBinding(1, gi.hashTable);
1958 cmd.setBinding(2, gi.probes);
1959 cmd.setBinding(3, gi.freeList);
1960 cmd.setPipeline(shaders.probePrune);
1961 cmd.dispatchThreads(gi.maxProbes);
1962
1963 cmd.setBinding(0, wview.sceneGlobals().uboGlobal[SceneGlobals::V_Main]);
1964 cmd.setBinding(1, gbufDiffuse, Sampler::nearest());
1965 cmd.setBinding(2, gbufNormal, Sampler::nearest());
1966 cmd.setBinding(3, zbuffer, Sampler::nearest());
1967 cmd.setBinding(4, gi.voteTable);
1968 cmd.setBinding(5, gi.hashTable);
1969 cmd.setBinding(6, gi.probes);
1970 cmd.setBinding(7, gi.freeList);
1971 cmd.setPipeline(shaders.probeAlocation);
1972 cmd.dispatchThreads(sceneDepth.size());
1973 }
1974
1975 cmd.setDebugMarker("GI-Trace");
1976 cmd.setBinding(0, wview.sceneGlobals().uboGlobal[SceneGlobals::V_Main]);
1977 cmd.setBinding(1, gi.probesGBuffDiff);
1978 cmd.setBinding(2, gi.probesGBuffNorm);
1979 cmd.setBinding(3, gi.probesGBuffRayT);
1980 cmd.setBinding(4, gi.hashTable);
1981 cmd.setBinding(5, gi.probes);
1982 cmd.setBinding(6, scene.rtScene.tlas);
1983 cmd.setBinding(7, Sampler::bilinear());
1984 cmd.setBinding(8, scene.rtScene.tex);
1985 cmd.setBinding(9, scene.rtScene.vbo);
1986 cmd.setBinding(10,scene.rtScene.ibo);
1987 cmd.setBinding(11,scene.rtScene.rtDesc);
1988 cmd.setPipeline(shaders.probeTrace);
1989 cmd.dispatch(1024); // TODO: dispath indirect?
1990
1991 cmd.setDebugMarker("GI-HashMap");
1992 cmd.setBinding(0, gi.voteTable);
1993 cmd.setBinding(1, gi.hashTable);
1994 cmd.setBinding(2, gi.probes);
1995 cmd.setBinding(3, gi.freeList);
1996 cmd.setPipeline(shaders.probeClearHash);
1997 cmd.dispatchThreads(maxHash);
1998 cmd.setPipeline(shaders.probeMakeHash);
1999 cmd.dispatchThreads(gi.maxProbes);
2000
2001 cmd.setDebugMarker("GI-Lighting");
2002 cmd.setBinding(0, gi.probesLightingPrev);
2003 cmd.setBinding(1, gi.probesLighting);
2004 cmd.setPipeline(shaders.copyImg);
2005 cmd.dispatchThreads(gi.probesLighting.size());
2006
2007 cmd.setBinding(0, wview.sceneGlobals().uboGlobal[SceneGlobals::V_Main]);
2008 cmd.setBinding(1, gi.probesLighting);
2009 cmd.setBinding(2, gi.probesGBuffDiff, Sampler::nearest());
2010 cmd.setBinding(3, gi.probesGBuffNorm, Sampler::nearest());
2011 cmd.setBinding(4, gi.probesGBuffRayT, Sampler::nearest());
2012 cmd.setBinding(5, sky.viewCldLut, Sampler::bilinear());
2013 cmd.setBinding(6, shadowMap[1], Sampler::bilinear());
2014 cmd.setBinding(7, gi.probesLightingPrev, Sampler::nearest());
2015 cmd.setBinding(8, gi.hashTable);
2016 cmd.setBinding(9, gi.probes);
2017 cmd.setPipeline(shaders.probeLighting);
2018 cmd.dispatch(1024);
2019 }
2020
2021void Renderer::prepareExposure(Encoder<CommandBuffer>& cmd, WorldView& wview) {
2022 auto& scene = wview.sceneGlobals();
2023
2024 auto sunDir = wview.sky().sunLight().dir();
2025 struct Push {
2026 float baseL = 0.0;
2027 float sunOcclusion = 1.0;
2028 };
2029 Push push;
2030 push.sunOcclusion = smoothstep(0.0f, 0.01f, sunDir.y);
2031
2032 static float override = 0;
2033 static float add = 1.f;
2034 if(override>0)
2035 push.baseL = override;
2036 push.baseL += add;
2037
2038 cmd.setDebugMarker("Exposure");
2039 cmd.setFramebuffer({});
2040 cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]);
2041 cmd.setBinding(1, sky.viewCldLut);
2042 cmd.setBinding(2, sky.transLut, Sampler::bilinear(ClampMode::ClampToEdge));
2043 cmd.setBinding(3, sky.cloudsLut, Sampler::bilinear(ClampMode::ClampToEdge));
2044 cmd.setBinding(4, sky.irradianceLut);
2045 cmd.setPushData(&push, sizeof(push));
2046 cmd.setPipeline(shaders.skyExposure);
2047 cmd.dispatch(1);
2048 }
2049
2050void Renderer::drawProbesDbg(Encoder<CommandBuffer>& cmd, const WorldView& wview) {
2051 if(!settings.giEnabled)
2052 return;
2053
2054 static bool enable = false;
2055 if(!enable)
2056 return;
2057
2058 cmd.setDebugMarker("GI-dbg");
2059 cmd.setBinding(0, wview.sceneGlobals().uboGlobal[SceneGlobals::V_Main]);
2060 cmd.setBinding(1, gi.probesLighting);
2061 cmd.setBinding(2, gi.probes);
2062 cmd.setBinding(3, gi.hashTable);
2063 cmd.setPipeline(shaders.probeDbg);
2064 cmd.draw(nullptr, 0, 36, 0, gi.maxProbes);
2065 }
2066
2067void Renderer::drawProbesHitDbg(Encoder<CommandBuffer>& cmd) {
2068 if(!settings.giEnabled)
2069 return;
2070
2071 static bool enable = false;
2072 if(!enable)
2073 return;
2074
2075 cmd.setDebugMarker("GI-dbg");
2076 cmd.setBinding(1, gi.probesLighting);
2077 cmd.setBinding(2, gi.probesGBuffDiff);
2078 cmd.setBinding(3, gi.probesGBuffRayT);
2079 cmd.setBinding(4, gi.probes);
2080 cmd.setPipeline(shaders.probeHitDbg);
2081 cmd.draw(nullptr, 0, 36, 0, gi.maxProbes*256);
2082 //cmd.draw(nullptr, 0, 36, 0, 1024);
2083 }
2084
2085void Renderer::drawAmbient(Encoder<CommandBuffer>& cmd, const WorldView& view) {
2086 static bool enable = true;
2087 if(!enable)
2088 return;
2089
2090 if(settings.giEnabled && settings.zCloudShadowScale) {
2091 cmd.setDebugMarker("AmbientLight");
2092 cmd.setBinding(0, view.sceneGlobals().uboGlobal[SceneGlobals::V_Main]);
2093 cmd.setBinding(1, gi.probesLighting);
2094 cmd.setBinding(2, gbufDiffuse, Sampler::nearest());
2095 cmd.setBinding(3, gbufNormal, Sampler::nearest());
2096 cmd.setBinding(4, zbuffer, Sampler::nearest());
2097 cmd.setBinding(5, ssao.ssaoBlur, Sampler::nearest());
2098 cmd.setBinding(6, gi.hashTable);
2099 cmd.setBinding(7, gi.probes);
2100 cmd.setPipeline(shaders.probeAmbient);
2101 cmd.draw(nullptr, 0, 3);
2102 return;
2103 }
2104
2105 cmd.setDebugMarker("AmbientLight");
2106 cmd.setBinding(0, view.sceneGlobals().uboGlobal[SceneGlobals::V_Main]);
2107 cmd.setBinding(1, gbufDiffuse, Sampler::nearest());
2108 cmd.setBinding(2, gbufNormal, Sampler::nearest());
2109 cmd.setBinding(3, sky.irradianceLut);
2110 if(settings.zCloudShadowScale) {
2111 cmd.setBinding(4, ssao.ssaoBlur, Sampler::nearest(ClampMode::ClampToEdge));
2112 cmd.setPipeline(shaders.ambientLightSsao);
2113 } else {
2114 cmd.setPipeline(shaders.ambientLight);
2115 }
2116 cmd.draw(nullptr, 0, 3);
2117 }
2118
2119Tempest::Attachment Renderer::screenshoot(uint8_t frameId) {
2120 auto& device = Resources::device();
2121 device.waitIdle();
2122
2123 uint32_t w = uint32_t(zbuffer.w());
2124 uint32_t h = uint32_t(zbuffer.h());
2125 auto img = device.attachment(Tempest::TextureFormat::RGBA8,w,h);
2126
2127 CommandBuffer cmd;
2128 {
2129 auto enc = cmd.startEncoding(device);
2130 draw(img,enc,frameId);
2131 }
2132
2133 auto sync = device.submit(cmd);
2134 sync.wait();
2135 return img;
2136
2137 // debug
2138 auto d16 = device.attachment(TextureFormat::R16, swapchain.w(),swapchain.h());
2139 auto normals = device.attachment(TextureFormat::RGBA16, swapchain.w(),swapchain.h());
2140
2141 {
2142 auto enc = cmd.startEncoding(device);
2143 enc.setFramebuffer({{normals,Tempest::Discard,Tempest::Preserve}});
2144 enc.setBinding(0, gbufNormal, Sampler::nearest());
2145 enc.setPipeline(shaders.copy);
2146 enc.draw(nullptr, 0, 3);
2147
2148 enc.setFramebuffer({{d16,Tempest::Discard,Tempest::Preserve}});
2149 enc.setBinding(0,zbuffer,Sampler::nearest());
2150 enc.setPipeline(shaders.copy);
2151 enc.draw(nullptr, 0, 3);
2152 }
2153 sync = device.submit(cmd);
2154 sync.wait();
2155
2156 auto pm = device.readPixels(textureCast<const Texture2d&>(normals));
2157 pm.save("gbufNormal.png");
2158
2159 pm = device.readPixels(textureCast<const Texture2d&>(d16));
2160 pm.save("zbuffer.hdr");
2161
2162 return img;
2163 }
2164
2165float Renderer::internalResolutionScale() const {
2166 if(settings.vidResIndex==0)
2167 return 1;
2168 if(settings.vidResIndex==1)
2169 return 0.75;
2170 return 0.5;
2171 }
2172
2173Size Renderer::internalResolution() const {
2174 if(settings.vidResIndex==0)
2175 return Size(int(swapchain.w()), int(swapchain.h()));
2176 if(settings.vidResIndex==1)
2177 return Size(int(3*swapchain.w()/4), int(3*swapchain.h()/4));
2178 return Size(int(swapchain.w()/2), int(swapchain.h()/2));
2179 }
2180
float zFar() const
Definition camera.cpp:102
Tempest::Matrix4x4 projective() const
Definition camera.cpp:259
bool isInWater() const
Definition camera.cpp:194
float zNear() const
Definition camera.cpp:97
static constexpr const float minShadowY
Definition camera.h:18
Tempest::Matrix4x4 viewProjLwc() const
Definition camera.cpp:925
Tempest::Matrix4x4 viewShadowVsm(const Tempest::Vec3 &ldir) const
Definition camera.cpp:274
Tempest::Matrix4x4 viewShadow(const Tempest::Vec3 &ldir, size_t layer) const
Definition camera.cpp:321
Tempest::Matrix4x4 viewProj() const
Definition camera.cpp:909
void clear()
Definition frustrum.cpp:98
void make(const Tempest::Matrix4x4 &m, int32_t w, int32_t h)
Definition frustrum.cpp:5
Camera * camera()
Definition gothic.cpp:319
Tempest::Signal< void()> onSettingsChanged
Definition gothic.h:182
static auto options() -> const Options &
Definition gothic.cpp:496
static Gothic & inst()
Definition gothic.cpp:249
static int settingsGetI(std::string_view sec, std::string_view name)
Definition gothic.cpp:807
WorldView * worldView() const
Definition gothic.cpp:307
Tempest::Signal< void()> toggleGi
Definition gothic.h:143
static float settingsGetF(std::string_view sec, std::string_view name)
Definition gothic.cpp:841
Tempest::Signal< void()> toggleVsm
Definition gothic.h:143
Tempest::Signal< void()> toggleRtsm
Definition gothic.h:143
void draw(Tempest::Encoder< Tempest::CommandBuffer > &cmd)
State isOpen() const
const Tempest::StorageBuffer & bvh() const
Definition landscape.h:16
auto & lightsSsbo() const
Definition lightgroup.h:52
size_t size() const
Definition lightgroup.h:48
Tempest::Vec3 dir() const
Definition lightsource.h:12
Tempest::StorageImage dbg32
Definition renderer.h:241
void resetSwapchain()
Definition renderer.cpp:109
Tempest::StorageBuffer visList
Definition renderer.h:230
Tempest::Attachment screenshoot(uint8_t frameId)
void onWorldChanged()
Definition renderer.cpp:282
Tempest::StorageBuffer drawTasks
Definition renderer.h:237
Tempest::StorageBuffer pageTblOmni
Definition renderer.h:218
Tempest::ZBuffer pageData
Definition renderer.h:215
Tempest::StorageImage outputImageClr
Definition renderer.h:227
Tempest::StorageBuffer pageList
Definition renderer.h:216
Tempest::StorageBuffer pageListTmp
Definition renderer.h:217
Tempest::StorageImage pageTbl
Definition renderer.h:213
void dbgDraw(Tempest::Painter &painter)
Definition renderer.cpp:539
const uint32_t maxProbes
Definition renderer.h:194
Tempest::StorageImage lightTiles
Definition renderer.h:238
Tempest::StorageImage vsmDbg
Definition renderer.h:222
Tempest::StorageImage dbg16
Definition renderer.h:241
Tempest::StorageImage pages
Definition renderer.h:229
Tempest::StorageImage primTilesOmni
Definition renderer.h:239
Tempest::StorageImage dbg64
Definition renderer.h:241
Tempest::StorageBuffer posList
Definition renderer.h:231
Tempest::StorageImage outputImage
Definition renderer.h:226
Tempest::StorageBuffer epipoles
Definition renderer.h:207
Tempest::StorageImage primTiles
Definition renderer.h:234
Tempest::StorageBuffer visibleLights
Definition renderer.h:219
Tempest::StorageImage pageHiZ
Definition renderer.h:214
Tempest::StorageImage epTrace
Definition renderer.h:208
Tempest::StorageImage meshTiles
Definition renderer.h:233
Renderer(Tempest::Swapchain &swapchain)
Definition renderer.cpp:46
void draw(Tempest::Encoder< Tempest::CommandBuffer > &cmd, uint8_t cmdId, size_t imgId, Tempest::VectorImage::Mesh &uiLayer, Tempest::VectorImage::Mesh &numOverlay, InventoryMenu &inventory, VideoWidget &video)
Tempest::StorageImage lightBins
Definition renderer.h:239
static const Tempest::IndexBuffer< uint16_t > & cubeIbo()
@ ShadowLayers
Definition resources.h:49
static const Tempest::Sampler & shadowSampler()
static Tempest::Device & device()
Definition resources.h:83
static const Tempest::Texture2d & fallbackBlack()
static void recycle(Tempest::DescriptorArray &&arr)
Tempest::StorageImage vsmDbg
Tempest::StorageBuffer uboGlobal[V_Count]
Tempest::Vec3 originLwc
Tempest::ComputePipeline rtsmPrimOmni
Definition shaders.h:111
Tempest::ComputePipeline rtsmHiZ
Definition shaders.h:101
Tempest::ComputePipeline fogViewLut3d
Definition shaders.h:53
Tempest::RenderPipeline fog3dHQ
Definition shaders.h:50
Tempest::ComputePipeline rtsmMeshletCull
Definition shaders.h:103
static Shaders & inst()
Definition shaders.cpp:39
Tempest::ComputePipeline vsmListPages
Definition shaders.h:89
Tempest::RenderPipeline skyPathTrace
Definition shaders.h:56
Tempest::ComputePipeline probeAlocation
Definition shaders.h:78
Tempest::ComputePipeline rtsmLightsOmni
Definition shaders.h:110
Tempest::ComputePipeline rtsmMeshletOmni
Definition shaders.h:109
Tempest::ComputePipeline vsmCullLights
Definition shaders.h:88
Tempest::ComputePipeline fogViewLutSep
Definition shaders.h:53
Tempest::ComputePipeline rtsmBackfaceOmni
Definition shaders.h:109
Tempest::ComputePipeline probeInit
Definition shaders.h:77
Tempest::RenderPipeline directLightSh
Definition shaders.h:32
Tempest::ComputePipeline fogOcclusion
Definition shaders.h:52
Tempest::ComputePipeline swRendering
Definition shaders.h:120
Tempest::RenderPipeline stash
Definition shaders.h:39
Tempest::RenderPipeline probeHitDbg
Definition shaders.h:76
Tempest::RenderPipeline waterReflection
Definition shaders.h:59
Tempest::ComputePipeline hiZMip
Definition shaders.h:69
Tempest::RenderPipeline rtsmDbg
Definition shaders.h:114
Tempest::ComputePipeline probePrune
Definition shaders.h:78
static bool isRtsmSupported()
Definition shaders.cpp:325
Tempest::RenderPipeline probeAmbient
Definition shaders.h:80
Tempest::ComputePipeline rtsmCulling
Definition shaders.h:102
Tempest::ComputePipeline rtsmCompactOmni
Definition shaders.h:110
Tempest::RenderPipeline vsmDirectLight
Definition shaders.h:93
Tempest::RenderPipeline skyViewLut
Definition shaders.h:48
Tempest::ComputePipeline vsmPostprocessOmni
Definition shaders.h:88
Tempest::RenderPipeline directLightRq
Definition shaders.h:32
Tempest::RenderPipeline ambientLight
Definition shaders.h:33
Tempest::ComputePipeline rtsmRaster
Definition shaders.h:104
Tempest::RenderPipeline vsmDbg
Definition shaders.h:94
Tempest::RenderPipeline sun
Definition shaders.h:51
Tempest::RenderPipeline lightsVsm
Definition shaders.h:31
Tempest::ComputePipeline rtsmPosition
Definition shaders.h:102
Tempest::ComputePipeline vsmMarkOmniPages
Definition shaders.h:88
Tempest::ComputePipeline swRaytracing
Definition shaders.h:116
Tempest::RenderPipeline skyTransmittance
Definition shaders.h:47
Tempest::ComputePipeline hiZPot
Definition shaders.h:69
Tempest::ComputePipeline probeMakeHash
Definition shaders.h:77
Tempest::RenderPipeline swRenderingDbg
Definition shaders.h:121
Tempest::ComputePipeline ssao
Definition shaders.h:42
Tempest::ComputePipeline rtsmCullLights
Definition shaders.h:107
Tempest::ComputePipeline rtsmRasterOmni
Definition shaders.h:111
Tempest::RenderPipeline lightsRq
Definition shaders.h:31
Tempest::ComputePipeline ssaoBlur
Definition shaders.h:42
Tempest::ComputePipeline rtsmTaskOmni
Definition shaders.h:110
Tempest::ComputePipeline vsmFogShadow
Definition shaders.h:91
Tempest::ComputePipeline probeClear
Definition shaders.h:77
Tempest::RenderPipeline vsmFog
Definition shaders.h:92
Tempest::ComputePipeline rtsmRenderingOmni
Definition shaders.h:113
Tempest::ComputePipeline vsmAllocPages
Definition shaders.h:89
static bool isVsmSupported()
Definition shaders.cpp:316
Tempest::ComputePipeline rtsmCompactLights
Definition shaders.h:107
Tempest::ComputePipeline rtsmPrimCull
Definition shaders.h:103
Tempest::RenderPipeline skyViewCldLut
Definition shaders.h:48
Tempest::ComputePipeline cmaa2ProcessCandidates
Definition shaders.h:65
Tempest::RenderPipeline directLight
Definition shaders.h:32
Tempest::RenderPipeline fog
Definition shaders.h:49
void waitCompiler()
Definition shaders.cpp:35
Tempest::ComputePipeline probeVote
Definition shaders.h:78
Tempest::ComputePipeline vsmClear
Definition shaders.h:88
Tempest::ComputePipeline rtsmClearOmni
Definition shaders.h:106
Tempest::ComputePipeline vsmFogPages
Definition shaders.h:91
Tempest::ComputePipeline vsmMergePages
Definition shaders.h:89
Tempest::RenderPipeline ambientLightSsao
Definition shaders.h:33
Tempest::ComputePipeline fogEpipolarVsm
Definition shaders.h:83
Tempest::RenderPipeline underwaterT
Definition shaders.h:58
Tempest::RenderPipeline copy
Definition shaders.h:38
Tempest::RenderPipeline sky
Definition shaders.h:48
Tempest::RenderPipeline cmaa2DeferredColorApply2x2
Definition shaders.h:66
Tempest::ComputePipeline cloudsLut
Definition shaders.h:52
Tempest::ComputePipeline rtsmCullingOmni
Definition shaders.h:107
Tempest::ComputePipeline probeTrace
Definition shaders.h:79
Tempest::RenderPipeline skyMultiScattering
Definition shaders.h:47
Tempest::ComputePipeline rtsmPositionOmni
Definition shaders.h:108
Tempest::RenderPipeline lights
Definition shaders.h:31
Tempest::ComputePipeline rtsmBboxesOmni
Definition shaders.h:110
Tempest::ComputePipeline cmaa2EdgeColor2x2Presets[uint32_t(AaPreset::PRESETS_COUNT)]
Definition shaders.h:64
Tempest::ComputePipeline vsmFogTrace
Definition shaders.h:91
Tempest::RenderPipeline skySep
Definition shaders.h:48
Tempest::ComputePipeline fogEpipolarOcclusion
Definition shaders.h:84
Tempest::ComputePipeline irradiance
Definition shaders.h:44
Tempest::ComputePipeline copyImg
Definition shaders.h:36
Tempest::RenderPipeline rtsmDirectLight
Definition shaders.h:99
Tempest::ComputePipeline vsmClearOmni
Definition shaders.h:88
Tempest::ComputePipeline rtsmFogPages
Definition shaders.h:101
Tempest::ComputePipeline probeLighting
Definition shaders.h:79
Tempest::RenderPipeline waterReflectionSSR
Definition shaders.h:59
Tempest::ComputePipeline rtsmPages
Definition shaders.h:101
Tempest::RenderPipeline underwaterS
Definition shaders.h:58
Tempest::ComputePipeline vsmMarkPages
Definition shaders.h:88
Tempest::ComputePipeline vsmClumpPages
Definition shaders.h:89
Tempest::RenderPipeline probeDbg
Definition shaders.h:76
Tempest::ComputePipeline rtsmClear
Definition shaders.h:101
Tempest::ComputePipeline probeClearHash
Definition shaders.h:77
Tempest::ComputePipeline skyExposure
Definition shaders.h:54
Tempest::RenderPipeline tonemapping
Definition shaders.h:61
const State & cloudsNight() const
Definition sky.h:32
const State & cloudsDay() const
Definition sky.h:31
const Tempest::Texture2d & sunImage() const
Definition sky.h:28
float sunIntensity() const
Definition sky.h:25
float moonIntensity() const
Definition sky.h:26
float isNight() const
Definition sky.cpp:80
const LightSource & sunLight() const
Definition sky.h:23
bool isActive() const
void prepareGlobals(Tempest::Encoder< Tempest::CommandBuffer > &cmd, uint8_t fId)
Definition worldview.cpp:73
const DrawBuckets & drawBuckets() const
void drawShadow(Tempest::Encoder< Tempest::CommandBuffer > &cmd, uint8_t frameId, uint8_t layer)
void drawGBuffer(Tempest::Encoder< Tempest::CommandBuffer > &cmd, uint8_t frameId)
void drawTranslucent(Tempest::Encoder< Tempest::CommandBuffer > &cmd, uint8_t frameId)
const Sky & sky() const
Definition worldview.h:83
const SceneGlobals & sceneGlobals() const
Definition worldview.h:82
auto instanceSsbo() const -> const Tempest::StorageBuffer &
const DrawClusters & clusters() const
void postFrameupdate()
const Landscape & landscape() const
Definition worldview.h:84
void visibilityPass(Tempest::Encoder< Tempest::CommandBuffer > &cmd, int pass)
void drawHiZ(Tempest::Encoder< Tempest::CommandBuffer > &cmd)
void drawVsm(Tempest::Encoder< Tempest::CommandBuffer > &cmd)
void visibilityVsm(Tempest::Encoder< Tempest::CommandBuffer > &cmd)
bool updateLights()
bool updateRtScene()
const DrawCommands & drawCommands() const
void updateFrustrum(const Frustrum fr[])
void preFrameUpdate(const Camera &camera, uint64_t tickCount, uint8_t fId)
Definition worldview.cpp:47
void drawWater(Tempest::Encoder< Tempest::CommandBuffer > &cmd)
void setVirtualShadowMap(bool enabled, const Tempest::ZBuffer &pageData, const Tempest::StorageImage &pageTbl, const Tempest::StorageImage &pageHiZ, const Tempest::StorageBuffer &pageList)
Definition worldview.cpp:94
const LightSource & mainLight() const
Definition worldview.cpp:22
const LightGroup & lights() const
Definition worldview.h:85
static uint32_t nextPot(uint32_t x)
static const bool skyPathTrace
Definition renderer.cpp:17
static Size tileCount(Size sz, int s)
Definition renderer.cpp:40
static float linearstep(float edge0, float edge1, float x)
Definition renderer.cpp:35
static float smoothstep(float edge0, float edge1, float x)
Definition renderer.cpp:30
static uint32_t nextPot(uint32_t x)
Definition renderer.cpp:19
const Tempest::Texture2d * lay[2]
Definition sky.h:15