diff --git a/allcull.png b/allcull.png deleted file mode 100644 index 355b82a..0000000 Binary files a/allcull.png and /dev/null differ diff --git a/allnocull.png b/allnocull.png deleted file mode 100644 index c71b182..0000000 Binary files a/allnocull.png and /dev/null differ diff --git a/benchmark.py b/benchmark.py deleted file mode 100644 index 5ec632e..0000000 --- a/benchmark.py +++ /dev/null @@ -1,4 +0,0 @@ -import subprocess - -subprocess.run(['build/Benchmark.exe'], cwd='build') -subprocess.run(['build/Benchmark.exe', 'NOCULL'], cwd='build') \ No newline at end of file diff --git a/plots.py b/plots.py deleted file mode 100644 index 9400eca..0000000 --- a/plots.py +++ /dev/null @@ -1,81 +0,0 @@ -import pandas as pd -import matplotlib.pyplot as plt - -#areas = pd.read_csv('build/s.csv') -# -#plot = areas.hist(column='area', bins=100) -#plt.yscale('log') -#plt.show() - -df = pd.read_csv('build/stats.csv') -noculldf = pd.read_csv('build/statsNOCULL.csv') - -fig, ax = plt.subplots() - -scaled_reltime = df['RelTime'] / 10**9 - -scaled_FrameTime = df['FrameTime'].rolling(window=100).mean() / 10**9 -scaled_CACHED = df['CACHED'].rolling(window=100).mean() / 10**9 -scaled_MIPGEN = df['MIPGEN'].rolling(window=100).mean() / 10**9 -scaled_DEPTHCULL = df['DEPTHCULL'].rolling(window=100).mean() / 10**9 -scaled_VISIBILITY = df['VISIBILITY'].rolling(window=100).mean() / 10**9 -scaled_LIGHTCULL = df['LIGHTCULL'].rolling(window=100).mean() / 10**9 -scaled_BASE = df['BASE'].rolling(window=100).mean() / 10**9 - -ax.plot(scaled_reltime, scaled_FrameTime, label='Frame Time') -ax.plot(scaled_reltime, scaled_CACHED, label='CACHED') -ax.plot(scaled_reltime, scaled_MIPGEN, label='MIPGEN') -ax.plot(scaled_reltime, scaled_DEPTHCULL, label='DEPTHCULL') -ax.plot(scaled_reltime, scaled_VISIBILITY, label='VISIBILITY') -ax.plot(scaled_reltime, scaled_LIGHTCULL, label='LIGHTCULL') -ax.plot(scaled_reltime, scaled_BASE, label='BASE') - - - -ax.set_xlabel('Application Time (ms)') -ax.set_ylabel('Render Times (ms)') - -ax.legend() - -fig.savefig('allcull.png') - -nocullfig, nocullax = plt.subplots() - -nocullscaled_reltime = noculldf['RelTime'] / 10**9 - -nocullscaled_FrameTime = noculldf['FrameTime'].rolling(window=100).mean() / 10**9 -nocullscaled_CACHED = noculldf['CACHED'].rolling(window=100).mean() / 10**9 -nocullscaled_MIPGEN = noculldf['MIPGEN'].rolling(window=100).mean() / 10**9 -nocullscaled_DEPTHCULL = noculldf['DEPTHCULL'].rolling(window=100).mean() / 10**9 -nocullscaled_VISIBILITY = noculldf['VISIBILITY'].rolling(window=100).mean() / 10**9 -nocullscaled_LIGHTCULL = noculldf['LIGHTCULL'].rolling(window=100).mean() / 10**9 -nocullscaled_BASE = noculldf['BASE'].rolling(window=100).mean() / 10**9 - -nocullax.plot(nocullscaled_reltime, nocullscaled_FrameTime, label='Frame Time') -nocullax.plot(nocullscaled_reltime, nocullscaled_CACHED, label='CACHED') -nocullax.plot(nocullscaled_reltime, nocullscaled_MIPGEN, label='MIPGEN') -nocullax.plot(nocullscaled_reltime, nocullscaled_DEPTHCULL, label='DEPTHCULL') -nocullax.plot(nocullscaled_reltime, nocullscaled_VISIBILITY, label='VISIBILITY') -nocullax.plot(nocullscaled_reltime, nocullscaled_LIGHTCULL, label='LIGHTCULL') -nocullax.plot(nocullscaled_reltime, nocullscaled_BASE, label='BASE') - -nocullax.set_xlabel('Application Time (ms)') -nocullax.set_ylabel('Render Times (ms)') - -nocullax.legend() - -nocullfig.savefig('allnocull.png') - -combfig, combax = plt.subplots() - -combax.plot(scaled_reltime, scaled_FrameTime, label='Culling Frametime') -combax.plot(nocullscaled_reltime, nocullscaled_FrameTime, label='No Culling Frametime') - -combax.set_xlabel('Application Time (ms)') -combax.set_ylabel('Render Times (ms)') - -combax.legend() - -combfig.savefig('combined.png') - - diff --git a/res/shaders/WaterCommon.slang b/res/shaders/WaterCommon.slang new file mode 100644 index 0000000..ad8d289 --- /dev/null +++ b/res/shaders/WaterCommon.slang @@ -0,0 +1,53 @@ +struct WaterPayload +{ + float2 offset; + float extent; + float height; +}; + +struct WaterVertex +{ + float4 position_CS : SV_Position; + float3 position_WS : POSITION0; + float2 texCoord : TEXCOORD0; + float depth : DEPTH; +}; + +struct MaterialParams +{ + float3 sunDirection; + float displacementDepthAttenuation; + + float foamSubtract0; + float foamSubtract1; + float foamSubtract2; + float foamSubtract3; + + float normalStrength; + float foamDepthAttenuation; + float normalDepthAttenuation; + float roughness; + + float3 sunIrradiance; + float foamRoughnessModifier; + + float3 scatterColor; + float environmentLightStrength; + + float3 bubbleColor; + float heightModifier; + + float bubbleDensity; + float wavePeakScatterStrength; + float scatterStrength; + float scatterShadowStrength; + + float3 foamColor; + Texture2DArray displacementTextures; + Texture2DArray slopeTextures; + TextureCube environmentMap; + SamplerState sampler; + StructuredBuffer tiles; +}; +layout(set = 1) +ParameterBlock pWaterMaterial; diff --git a/res/shaders/WaterCompute.slang b/res/shaders/WaterCompute.slang new file mode 100644 index 0000000..d51a324 --- /dev/null +++ b/res/shaders/WaterCompute.slang @@ -0,0 +1,329 @@ +const static float PI = 3.1415926535897932f; +// FFT and JONSWAP Implementation largely referenced from https://github.com/gasgiant/FFT-Ocean/ +struct SpectrumParameters { + float scale; + float angle; + float spreadBlend; + float swell; + float alpha; + float peakOmega; + float gamma; + float shortWavesFade; +}; + +struct ComputeParams +{ + float frameTime, deltaTime, gravity, repeatTime, depth, lowCutoff, highCutoff; + int seed; + float2 lambda; + uint N, lengthScale0, lengthScale1, lengthScale2, lengthScale3; + float foamBias, foamDecayRate, foamAdd, foamThreshold; + RWTexture2DArray spectrumTextures, initialSpectrumTextures, displacementTextures; + RWTexture2DArray slopeTexture; + RWTexture2D boyancyData; + StructuredBuffer spectrums; + SamplerState linear_repeat_sampler; +}; +layout(set = 0) +ParameterBlock pParams; + +float2 ComplexMult(float2 a, float2 b) { + return float2(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x); +} + +float2 EulerFormula(float x) { + return float2(cos(x), sin(x)); +} + +float hash(uint n) { + // integer hash copied from Hugo Elias + n = (n << 13U) ^ n; + n = n * (n * n * 15731U + 0x789221U) + (0x1376312589U); + return float(n & uint(0x7fffffffU)) / float(0x7fffffff); +} + +float2 UniformToGaussian(float u1, float u2) { + float R = sqrt(-2.0f * log(u1)); + float theta = 2.0f * PI * u2; + + return float2(R * cos(theta), R * sin(theta)); +} + + +float Dispersion(float kMag) { + return sqrt(pParams.gravity * kMag * tanh(min(kMag * pParams.depth, 20))); +} + +float DispersionDerivative(float kMag) { + float th = tanh(min(kMag * pParams.depth, 20)); + float ch = cosh(kMag * pParams.depth); + return pParams.gravity * (pParams.depth * kMag / ch / ch + th) / Dispersion(kMag) / 2.0f; +} + +float NormalizationFactor(float s) { + float s2 = s * s; + float s3 = s2 * s; + float s4 = s3 * s; + if (s < 5) return -0.000564f * s4 + 0.00776f * s3 - 0.044f * s2 + 0.192f * s + 0.163f; + else return -4.80e-08f * s4 + 1.07e-05f * s3 - 9.53e-04f * s2 + 5.90e-02f * s + 3.93e-01f; +} + +float DonelanBannerBeta(float x) { + if (x < 0.95f) return 2.61f * pow(abs(x), 1.3f); + if (x < 1.6f) return 2.28f * pow(abs(x), -1.3f); + + float p = -0.4f + 0.8393f * exp(-0.567f * log(x * x)); + return pow(10.0f, p); +} + +float DonelanBanner(float theta, float omega, float peakOmega) { + float beta = DonelanBannerBeta(omega / peakOmega); + float sech = 1.0f / cosh(beta * theta); + return beta / 2.0f / tanh(beta * 3.1416f) * sech * sech; +} + +float Cosine2s(float theta, float s) { + return NormalizationFactor(s) * pow(abs(cos(0.5f * theta)), 2.0f * s); +} + +float SpreadPower(float omega, float peakOmega) { + if (omega > peakOmega) + return 9.77f * pow(abs(omega / peakOmega), -2.5f); + else + return 6.97f * pow(abs(omega / peakOmega), 5.0f); +} + +float DirectionSpectrum(float theta, float omega, SpectrumParameters spectrum) { + float s = SpreadPower(omega, spectrum.peakOmega) + 16 * tanh(min(omega / spectrum.peakOmega, 20)) * spectrum.swell * spectrum.swell; + return lerp(2.0f / 3.1415f * cos(theta) * cos(theta), Cosine2s(theta - spectrum.angle, s), spectrum.spreadBlend); +} + +float TMACorrection(float omega) { + float omegaH = omega * sqrt(pParams.depth / pParams.gravity); + if (omegaH <= 1.0f) + return 0.5f * omegaH * omegaH; + if (omegaH < 2.0f) + return 1.0f - 0.5f * (2.0f - omegaH) * (2.0f - omegaH); + + return 1.0f; +} + +float JONSWAP(float omega, SpectrumParameters spectrum) { + float sigma = (omega <= spectrum.peakOmega) ? 0.07f : 0.09f; + + float r = exp(-(omega - spectrum.peakOmega) * (omega - spectrum.peakOmega) / 2.0f / sigma / sigma / spectrum.peakOmega / spectrum.peakOmega); + + float oneOverOmega = 1.0f / omega; + float peakOmegaOverOmega = spectrum.peakOmega / omega; + return spectrum.scale * TMACorrection(omega) * spectrum.alpha * pParams.gravity * pParams.gravity + * oneOverOmega * oneOverOmega * oneOverOmega * oneOverOmega * oneOverOmega + * exp(-1.25f * peakOmegaOverOmega * peakOmegaOverOmega * peakOmegaOverOmega * peakOmegaOverOmega) + * pow(abs(spectrum.gamma), r); +} + +float ShortWavesFade(float kLength, SpectrumParameters spectrum) { + return exp(-spectrum.shortWavesFade * spectrum.shortWavesFade * kLength * kLength); +} + +[numthreads(8,8,1)] +void CS_InitializeSpectrum(uint3 id : SV_DISPATCHTHREADID) { + uint seed = id.x + pParams.N * id.y + pParams.N; + seed += pParams.seed; + + float lengthScales[4] = { pParams.lengthScale0, pParams.lengthScale1, pParams.lengthScale2, pParams.lengthScale3 }; + + for (uint i = 0; i < 4; ++i) { + float halfN = pParams.N / 2.0f; + + float deltaK = 2.0f * PI / lengthScales[i]; + float2 K = (id.xy - halfN) * deltaK; + float kLength = length(K); + + seed += i + uint(hash(seed) * 10); + float4 uniformRandSamples = float4(hash(seed), hash(seed * 2), hash(seed * 3), hash(seed * 4)); + float2 gauss1 = float2(1, 1);UniformToGaussian(uniformRandSamples.x, uniformRandSamples.y); + float2 gauss2 = float2(1, 1);UniformToGaussian(uniformRandSamples.z, uniformRandSamples.w); + + if (pParams.lowCutoff <= kLength && kLength <= pParams.highCutoff) { + float kAngle = atan2(K.y, K.x); + float omega = Dispersion(kLength); + + float dOmegadk = DispersionDerivative(kLength); + + float spectrum = JONSWAP(omega, pParams.spectrums[i * 2]) * DirectionSpectrum(kAngle, omega, pParams.spectrums[i * 2]) * ShortWavesFade(kLength, pParams.spectrums[i * 2]); + + if (pParams.spectrums[i * 2 + 1].scale > 0) + spectrum += JONSWAP(omega, pParams.spectrums[i * 2 + 1]) * DirectionSpectrum(kAngle, omega, pParams.spectrums[i * 2 + 1]) * ShortWavesFade(kLength, pParams.spectrums[i * 2 + 1]); + + pParams.initialSpectrumTextures[uint3(id.xy, i)] = float4(float2(gauss2.x, gauss1.y) * sqrt(2 * spectrum * abs(dOmegadk) / kLength * deltaK * deltaK), 0.0f, 0.0f); + } else { + pParams.initialSpectrumTextures[uint3(id.xy, i)] = 0.0f; + } + } +} + +[numthreads(8,8,1)] +void CS_PackSpectrumConjugate(uint3 id : SV_DISPATCHTHREADID) { + for (uint i = 0; i < 4; ++i) { + float2 h0 = pParams.initialSpectrumTextures[uint3(id.xy, i)].rg; + float2 h0conj = pParams.initialSpectrumTextures[uint3((pParams.N - id.x ) % pParams.N, (pParams.N - id.y) % pParams.N, i)].rg; + + pParams.initialSpectrumTextures[uint3(id.xy, i)] = float4(h0, h0conj.x, -h0conj.y); + } +} + +[numthreads(8, 8, 1)] +void CS_UpdateSpectrumForFFT(uint3 id : SV_DISPATCHTHREADID) { + + float lengthScales[4] = { pParams.lengthScale0, pParams.lengthScale1, pParams.lengthScale2, pParams.lengthScale3 }; + + for (int i = 0; i < 4; ++i) { + float4 initialSignal = pParams.initialSpectrumTextures[uint3(id.xy, i)]; + float2 h0 = initialSignal.xy; + float2 h0conj = initialSignal.zw; + + float halfN = pParams.N / 2.0f; + float2 K = (id.xy - halfN) * 2.0f * PI / lengthScales[i]; + float kMag = length(K); + float kMagRcp = rcp(kMag); + + if (kMag < 0.0001f) { + kMagRcp = 1.0f; + } + + float w_0 = 2.0f * PI / pParams.repeatTime; + float dispersion = floor(sqrt(pParams.gravity * kMag) / w_0) * w_0 * pParams.frameTime; + + float2 exponent = EulerFormula(dispersion); + + float2 htilde = ComplexMult(h0, exponent) + ComplexMult(h0conj, float2(exponent.x, -exponent.y)); + float2 ih = float2(-htilde.y, htilde.x); + + float2 displacementX = ih * K.x * kMagRcp; + float2 displacementY = htilde; + float2 displacementZ = ih * K.y * kMagRcp; + + float2 displacementX_dx = -htilde * K.x * K.x * kMagRcp; + float2 displacementY_dx = ih * K.x; + float2 displacementZ_dx = -htilde * K.x * K.y * kMagRcp; + + float2 displacementY_dz = ih * K.y; + float2 displacementZ_dz = -htilde * K.y * K.y * kMagRcp; + + float2 htildeDisplacementX = float2(displacementX.x - displacementZ.y, displacementX.y + displacementZ.x); + float2 htildeDisplacementZ = float2(displacementY.x - displacementZ_dx.y, displacementY.y + displacementZ_dx.x); + + float2 htildeSlopeX = float2(displacementY_dx.x - displacementY_dz.y, displacementY_dx.y + displacementY_dz.x); + float2 htildeSlopeZ = float2(displacementX_dx.x - displacementZ_dz.y, displacementX_dx.y + displacementZ_dz.x); + + pParams.spectrumTextures[uint3(id.xy, i * 2)] = float4(htildeDisplacementX, htildeDisplacementZ); + pParams.spectrumTextures[uint3(id.xy, i * 2 + 1)] = float4(htildeSlopeX, htildeSlopeZ); + } +} + +float2 ComplexExp(float2 a) { + return float2(cos(a.y), sin(a.y) * exp(a.x)); +} + + +float4 ComputeTwiddleFactorAndInputIndices(uint2 id) { + uint b = pParams.N >> (id.x + 1); + float2 mult = 2 * PI * float2(0.0f, 1.0f) / pParams.N; + uint i = (2 * b * (id.y / b) + id.y % b) % pParams.N; + float2 twiddle = ComplexExp(-mult * ((id.y / b) * b)); + + return float4(twiddle, i, i + b); +} + +#define SIZE 1024 +#define LOG_SIZE 10 + +groupshared float4 fftGroupBuffer[2][SIZE]; + +void ButterflyValues(uint step, uint index, out uint2 indices, out float2 twiddle) { + const float twoPi = 6.28318530718; + uint b = SIZE >> (step + 1); + uint w = b * (index / b); + uint i = (w + index) % SIZE; + sincos(-twoPi / SIZE * w, twiddle.y, twiddle.x); + + //This is what makes it the inverse FFT + twiddle.y = -twiddle.y; + indices = uint2(i, i + b); +} + +float4 FFT(uint threadIndex, float4 input) { + fftGroupBuffer[0][threadIndex] = input; + GroupMemoryBarrierWithGroupSync(); + bool flag = false; + + [unroll] + for (uint step = 0; step < LOG_SIZE; ++step) { + uint2 inputsIndices; + float2 twiddle; + ButterflyValues(step, threadIndex, inputsIndices, twiddle); + + float4 v = fftGroupBuffer[uint(flag)][inputsIndices.y]; + fftGroupBuffer[uint(flag)][threadIndex] = fftGroupBuffer[uint(flag)][inputsIndices.x] + float4(ComplexMult(twiddle, v.xy), ComplexMult(twiddle, v.zw)); + + flag = !flag; + GroupMemoryBarrierWithGroupSync(); + } + + return fftGroupBuffer[uint(flag)][threadIndex]; +} + +[numthreads(SIZE, 1, 1)] +void CS_HorizontalFFT(uint3 id : SV_DISPATCHTHREADID) { + for (int i = 0; i < 8; ++i) { + pParams.spectrumTextures[uint3(id.xy, i)] = FFT(id.x, pParams.spectrumTextures[uint3(id.xy, i)]); + } +} + +[numthreads(SIZE, 1, 1)] +void CS_VerticalFFT(uint3 id : SV_DISPATCHTHREADID) { + for (int i = 0; i < 8; ++i) { + pParams.spectrumTextures[uint3(id.yx, i)] = FFT(id.x, pParams.spectrumTextures[uint3(id.yx, i)]); + } +} + +float4 Permute(float4 data, float3 id) { + return data * (1.0f - 2.0f * ((id.x + id.y) % 2)); +} + +[numthreads(8, 8, 1)] +void CS_AssembleMaps(uint3 id : SV_DISPATCHTHREADID) { + for (int i = 0; i < 4; ++i) { + float4 htildeDisplacement = Permute(pParams.spectrumTextures[uint3(id.xy, i * 2)], id); + float4 htildeSlope = Permute(pParams.spectrumTextures[uint3(id.xy, i * 2 + 1)], id); + + float2 dxdz = htildeDisplacement.rg; + float2 dydxz = htildeDisplacement.ba; + float2 dyxdyz = htildeSlope.rg; + float2 dxxdzz = htildeSlope.ba; + + float jacobian = (1.0f + pParams.lambda.x * dxxdzz.x) * (1.0f + pParams.lambda.y * dxxdzz.y) - pParams.lambda.x * pParams.lambda.y * dydxz.y * dydxz.y; + + float3 displacement = float3(pParams.lambda.x * dxdz.x, dydxz.x, pParams.lambda.y * dxdz.y); + + float2 slopes = dyxdyz.xy / (1 + abs(dxxdzz * pParams.lambda)); + float covariance = slopes.x * slopes.y; + + float foam = pParams.displacementTextures[uint3(id.xy, i)].a; + foam *= exp(-pParams.foamDecayRate); + foam = saturate(foam); + + float biasedJacobian = max(0.0f, -(jacobian - pParams.foamBias)); + + if (biasedJacobian > pParams.foamThreshold) + foam += pParams.foamAdd * biasedJacobian; + + + pParams.displacementTextures[uint3(id.xy, i)] = float4(displacement, foam); + pParams.slopeTexture[uint3(id.xy, i)] = float2(slopes); + + if (i == 0) { + pParams.boyancyData[id.xy] = half(displacement.y); + } + } +} diff --git a/res/shaders/WaterMesh.slang b/res/shaders/WaterMesh.slang index e69de29..391ae65 100644 --- a/res/shaders/WaterMesh.slang +++ b/res/shaders/WaterMesh.slang @@ -0,0 +1,69 @@ +import Common; +import Scene; +import WaterCommon; +import MaterialParameter; + +const static uint64_t TILE_VERTS = 144; +const static uint64_t TILE_PRIMS = 242; + +const static float2 VERT[TILE_VERTS] = {float2(0.0f / 11, 0.0f / 11), float2(0.0f / 11, 1.0f / 11), float2(0.0f / 11, 2.0f / 11), float2(0.0f / 11, 3.0f / 11), float2(0.0f / 11, 4.0f / 11), float2(0.0f / 11, 5.0f / 11), float2(0.0f / 11, +6.0f / 11), float2(0.0f / 11, 7.0f / 11), float2(0.0f / 11, 8.0f / 11), float2(0.0f / 11, 9.0f / 11), float2(0.0f / 11, 10.0f / 11), float2(0.0f / 11, 11.0f / 11), float2(1.0f / 11, 0.0f / 11), float2(1.0f / 11, 1.0f / 11), float2(1.0f / 11, 2.0f / 11), float2(1.0f / 11, 3.0f / 11), float2(1.0f / +11, 4.0f / 11), float2(1.0f / 11, 5.0f / 11), float2(1.0f / 11, 6.0f / 11), float2(1.0f / 11, 7.0f / 11), float2(1.0f / 11, 8.0f / 11), float2(1.0f / 11, 9.0f / 11), float2(1.0f / 11, 10.0f / 11), float2(1.0f / 11, 11.0f / 11), float2(2.0f / 11, 0.0f / 11), float2(2.0f / 11, 1.0f / 11), float2(2.0f / 11, 2.0f / 11), float2(2.0f / 11, 3.0f / 11), float2(2.0f / 11, 4.0f / 11), float2(2.0f / 11, 5.0f / 11), float2(2.0f / 11, 6.0f / 11), float2(2.0f / 11, 7.0f / 11), float2(2.0f / 11, 8.0f / 11), float2(2.0f / 11, 9.0f / 11), float2(2.0f / 11, 10.0f / 11), float2(2.0f / 11, 11.0f / 11), float2(3.0f / 11, 0.0f / 11), float2(3.0f / 11, 1.0f / 11), float2(3.0f / 11, 2.0f / 11), float2(3.0f / 11, 3.0f / 11), float2(3.0f / 11, 4.0f / 11), float2(3.0f / 11, 5.0f / 11), float2(3.0f / 11, 6.0f / 11), float2(3.0f / 11, 7.0f / 11), float2(3.0f / 11, 8.0f / 11), float2(3.0f / 11, 9.0f / 11), float2(3.0f / 11, 10.0f / 11), float2(3.0f / 11, 11.0f / 11), float2(4.0f / 11, 0.0f / 11), float2(4.0f +/ 11, 1.0f / 11), float2(4.0f / 11, 2.0f / 11), float2(4.0f / 11, 3.0f / 11), float2(4.0f / 11, 4.0f / 11), float2(4.0f / 11, 5.0f / 11), float2(4.0f / 11, 6.0f / 11), float2(4.0f / 11, 7.0f / 11), float2(4.0f / 11, 8.0f / 11), float2(4.0f / 11, 9.0f / 11), float2(4.0f / 11, 10.0f / 11), float2(4.0f / 11, 11.0f / 11), float2(5.0f / 11, 0.0f / 11), float2(5.0f / 11, 1.0f / 11), float2(5.0f / 11, +2.0f / 11), float2(5.0f / 11, 3.0f / 11), float2(5.0f / 11, 4.0f / 11), float2(5.0f / 11, 5.0f / 11), float2(5.0f / 11, 6.0f / 11), float2(5.0f / 11, 7.0f / 11), float2(5.0f / 11, 8.0f / 11), float2(5.0f / 11, 9.0f / 11), float2(5.0f / 11, 10.0f / 11), float2(5.0f / 11, 11.0f / 11), float2(6.0f / +11, 0.0f / 11), float2(6.0f / 11, 1.0f / 11), float2(6.0f / 11, 2.0f / 11), float2(6.0f / 11, 3.0f / 11), float2(6.0f / 11, 4.0f / 11), float2(6.0f / 11, 5.0f / 11), float2(6.0f / 11, 6.0f / 11), float2(6.0f / 11, 7.0f / 11), float2(6.0f / 11, 8.0f / 11), float2(6.0f / 11, 9.0f / 11), float2(6.0f +/ 11, 10.0f / 11), float2(6.0f / 11, 11.0f / 11), float2(7.0f / 11, 0.0f / 11), float2(7.0f / 11, 1.0f / 11), float2(7.0f / 11, 2.0f / 11), float2(7.0f / 11, 3.0f / 11), float2(7.0f / 11, 4.0f / 11), float2(7.0f / 11, 5.0f / 11), float2(7.0f / 11, 6.0f / 11), float2(7.0f / 11, 7.0f / 11), float2(7.0f / 11, 8.0f / 11), float2(7.0f / 11, 9.0f / 11), float2(7.0f / 11, 10.0f / 11), float2(7.0f / 11, 11.0f / 11), float2(8.0f / 11, 0.0f / 11), float2(8.0f / 11, 1.0f / 11), float2(8.0f / 11, 2.0f / 11), float2(8.0f / 11, 3.0f / 11), float2(8.0f / 11, 4.0f / 11), float2(8.0f / 11, 5.0f / 11), float2(8.0f / 11, 6.0f / 11), float2(8.0f / 11, 7.0f / 11), float2(8.0f / 11, 8.0f / 11), float2(8.0f / +11, 9.0f / 11), float2(8.0f / 11, 10.0f / 11), float2(8.0f / 11, 11.0f / 11), float2(9.0f / 11, 0.0f / 11), float2(9.0f / 11, 1.0f / 11), float2(9.0f / 11, 2.0f / 11), float2(9.0f / 11, 3.0f / 11), float2(9.0f / 11, 4.0f / 11), float2(9.0f / 11, 5.0f / 11), float2(9.0f / 11, 6.0f / 11), float2(9.0f / 11, 7.0f / 11), float2(9.0f / 11, 8.0f / 11), float2(9.0f / 11, 9.0f / 11), float2(9.0f / 11, 10.0f / 11), float2(9.0f / 11, 11.0f / 11), float2(10.0f / 11, 0.0f / 11), float2(10.0f / 11, 1.0f / 11), float2(10.0f / 11, 2.0f / 11), float2(10.0f / 11, 3.0f / 11), float2(10.0f / 11, 4.0f / 11), float2(10.0f / 11, 5.0f / 11), float2(10.0f / 11, 6.0f / 11), float2(10.0f / 11, 7.0f / 11), float2(10.0f / 11, 8.0f / 11), float2(10.0f / 11, 9.0f / 11), float2(10.0f / 11, 10.0f / 11), float2(10.0f / 11, 11.0f / 11), float2(11.0f / 11, 0.0f / 11), float2(11.0f / 11, 1.0f / 11), float2(11.0f / 11, 2.0f / 11), float2(11.0f / 11, 3.0f / 11), float2(11.0f / 11, 4.0f / 11), float2(11.0f / 11, 5.0f / 11), float2(11.0f / 11, 6.0f / 11), float2(11.0f / 11, 7.0f / 11), float2(11.0f / 11, 8.0f / 11), float2(11.0f / 11, 9.0f / 11), float2(11.0f / 11, 10.0f / 11), float2(11.0f / 11, 11.0f / 11)}; + +const static uint3 IND[TILE_PRIMS] = {uint3(0, 1, 12), uint3(12, 1, 13), uint3(1, 2, 13), uint3(13, 2, 14), uint3(2, 3, 14), uint3(14, 3, 15), uint3(3, 4, 15), uint3(15, 4, 16), uint3(4, 5, 16), uint3(16, 5, 17), uint3(5, 6, 17), uint3(17, 6, 18), uint3(6, 7, 18), uint3(18, 7, 19), uint3(7, 8, 19), uint3(19, 8, 20), uint3(8, 9, 20), uint3(20, 9, 21), uint3(9, 10, 21), uint3(21, 10, 22), uint3(10, 11, 22), uint3(22, 11, 23), uint3(12, 13, 24), uint3(24, 13, 25), uint3(13, 14, 25), uint3(25, 14, 26), uint3(14, +15, 26), uint3(26, 15, 27), uint3(15, 16, 27), uint3(27, 16, 28), uint3(16, 17, 28), uint3(28, 17, 29), uint3(17, 18, 29), uint3(29, 18, 30), uint3(18, 19, 30), uint3(30, 19, 31), uint3(19, 20, 31), uint3(31, 20, 32), uint3(20, 21, 32), uint3(32, 21, 33), uint3(21, 22, 33), uint3(33, 22, 34), uint3(22, 23, 34), uint3(34, 23, 35), uint3(24, 25, 36), uint3(36, 25, 37), uint3(25, 26, +37), uint3(37, 26, 38), uint3(26, 27, 38), uint3(38, 27, 39), uint3(27, 28, 39), uint3(39, 28, 40), uint3(28, 29, 40), uint3(40, 29, 41), uint3(29, 30, 41), uint3(41, 30, 42), uint3(30, 31, 42), uint3(42, 31, 43), uint3(31, 32, 43), uint3(43, 32, 44), uint3(32, 33, 44), uint3(44, 33, 45), uint3(33, 34, 45), uint3(45, 34, 46), uint3(34, 35, 46), uint3(46, 35, 47), uint3(36, 37, 48), uint3(48, 37, 49), uint3(37, 38, 49), uint3(49, 38, 50), uint3(38, 39, 50), uint3(50, 39, 51), uint3(39, 40, 51), uint3(51, 40, 52), uint3(40, 41, 52), uint3(52, 41, 53), uint3(41, 42, 53), +uint3(53, 42, 54), uint3(42, 43, 54), uint3(54, 43, 55), uint3(43, 44, 55), uint3(55, 44, 56), uint3(44, 45, 56), uint3(56, 45, 57), uint3(45, 46, 57), uint3(57, 46, 58), uint3(46, 47, 58), uint3(58, 47, 59), uint3(48, 49, 60), uint3(60, 49, 61), uint3(49, 50, 61), uint3(61, 50, 62), uint3(50, 51, 62), uint3(62, 51, 63), uint3(51, 52, 63), uint3(63, 52, 64), uint3(52, 53, 64), uint3(64, 53, 65), uint3(53, 54, 65), uint3(65, 54, 66), uint3(54, 55, 66), uint3(66, 55, 67), uint3(55, 56, 67), uint3(67, 56, 68), uint3(56, 57, 68), uint3(68, 57, 69), uint3(57, 58, 69), uint3(69, 58, 70), uint3(58, 59, 70), uint3(70, 59, 71), uint3(60, 61, 72), uint3(72, 61, 73), uint3(61, 62, 73), uint3(73, 62, 74), uint3(62, 63, 74), uint3(74, 63, 75), uint3(63, 64, 75), uint3(75, 64, 76), uint3(64, 65, 76), uint3(76, 65, 77), uint3(65, 66, 77), uint3(77, 66, 78), uint3(66, 67, 78), uint3(78, 67, 79), uint3(67, 68, 79), uint3(79, 68, 80), uint3(68, 69, 80), uint3(80, 69, 81), uint3(69, 70, 81), uint3(81, 70, 82), uint3(70, 71, 82), uint3(82, 71, 83), uint3(72, +73, 84), uint3(84, 73, 85), uint3(73, 74, 85), uint3(85, 74, 86), uint3(74, 75, 86), uint3(86, 75, 87), uint3(75, 76, 87), uint3(87, 76, 88), uint3(76, 77, 88), uint3(88, 77, 89), uint3(77, 78, 89), uint3(89, 78, 90), uint3(78, 79, 90), uint3(90, 79, 91), uint3(79, 80, 91), uint3(91, 80, 92), uint3(80, 81, 92), uint3(92, 81, 93), uint3(81, 82, 93), uint3(93, 82, 94), uint3(82, 83, +94), uint3(94, 83, 95), uint3(84, 85, 96), uint3(96, 85, 97), uint3(85, 86, 97), uint3(97, 86, 98), uint3(86, 87, 98), uint3(98, 87, 99), uint3(87, 88, 99), uint3(99, 88, 100), uint3(88, 89, 100), uint3(100, 89, 101), uint3(89, 90, 101), uint3(101, 90, 102), uint3(90, 91, 102), uint3(102, 91, 103), uint3(91, 92, 103), uint3(103, 92, 104), uint3(92, 93, 104), uint3(104, 93, 105), uint3(93, 94, 105), uint3(105, 94, 106), uint3(94, 95, 106), uint3(106, 95, 107), uint3(96, 97, 108), uint3(108, 97, 109), uint3(97, 98, 109), uint3(109, 98, 110), uint3(98, 99, 110), uint3(110, 99, 111), uint3(99, 100, 111), uint3(111, 100, 112), uint3(100, 101, 112), uint3(112, 101, 113), uint3(101, 102, 113), uint3(113, 102, 114), uint3(102, 103, 114), uint3(114, 103, 115), uint3(103, 104, 115), uint3(115, 104, 116), uint3(104, 105, 116), uint3(116, 105, 117), uint3(105, 106, 117), uint3(117, 106, 118), uint3(106, 107, 118), uint3(118, 107, 119), uint3(108, 109, 120), uint3(120, 109, 121), uint3(109, 110, 121), uint3(121, 110, 122), uint3(110, 111, 122), uint3(122, 111, +123), uint3(111, 112, 123), uint3(123, 112, 124), uint3(112, 113, 124), uint3(124, 113, 125), uint3(113, 114, 125), uint3(125, 114, 126), uint3(114, 115, 126), uint3(126, 115, 127), uint3(115, 116, 127), uint3(127, 116, 128), uint3(116, 117, 128), uint3(128, 117, 129), uint3(117, 118, 129), uint3(129, 118, 130), uint3(118, 119, 130), uint3(130, 119, 131), uint3(120, 121, 132), uint3(132, 121, 133), uint3(121, 122, 133), uint3(133, 122, 134), uint3(122, 123, 134), uint3(134, 123, 135), uint3(123, 124, 135), uint3(135, 124, 136), uint3(124, 125, 136), uint3(136, 125, 137), uint3(125, 126, 137), uint3(137, 126, 138), uint3(126, 127, 138), uint3(138, 127, 139), uint3(127, 128, 139), uint3(139, 128, 140), uint3(128, 129, 140), uint3(140, 129, 141), uint3(129, 130, 141), uint3(141, 130, 142), uint3(130, 131, 142), uint3(142, 131, 143)}; + + +[numthreads(MESH_GROUP_SIZE, 1, 1)] +[outputtopology("triangle")] +[shader("mesh")] +void meshMain( + in uint threadID: SV_GroupThreadID, + in uint groupID: SV_GroupID, + in payload WaterPayload params, + out vertices WaterVertex vertices[TILE_VERTS], + out indices uint3 indices[TILE_PRIMS], +) { + float4x4 vp = mul(pViewParams.projectionMatrix, pViewParams.viewMatrix); + SetMeshOutputCounts(TILE_VERTS, TILE_PRIMS); + + for(uint i = threadID; i < TILE_PRIMS; i += MESH_GROUP_SIZE) + { + indices[i] = IND[i]; + } + for(uint i = threadID; i < TILE_VERTS; i += MESH_GROUP_SIZE) + { + float2 base = VERT[i]; + float2 worldTransformed = params.offset + (params.extent * base); + float3 worldPos = float3(worldTransformed.x, params.height, worldTransformed.y); + float3 displacement1 = pWaterMaterial.displacementTextures.Sample(pWaterMaterial.sampler, float3(worldPos.xz, 0)).xyz; + float3 displacement2 = pWaterMaterial.displacementTextures.Sample(pWaterMaterial.sampler, float3(worldPos.xz, 1)).xyz; + float3 displacement3 = pWaterMaterial.displacementTextures.Sample(pWaterMaterial.sampler, float3(worldPos.xz, 2)).xyz; + float3 displacement4 = pWaterMaterial.displacementTextures.Sample(pWaterMaterial.sampler, float3(worldPos.xz, 3)).xyz; + float3 displacement = displacement1 + displacement2 + displacement3 + displacement4; + + float4 clipPos = mul(vp, float4(worldPos, 1)); + float depth = 1 - clamp(1 / (clipPos.z / clipPos.w), 0, 1); + + displacement = lerp(0, displacement, pow(saturate(depth), pWaterMaterial.displacementDepthAttenuation)); + + worldPos += displacement; + + WaterVertex v; + v.position_WS = worldPos; + v.position_CS = clipPos;// mul(vp, float4(worldPos, 1)); + v.texCoord = worldPos.xz; + v.depth = clipPos.z / clipPos.w; + vertices[i] = v; + } +} \ No newline at end of file diff --git a/res/shaders/WaterPass.slang b/res/shaders/WaterPass.slang index e69de29..99daf85 100644 --- a/res/shaders/WaterPass.slang +++ b/res/shaders/WaterPass.slang @@ -0,0 +1,103 @@ +import Common; +import WaterCommon; + +float SchlickFresnel(float3 normal, float3 viewDir) { + // 0.02f comes from the reflectivity bias of water kinda idk it's from a paper somewhere i'm not gonna link it tho lmaooo + return 0.02f + (1 - 0.02f) * (pow(1 - clamp(dot(normal, viewDir), 0, 1), 5.0f)); +} + +float SmithMaskingBeckmann(float3 H, float3 S, float roughness) { + float hdots = max(0.001f, clamp(dot(H, S), 0, 1)); + float a = hdots / (roughness * sqrt(1 - hdots * hdots)); + float a2 = a * a; + + return a < 1.6f ? (1.0f - 1.259f * a + 0.396f * a2) / (3.535f * a + 2.181 * a2) : 0.0f; +} + +float Beckmann(float ndoth, float roughness) { + float exp_arg = (ndoth * ndoth - 1) / (roughness * roughness * ndoth * ndoth); + + return exp(exp_arg) / (PI * roughness * roughness * ndoth * ndoth * ndoth * ndoth); +} + +[shader("pixel")] +float4 main(WaterVertex vert) : SV_TARGET { + float3 lightDir = -normalize(pWaterMaterial.sunDirection); + float3 viewDir = normalize(pViewParams.cameraPos_WS.xyz - vert.position_WS); + float3 halfwayDir = normalize(lightDir + viewDir); + float depth = vert.depth; + float LdotH = clamp(dot(lightDir, halfwayDir), 0, 1); + float VdotH = clamp(dot(viewDir, halfwayDir), 0, 1); + + + float4 displacementFoam1 = pWaterMaterial.displacementTextures.Sample(pWaterMaterial.sampler, float3(vert.texCoord, 0)); + displacementFoam1.a += pWaterMaterial.foamSubtract0; + float4 displacementFoam2 = pWaterMaterial.displacementTextures.Sample(pWaterMaterial.sampler, float3(vert.texCoord, 0)); + displacementFoam2.a += pWaterMaterial.foamSubtract1; + float4 displacementFoam3 = pWaterMaterial.displacementTextures.Sample(pWaterMaterial.sampler, float3(vert.texCoord, 0)); + displacementFoam3.a += pWaterMaterial.foamSubtract2; + float4 displacementFoam4 = pWaterMaterial.displacementTextures.Sample(pWaterMaterial.sampler, float3(vert.texCoord, 0)); + displacementFoam4.a += pWaterMaterial.foamSubtract3; + float4 displacementFoam = displacementFoam1 + displacementFoam2 + displacementFoam3 + displacementFoam4; + + float2 slopes1 = pWaterMaterial.slopeTextures.Sample(pWaterMaterial.sampler, float3(vert.texCoord, 0)); + float2 slopes2 = pWaterMaterial.slopeTextures.Sample(pWaterMaterial.sampler, float3(vert.texCoord, 1)); + float2 slopes3 = pWaterMaterial.slopeTextures.Sample(pWaterMaterial.sampler, float3(vert.texCoord, 2)); + float2 slopes4 = pWaterMaterial.slopeTextures.Sample(pWaterMaterial.sampler, float3(vert.texCoord, 3)); + float2 slopes = slopes1 + slopes2 + slopes3 + slopes4; + + slopes *= pWaterMaterial.normalStrength; + float foam = lerp(0.0f, saturate(displacementFoam.a), pow(depth, pWaterMaterial.foamDepthAttenuation)); + + float3 macroNormal = float3(0, 1, 0); + float3 mesoNormal = normalize(float3(-slopes.x, 1.0f, -slopes.y)); + mesoNormal = normalize(lerp(float3(0, 1, 0), mesoNormal, pow(saturate(depth), pWaterMaterial.normalDepthAttenuation))); + mesoNormal = normalize(mesoNormal); + + float NdotL = clamp(dot(mesoNormal, lightDir), 0, 1); + + + float a = pWaterMaterial.roughness + foam * pWaterMaterial.foamRoughnessModifier; + float ndoth = max(0.0001f, dot(mesoNormal, halfwayDir)); + + float viewMask = SmithMaskingBeckmann(halfwayDir, viewDir, a); + float lightMask = SmithMaskingBeckmann(halfwayDir, lightDir, a); + + float G = rcp(1 + viewMask + lightMask); + + float eta = 1.33f; + float R = ((eta - 1) * (eta - 1)) / ((eta + 1) * (eta + 1)); + float thetaV = acos(viewDir.y); + + float numerator = pow(1 - dot(mesoNormal, viewDir), 5 * exp(-2.69 * a)); + float F = R + (1 - R) * numerator / (1.0f + 22.7f * pow(a, 1.5f)); + F = saturate(F); + + float3 specular = pWaterMaterial.sunIrradiance * F * G * Beckmann(ndoth, a); + specular /= 4.0f * max(0.001f, clamp(dot(macroNormal, lightDir), 0, 1)); + specular *= clamp(dot(mesoNormal, lightDir), 0, 1); + + float3 envReflection = pWaterMaterial.environmentMap.Sample(pWaterMaterial.sampler, reflect(-viewDir, mesoNormal)).rgb; + envReflection *= pWaterMaterial.environmentLightStrength; + + float H = max(0.0f, displacementFoam.y) * pWaterMaterial.heightModifier; + float3 scatterColor = pWaterMaterial.scatterColor; + float3 bubbleColor = pWaterMaterial.bubbleColor; + float bubbleDensity = pWaterMaterial.bubbleDensity; + + + float k1 = pWaterMaterial.wavePeakScatterStrength * H * pow(clamp(dot(lightDir, -viewDir), 0, 1), 4.0f) * pow(0.5f - 0.5f * dot(lightDir, mesoNormal), 3.0f); + float k2 = pWaterMaterial.scatterStrength * pow(clamp(dot(viewDir, mesoNormal), 0, 1), 2.0f); + float k3 = pWaterMaterial.scatterShadowStrength * NdotL; + float k4 = bubbleDensity; + + float3 scatter = (k1 + k2) * scatterColor * pWaterMaterial.sunIrradiance * rcp(1 + lightMask); + scatter += k3 * scatterColor * pWaterMaterial.sunIrradiance + k4 * bubbleColor * pWaterMaterial.sunIrradiance; + + + float3 output = (1 - F) * scatter + specular + F * envReflection; + output = max(0.0f, output); + output = lerp(output, pWaterMaterial.foamColor, saturate(foam)); + + return float4(output, 1.0f); +} diff --git a/res/shaders/WaterTask.slang b/res/shaders/WaterTask.slang index e69de29..cc38ad4 100644 --- a/res/shaders/WaterTask.slang +++ b/res/shaders/WaterTask.slang @@ -0,0 +1,15 @@ +import Common; +import Scene; +import WaterCommon; + +groupshared WaterPayload p; + +[numthreads(1, 1, 1)] +[shader("amplification")] +void taskMain( + uint threadID: SV_GroupThreadID, + uint groupID: SV_GroupID, ) +{ + p = pWaterMaterial.tiles[groupID]; + DispatchMesh(1, 1, 1, p); +} diff --git a/res/shaders/lib/Common.slang b/res/shaders/lib/Common.slang index d69664e..9a6d749 100644 --- a/res/shaders/lib/Common.slang +++ b/res/shaders/lib/Common.slang @@ -1,6 +1,8 @@ const static float PI = 3.1415926535897932f; const static uint BLOCK_SIZE = 32; static const uint64_t MAX_TEXCOORDS = 8; +static const uint32_t TASK_GROUP_SIZE = 32; +static const uint32_t MESH_GROUP_SIZE = 32; struct ViewParameter { diff --git a/res/shaders/lib/Scene.slang b/res/shaders/lib/Scene.slang index 4126b3a..4eefe2a 100644 --- a/res/shaders/lib/Scene.slang +++ b/res/shaders/lib/Scene.slang @@ -22,8 +22,6 @@ struct MeshData static const uint32_t MAX_VERTICES = 256; static const uint32_t MAX_PRIMITIVES = 256; -static const uint32_t TASK_GROUP_SIZE = 32; -static const uint32_t MESH_GROUP_SIZE = 32; static const uint32_t MAX_MESHLETS_PER_INSTANCE = 2048; struct InstanceData diff --git a/src/Benchmark/PlayView.cpp b/src/Benchmark/PlayView.cpp index e71b2f0..a47ec06 100644 --- a/src/Benchmark/PlayView.cpp +++ b/src/Benchmark/PlayView.cpp @@ -15,41 +15,52 @@ PlayView::PlayView(Gfx::PGraphics graphics, PWindow window, const ViewportCreate Gfx::PPipelineStatisticsQuery baseQuery = res->requestQuery("BASEPASS_QUERY"); Gfx::PPipelineStatisticsQuery lightCullQuery = res->requestQuery("LIGHTCULL_QUERY"); Gfx::PPipelineStatisticsQuery visibilityQuery = res->requestQuery("VISIBILITY_QUERY"); - Gfx::PTimestampQuery timeQuery = res->requestTimestampQuery("TIMESTAMP"); + Gfx::PTimestampQuery cachedTS = res->requestTimestampQuery("CACHED_TS"); + Gfx::PTimestampQuery depthTS = res->requestTimestampQuery("DEPTH_TS"); + Gfx::PTimestampQuery lightCullTS = res->requestTimestampQuery("LIGHTCULL_TS"); + Gfx::PTimestampQuery visibilityTS = res->requestTimestampQuery("VISIBILITY_TS"); + Gfx::PTimestampQuery baseTS = res->requestTimestampQuery("BASE_TS"); std::ofstream stats(fmt::format("stats{}.csv", useMeshCulling ? "" : "NOCULL")); - stats << std::fixed << std::setprecision(0); stats << "RelTime," - << "CachedIAV,CachedIAP,CachedVS,CachedClipInv,CachedClipPrim,CachedFS,CachedCS,CachedTS,CachedMS," - << "DepthIAV,DepthIAP,DepthVS,DepthClipInv,DepthClipPrim,DepthFS,DepthCS,DepthTS,DepthMS," - << "BaseIAV,BaseIAP,BaseVS,BaseClipInv,BaseClipPrim,BaseFS,BaseCS,BaseTS,BaseMS," - << "LightCullIAV,LightCullIAP,LightCullVS,LightCullClipInv,LightCullClipPrim,LightCullFS,LightCullCS,LightCullTS,LightCullMS," - << "VisibilityIAV,VisibilityIAP,VisibilityVS,VisibilityClipInv,VisibilityClipPrim,VisibilityFS,VisibilityCS,VisibilityTS," - "VisibilityMS," - << "CACHED,MIPGEN,DEPTHCULL,VISIBILITY,LIGHTCULL,BASE,FrameTime" << std::endl; - float start = 0; + << "CACHED,MIPGEN,DEPTHCULL,VISIBILITY,LIGHTCULL,BASE,FrameTime," + << "CachedIAV,CachedIAP,CachedVS,CachedClipInv,CachedClipPrim,CachedFS,CachedCS," + << "DepthIAV,DepthIAP,DepthVS,DepthClipInv,DepthClipPrim,DepthFS,DepthCS," + << "BaseIAV,BaseIAP,BaseVS,BaseClipInv,BaseClipPrim,BaseFS,BaseCS," + << "LightCullIAV,LightCullIAP,LightCullVS,LightCullClipInv,LightCullClipPrim,LightCullFS,LightCullCS," + << "VisibilityIAV,VisibilityIAP,VisibilityVS,VisibilityClipInv,VisibilityClipPrim,VisibilityFS,VisibilityCS" << std::endl; + uint64 start = 0; + uint64 prevBegin = 0; std::this_thread::sleep_for(std::chrono::milliseconds(500)); + stats << std::fixed << std::setprecision(0); while (getGlobals().running) { - auto timestamps = timeQuery->getResults(); + auto cached = cachedTS->getResults(); + auto depth = depthTS->getResults(); + auto lightCull = lightCullTS->getResults(); + auto visibility = visibilityTS->getResults(); + auto base = baseTS->getResults(); auto cachedResults = cachedQuery->getResults(); auto depthResults = depthQuery->getResults(); auto baseResults = baseQuery->getResults(); auto lightCullResults = lightCullQuery->getResults(); auto visiblityResults = visibilityQuery->getResults(); if (start == 0) { - start = timestamps[0].time; + start = cached[0].time; } - uint64 t0 = timestamps[0].time; - uint64 t1 = timestamps[1].time; - uint64 t2 = timestamps[2].time; - uint64 t3 = timestamps[3].time; - uint64 t4 = timestamps[4].time; - uint64 t5 = timestamps[5].time; - uint64 t6 = timestamps[6].time; - if (t1 < t0 || t2 < t1 || t3 < t2 || t4 < t3 || t5 < t4 || t6 < t5) - continue; - stats << t0 - start << "," << cachedResults << depthResults << baseResults << lightCullResults << visiblityResults << t1 - t0 - << "," << t2 - t1 << "," << t3 - t2 << "," << t4 - t3 << "," << t5 - t4 << "," << t6 - t5 << "," << t6 - t0 << std::endl; + int64 relTime = cached[0].time - start; + int64 cachedTime = cached[1].time - cached[0].time; + int64 mipTime = depth[1].time - depth[0].time; + int64 depthTime = depth[2].time - depth[0].time; + int64 baseTime = base[1].time - base[0].time; + int64 lightCullTime = lightCull[1].time - lightCull[0].time; + int64 visibilityTime = visibility[1].time - visibility[0].time; + int64 frameTime = cachedTime + mipTime + depthTime + baseTime + lightCullTime + visibilityTime; + + stats << relTime << "," << cachedTime << "," << mipTime << "," << depthTime << "," + << visibilityTime + << "," << lightCullTime << "," << baseTime << "," + << frameTime << "," << cachedResults << depthResults << baseResults << lightCullResults << visiblityResults << std::endl; stats.flush(); + // std::cout << "Writing " << timestamps[0].time << std::endl; } }); } diff --git a/src/Editor/main.cpp b/src/Editor/main.cpp index e90649b..acf907a 100644 --- a/src/Editor/main.cpp +++ b/src/Editor/main.cpp @@ -64,10 +64,10 @@ int main() { .filePath = sourcePath / "import/textures/skyboxsun5deg_tn.jpg", .type = TextureImportType::TEXTURE_CUBEMAP, }); - AssetImporter::importMesh(MeshImportArgs{ - .filePath = sourcePath / "import/models/after-the-rain-vr-sound/source/Whitechapel.glb", - .importPath = "Whitechapel", - }); + //ssetImporter::importMesh(MeshImportArgs{ + // .filePath = sourcePath / "import/models/after-the-rain-vr-sound/source/Whitechapel.glb", + // .importPath = "Whitechapel", + //); // AssetImporter::importMesh(MeshImportArgs{ // .filePath = sourcePath / "import/models/city-suburbs/source/city-suburbs.obj", // .importPath = "suburbs", diff --git a/src/Engine/Asset/FontAsset.cpp b/src/Engine/Asset/FontAsset.cpp index 3614d76..dcc65f8 100644 --- a/src/Engine/Asset/FontAsset.cpp +++ b/src/Engine/Asset/FontAsset.cpp @@ -86,9 +86,9 @@ void FontAsset::load(ArchiveBuffer& buffer) { .width = kTexture->baseWidth, .height = kTexture->baseHeight, .depth = kTexture->baseDepth, - .mipLevels = kTexture->numLevels, .layers = kTexture->numFaces, .elements = kTexture->numLayers, + .useMip = true, .usage = Gfx::SE_IMAGE_USAGE_SAMPLED_BIT, }; diff --git a/src/Engine/Asset/TextureAsset.cpp b/src/Engine/Asset/TextureAsset.cpp index 492acc0..6517525 100644 --- a/src/Engine/Asset/TextureAsset.cpp +++ b/src/Engine/Asset/TextureAsset.cpp @@ -47,9 +47,9 @@ void TextureAsset::load(ArchiveBuffer& buffer) { .width = ktxHandle->baseWidth, .height = ktxHandle->baseHeight, .depth = ktxHandle->baseDepth, - .mipLevels = ktxHandle->numLevels, .layers = ktxHandle->numFaces, .elements = ktxHandle->numLayers, + .useMip = true, .usage = Gfx::SE_IMAGE_USAGE_SAMPLED_BIT, .name = name, }; diff --git a/src/Engine/Component/CMakeLists.txt b/src/Engine/Component/CMakeLists.txt index 14f6240..6e03346 100644 --- a/src/Engine/Component/CMakeLists.txt +++ b/src/Engine/Component/CMakeLists.txt @@ -17,7 +17,8 @@ target_sources(Engine Skybox.h SphereCollider.h Transform.h - Transform.cpp) + Transform.cpp + WaterTile.h) target_sources(Engine @@ -36,4 +37,5 @@ target_sources(Engine ShapeBase.h Skybox.h SphereCollider.h - Transform.h) \ No newline at end of file + Transform.h + WaterTile.h) \ No newline at end of file diff --git a/src/Engine/Component/WaterTile.h b/src/Engine/Component/WaterTile.h new file mode 100644 index 0000000..bb4582c --- /dev/null +++ b/src/Engine/Component/WaterTile.h @@ -0,0 +1,15 @@ +#pragma once +#include "MinimalEngine.h" +#include "Math/Vector.h" + +namespace Seele { +namespace Component +{ +struct WaterTile +{ + IVector2 location; + float height; + constexpr static float DIMENSIONS = 100; +}; +} +} \ No newline at end of file diff --git a/src/Engine/Graphics/Enums.h b/src/Engine/Graphics/Enums.h index aabceac..b900614 100644 --- a/src/Engine/Graphics/Enums.h +++ b/src/Engine/Graphics/Enums.h @@ -159,10 +159,10 @@ static constexpr bool useAsyncCompute = false; static constexpr bool useMeshShading = true; static constexpr uint32 numFramesBuffered = 3; -// meshlet dimensions curated by NVIDIA static constexpr uint32 numVerticesPerMeshlet = 256; static constexpr uint32 numPrimitivesPerMeshlet = 256; double getCurrentFrameDelta(); +double getCurrentFrameTime(); uint32 getCurrentFrameIndex(); enum class QueueType { diff --git a/src/Engine/Graphics/Graphics.h b/src/Engine/Graphics/Graphics.h index 63b7a0f..efd9b86 100644 --- a/src/Engine/Graphics/Graphics.h +++ b/src/Engine/Graphics/Graphics.h @@ -62,6 +62,7 @@ class Graphics { virtual void waitDeviceIdle() = 0; virtual void executeCommands(Array commands) = 0; + virtual void executeCommands(OComputeCommand commands) = 0; virtual void executeCommands(Array commands) = 0; virtual OTexture2D createTexture2D(const TextureCreateInfo& createInfo) = 0; diff --git a/src/Engine/Graphics/Initializer.h b/src/Engine/Graphics/Initializer.h index 4cffa8e..4277b8e 100644 --- a/src/Engine/Graphics/Initializer.h +++ b/src/Engine/Graphics/Initializer.h @@ -50,10 +50,10 @@ struct TextureCreateInfo { uint32 width = 1; uint32 height = 1; uint32 depth = 1; - uint32 mipLevels = 1; uint32 layers = 1; uint32 elements = 1; uint32 samples = 1; + bool useMip = false; Gfx::SeImageUsageFlags usage = Gfx::SE_IMAGE_USAGE_SAMPLED_BIT; Gfx::SeMemoryPropertyFlags memoryProps = Gfx::SE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; std::string name; @@ -111,6 +111,7 @@ struct ShaderCompilationInfo { Array> typeParameter; Map defines; Gfx::PPipelineLayout rootSignature; + bool dumpIntermediate = false; }; struct ShaderCreateInfo { uint32 entryPointIndex; diff --git a/src/Engine/Graphics/RenderPass/BasePass.cpp b/src/Engine/Graphics/RenderPass/BasePass.cpp index f61b7f2..ffd831c 100644 --- a/src/Engine/Graphics/RenderPass/BasePass.cpp +++ b/src/Engine/Graphics/RenderPass/BasePass.cpp @@ -3,6 +3,7 @@ #include "Asset/AssetRegistry.h" #include "Component/Camera.h" #include "Component/Mesh.h" +#include "Component/WaterTile.h" #include "Graphics/Command.h" #include "Graphics/Descriptor.h" #include "Graphics/Enums.h" @@ -25,6 +26,7 @@ void Seele::addDebugVertex(DebugVertex vert) { gDebugVertices.add(vert); } void Seele::addDebugVertices(Array verts) { gDebugVertices.addAll(verts); } BasePass::BasePass(Gfx::PGraphics graphics, PScene scene) : RenderPass(graphics, scene) { + waterRenderer = new WaterRenderer(graphics, scene, viewParamsLayout); basePassLayout = graphics->createPipelineLayout("BasePassLayout"); basePassLayout->addDescriptorLayout(viewParamsLayout); @@ -96,37 +98,42 @@ void BasePass::beginFrame(const Component::Camera& cam) { opaqueCulling = lightCullingLayout->allocateDescriptorSet(); transparentCulling = lightCullingLayout->allocateDescriptorSet(); - // Debug vertices - VertexBufferCreateInfo vertexBufferInfo = { - .sourceData = - { - .size = sizeof(DebugVertex) * gDebugVertices.size(), - .data = (uint8*)gDebugVertices.data(), - }, - .vertexSize = sizeof(DebugVertex), - .numVertices = (uint32)gDebugVertices.size(), - .name = "DebugVertices", - }; - debugVertices = graphics->createVertexBuffer(vertexBufferInfo); - debugVertices->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, - Gfx::SE_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, Gfx::SE_PIPELINE_STAGE_VERTEX_INPUT_BIT); + waterRenderer->beginFrame(); + // Debug vertices + { + VertexBufferCreateInfo vertexBufferInfo = { + .sourceData = + { + .size = sizeof(DebugVertex) * gDebugVertices.size(), + .data = (uint8*)gDebugVertices.data(), + }, + .vertexSize = sizeof(DebugVertex), + .numVertices = (uint32)gDebugVertices.size(), + .name = "DebugVertices", + }; + debugVertices = graphics->createVertexBuffer(vertexBufferInfo); + debugVertices->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, + Gfx::SE_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, Gfx::SE_PIPELINE_STAGE_VERTEX_INPUT_BIT); + } // Skybox - skyboxDataLayout->reset(); - textureLayout->reset(); - skyboxData.transformMatrix = glm::rotate(skyboxData.transformMatrix, (float)(Gfx::getCurrentFrameDelta()), Vector(0, 1, 0)); - skyboxBuffer->rotateBuffer(sizeof(SkyboxData)); - skyboxBuffer->updateContents(0, sizeof(SkyboxData), &skyboxData); - skyboxBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, Gfx::SE_ACCESS_UNIFORM_READ_BIT, - Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - skyboxDataSet = skyboxDataLayout->allocateDescriptorSet(); - skyboxDataSet->updateBuffer(0, skyboxBuffer); - skyboxDataSet->writeChanges(); - textureSet = textureLayout->allocateDescriptorSet(); - textureSet->updateTexture(0, skybox.day); - textureSet->updateTexture(1, skybox.night); - textureSet->updateSampler(2, skyboxSampler); - textureSet->writeChanges(); + { + skyboxDataLayout->reset(); + textureLayout->reset(); + skyboxData.transformMatrix = glm::rotate(skyboxData.transformMatrix, (float)(Gfx::getCurrentFrameDelta()), Vector(0, 1, 0)); + skyboxBuffer->rotateBuffer(sizeof(SkyboxData)); + skyboxBuffer->updateContents(0, sizeof(SkyboxData), &skyboxData); + skyboxBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, + Gfx::SE_ACCESS_UNIFORM_READ_BIT, Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + skyboxDataSet = skyboxDataLayout->allocateDescriptorSet(); + skyboxDataSet->updateBuffer(0, skyboxBuffer); + skyboxDataSet->writeChanges(); + textureSet = textureLayout->allocateDescriptorSet(); + textureSet->updateTexture(0, skybox.day); + textureSet->updateTexture(1, skybox.night); + textureSet->updateSampler(2, skyboxSampler); + textureSet->writeChanges(); + } } void BasePass::render() { @@ -138,13 +145,15 @@ void BasePass::render() { transparentCulling->writeChanges(); query->beginQuery(); - timestamps->write(Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, "BASEPASS"); + timestamps->begin(); + timestamps->write(Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, "BaseBegin"); graphics->beginRenderPass(renderPass); Array commands; Gfx::ShaderPermutation permutation = graphics->getShaderCompiler()->getTemplate("BasePass"); permutation.setDepthCulling(true); // always use the culling info permutation.setPositionOnly(false); Array transparentData; + // Base Rendering for (VertexData* vertexData : VertexData::getList()) { transparentData.addAll(vertexData->getTransparentData()); vertexData->getInstanceDataSet()->updateBuffer(6, cullingBuffer); @@ -238,14 +247,18 @@ void BasePass::render() { commands.add(std::move(command)); } } - - Gfx::ORenderCommand skyboxCommand = graphics->createRenderCommand("SkyboxRender"); - skyboxCommand->setViewport(viewport); - skyboxCommand->bindPipeline(pipeline); - skyboxCommand->bindDescriptor({viewParamsSet, skyboxDataSet, textureSet}); - skyboxCommand->draw(36, 1, 0, 0); - commands.add(std::move(skyboxCommand)); - + + commands.add(waterRenderer->render(viewParamsSet)); + + // Skybox + { + Gfx::ORenderCommand skyboxCommand = graphics->createRenderCommand("SkyboxRender"); + skyboxCommand->setViewport(viewport); + skyboxCommand->bindPipeline(pipeline); + skyboxCommand->bindDescriptor({viewParamsSet, skyboxDataSet, textureSet}); + skyboxCommand->draw(36, 1, 0, 0); + commands.add(std::move(skyboxCommand)); + } // Transparent rendering { permutation.setDepthCulling(false); // ignore visibility infos for transparency @@ -360,7 +373,7 @@ void BasePass::render() { graphics->executeCommands(std::move(commands)); graphics->endRenderPass(); query->endQuery(); - timestamps->write(Gfx::SE_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, "END"); + timestamps->write(Gfx::SE_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, "BaseEnd"); timestamps->end(); gDebugVertices.clear(); } @@ -412,12 +425,13 @@ void BasePass::publishOutputs() { resources->registerRenderPassOutput("BASEPASS_COLOR", colorAttachment); resources->registerRenderPassOutput("BASEPASS_DEPTH", depthAttachment); + timestamps = graphics->createTimestampQuery(2, "BaseTS"); + resources->registerTimestampQueryOutput("BASE_TS", timestamps); query = graphics->createPipelineStatisticsQuery("BasePassPipelineStatistics"); resources->registerQueryOutput("BASEPASS_QUERY", query); } void BasePass::createRenderPass() { - timestamps = resources->requestTimestampQuery("TIMESTAMP"); cullingBuffer = resources->requestBuffer("CULLINGBUFFER"); Gfx::RenderTargetLayout layout = Gfx::RenderTargetLayout{ @@ -458,6 +472,8 @@ void BasePass::createRenderPass() { oLightGrid = resources->requestTexture("LIGHTCULLING_OLIGHTGRID"); tLightGrid = resources->requestTexture("LIGHTCULLING_TLIGHTGRID"); + waterRenderer->setViewport(viewport, renderPass); + // Debug rendering { debugPipelineLayout = graphics->createPipelineLayout("DebugPassLayout"); @@ -527,7 +543,6 @@ void BasePass::createRenderPass() { }; debugPipeline = graphics->createGraphicsPipeline(std::move(gfxInfo)); } - // Skybox { skyboxDataLayout = graphics->createDescriptorLayout("pSkyboxData"); diff --git a/src/Engine/Graphics/RenderPass/BasePass.h b/src/Engine/Graphics/RenderPass/BasePass.h index 101b3f7..e2123c6 100644 --- a/src/Engine/Graphics/RenderPass/BasePass.h +++ b/src/Engine/Graphics/RenderPass/BasePass.h @@ -1,6 +1,7 @@ #pragma once #include "MinimalEngine.h" #include "RenderPass.h" +#include "WaterRenderer.h" namespace Seele { DECLARE_REF(CameraActor) @@ -44,10 +45,12 @@ class BasePass : public RenderPass { Gfx::ODescriptorLayout lightCullingLayout; Gfx::OPipelineStatisticsQuery query; - Gfx::PTimestampQuery timestamps; + Gfx::OTimestampQuery timestamps; Gfx::PShaderBuffer cullingBuffer; + OWaterRenderer waterRenderer; + // Debug rendering Gfx::OVertexInput debugVertexInput; Gfx::OVertexBuffer debugVertices; diff --git a/src/Engine/Graphics/RenderPass/CMakeLists.txt b/src/Engine/Graphics/RenderPass/CMakeLists.txt index c7dc368..34904c2 100644 --- a/src/Engine/Graphics/RenderPass/CMakeLists.txt +++ b/src/Engine/Graphics/RenderPass/CMakeLists.txt @@ -20,7 +20,9 @@ target_sources(Engine UIPass.h UIPass.cpp VisibilityPass.h - VisibilityPass.cpp) + VisibilityPass.cpp + WaterRenderer.h + WaterRenderer.cpp) target_sources(Engine PUBLIC FILE_SET HEADERS diff --git a/src/Engine/Graphics/RenderPass/CachedDepthPass.cpp b/src/Engine/Graphics/RenderPass/CachedDepthPass.cpp index 75ee601..ac7b6df 100644 --- a/src/Engine/Graphics/RenderPass/CachedDepthPass.cpp +++ b/src/Engine/Graphics/RenderPass/CachedDepthPass.cpp @@ -47,13 +47,13 @@ void CachedDepthPass::beginFrame(const Component::Camera& cam) { void CachedDepthPass::render() { query->beginQuery(); timestamps->begin(); - timestamps->write(Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, "CACHED"); + timestamps->write(Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, "CachedBegin"); graphics->beginRenderPass(renderPass); Array commands; Gfx::ShaderPermutation permutation = graphics->getShaderCompiler()->getTemplate("CachedDepthPass"); permutation.setPositionOnly(getGlobals().usePositionOnly); - permutation.setDepthCulling(getGlobals().useDepthCulling); + permutation.setDepthCulling(true); for (VertexData* vertexData : VertexData::getList()) { permutation.setVertexData(vertexData->getTypeName()); vertexData->getInstanceDataSet()->updateBuffer(6, cullingBuffer); @@ -127,6 +127,8 @@ void CachedDepthPass::render() { graphics->executeCommands(std::move(commands)); graphics->endRenderPass(); + timestamps->write(Gfx::SE_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, "CachedEnd"); + timestamps->end(); query->endQuery(); } @@ -161,8 +163,8 @@ void CachedDepthPass::publishOutputs() { query = graphics->createPipelineStatisticsQuery("CachedPipelineStatistics"); resources->registerQueryOutput("CACHED_QUERY", query); - timestamps = graphics->createTimestampQuery(7, "Timestamps"); - resources->registerTimestampQueryOutput("TIMESTAMP", timestamps); + timestamps = graphics->createTimestampQuery(2, "CachedTS"); + resources->registerTimestampQueryOutput("CACHED_TS", timestamps); } void CachedDepthPass::createRenderPass() { diff --git a/src/Engine/Graphics/RenderPass/DepthCullingPass.cpp b/src/Engine/Graphics/RenderPass/DepthCullingPass.cpp index fc91f06..2ac33e5 100644 --- a/src/Engine/Graphics/RenderPass/DepthCullingPass.cpp +++ b/src/Engine/Graphics/RenderPass/DepthCullingPass.cpp @@ -78,7 +78,8 @@ void DepthCullingPass::render() { set->updateBuffer(1, depthMipBuffer); set->writeChanges(); - timestamps->write(Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, "DEPTHMIP"); + timestamps->begin(); + timestamps->write(Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, "MipBegin"); Gfx::OComputeCommand computeCommand = graphics->createComputeCommand("DepthMipGenCommand"); computeCommand->bindPipeline(depthInitialReduce); computeCommand->bindDescriptor({viewParamsSet, set}); @@ -115,7 +116,7 @@ void DepthCullingPass::render() { Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT); - timestamps->write(Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, "DEPTHCULL"); + timestamps->write(Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, "CullingBegin"); graphics->beginRenderPass(renderPass); Array commands; @@ -194,6 +195,8 @@ void DepthCullingPass::render() { graphics->executeCommands(std::move(commands)); graphics->endRenderPass(); + timestamps->write(Gfx::SE_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, "CullingEnd"); + timestamps->end(); query->endQuery(); // Sync depth read/write with compute read depthAttachment.getTexture()->pipelineBarrier( @@ -251,12 +254,13 @@ void DepthCullingPass::publishOutputs() { depthMipGen = graphics->createComputePipeline(pipelineCreateInfo); + timestamps = graphics->createTimestampQuery(3, "CullingTS"); + resources->registerTimestampQueryOutput("DEPTH_TS", timestamps); query = graphics->createPipelineStatisticsQuery("DepthPipelineStatistics"); resources->registerQueryOutput("DEPTH_QUERY", query); } void DepthCullingPass::createRenderPass() { - timestamps = resources->requestTimestampQuery("TIMESTAMP"); cullingBuffer = resources->requestBuffer("CULLINGBUFFER"); depthAttachment = resources->requestRenderTarget("DEPTHPREPASS_DEPTH"); diff --git a/src/Engine/Graphics/RenderPass/DepthCullingPass.h b/src/Engine/Graphics/RenderPass/DepthCullingPass.h index 03f61d2..b9407f7 100644 --- a/src/Engine/Graphics/RenderPass/DepthCullingPass.h +++ b/src/Engine/Graphics/RenderPass/DepthCullingPass.h @@ -33,7 +33,7 @@ class DepthCullingPass : public RenderPass { Gfx::ODescriptorLayout depthAttachmentLayout; Gfx::OPipelineLayout depthCullingLayout; Gfx::OPipelineStatisticsQuery query; - Gfx::PTimestampQuery timestamps; + Gfx::OTimestampQuery timestamps; Gfx::OPipelineLayout depthComputeLayout; Gfx::OComputeShader depthInitialReduceShader; diff --git a/src/Engine/Graphics/RenderPass/LightCullingPass.cpp b/src/Engine/Graphics/RenderPass/LightCullingPass.cpp index 8b5f050..1ccbc51 100644 --- a/src/Engine/Graphics/RenderPass/LightCullingPass.cpp +++ b/src/Engine/Graphics/RenderPass/LightCullingPass.cpp @@ -37,7 +37,8 @@ void LightCullingPass::beginFrame(const Component::Camera& cam) { void LightCullingPass::render() { query->beginQuery(); - timestamps->write(Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, "LIGHTCULL"); + timestamps->begin(); + timestamps->write(Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, "LightCullBegin"); oLightGrid->pipelineBarrier(Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT); tLightGrid->pipelineBarrier(Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, Gfx::SE_ACCESS_SHADER_WRITE_BIT, @@ -62,6 +63,8 @@ void LightCullingPass::render() { commands.add(std::move(computeCommand)); // std::cout << "Execute" << std::endl; graphics->executeCommands(std::move(commands)); + timestamps->write(Gfx::SE_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, "LightCullEnd"); + timestamps->end(); query->endQuery(); oLightIndexList->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); @@ -224,13 +227,14 @@ void LightCullingPass::publishOutputs() { resources->registerTextureOutput("LIGHTCULLING_OLIGHTGRID", Gfx::PTexture2D(oLightGrid)); resources->registerTextureOutput("LIGHTCULLING_TLIGHTGRID", Gfx::PTexture2D(tLightGrid)); + timestamps = graphics->createTimestampQuery(2, "LightCullTS"); + resources->registerTimestampQueryOutput("LIGHTCULL_TS", timestamps); query = graphics->createPipelineStatisticsQuery("LightCullPipelineStatistics"); resources->registerQueryOutput("LIGHTCULL_QUERY", query); } void LightCullingPass::createRenderPass() { depthAttachment = resources->requestRenderTarget("DEPTHPREPASS_DEPTH").getTexture(); - timestamps = resources->requestTimestampQuery("TIMESTAMP"); } void LightCullingPass::setupFrustums() { diff --git a/src/Engine/Graphics/RenderPass/LightCullingPass.h b/src/Engine/Graphics/RenderPass/LightCullingPass.h index 191c38f..0277e64 100644 --- a/src/Engine/Graphics/RenderPass/LightCullingPass.h +++ b/src/Engine/Graphics/RenderPass/LightCullingPass.h @@ -64,7 +64,7 @@ class LightCullingPass : public RenderPass { Gfx::PComputePipeline cullingPipeline; Gfx::PComputePipeline cullingEnabledPipeline; Gfx::OPipelineStatisticsQuery query; - Gfx::PTimestampQuery timestamps; + Gfx::OTimestampQuery timestamps; }; DEFINE_REF(LightCullingPass) } // namespace Seele diff --git a/src/Engine/Graphics/RenderPass/VisibilityPass.cpp b/src/Engine/Graphics/RenderPass/VisibilityPass.cpp index bcdf919..e73481e 100644 --- a/src/Engine/Graphics/RenderPass/VisibilityPass.cpp +++ b/src/Engine/Graphics/RenderPass/VisibilityPass.cpp @@ -26,7 +26,8 @@ void VisibilityPass::render() { visibilitySet->writeChanges(); query->beginQuery(); - timestamps->write(Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, "VISIBILITY"); + timestamps->begin(); + timestamps->write(Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, "VisibilityBegin"); Gfx::OComputeCommand command = graphics->createComputeCommand("VisibilityCommand"); command->bindPipeline(visibilityPipeline); command->bindDescriptor({viewParamsSet, visibilitySet}); @@ -34,6 +35,8 @@ void VisibilityPass::render() { Array commands; commands.add(std::move(command)); graphics->executeCommands(std::move(commands)); + timestamps->write(Gfx::SE_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, "VisibilityEnd"); + timestamps->end(); query->endQuery(); cullingBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, Gfx::SE_ACCESS_SHADER_READ_BIT, @@ -85,8 +88,10 @@ void VisibilityPass::publishOutputs() { }); resources->registerBufferOutput("CULLINGBUFFER", cullingBuffer); + timestamps = graphics->createTimestampQuery(2, "VisibilityTS"); + resources->registerTimestampQueryOutput("VISIBILITY_TS", timestamps); + query = graphics->createPipelineStatisticsQuery("VisibilityPipelineStatistics"); - timestamps = resources->requestTimestampQuery("TIMESTAMP"); resources->registerQueryOutput("VISIBILITY_QUERY", query); } diff --git a/src/Engine/Graphics/RenderPass/VisibilityPass.h b/src/Engine/Graphics/RenderPass/VisibilityPass.h index 75c681e..43f0eff 100644 --- a/src/Engine/Graphics/RenderPass/VisibilityPass.h +++ b/src/Engine/Graphics/RenderPass/VisibilityPass.h @@ -24,7 +24,7 @@ class VisibilityPass : public RenderPass { Gfx::OComputeShader visibilityShader; Gfx::PComputePipeline visibilityPipeline; Gfx::OPipelineStatisticsQuery query; - Gfx::PTimestampQuery timestamps; + Gfx::OTimestampQuery timestamps; // Holds culling information for every meshlet for each instance Gfx::OShaderBuffer cullingBuffer; diff --git a/src/Engine/Graphics/RenderPass/WaterRenderer.cpp b/src/Engine/Graphics/RenderPass/WaterRenderer.cpp new file mode 100644 index 0000000..8884769 --- /dev/null +++ b/src/Engine/Graphics/RenderPass/WaterRenderer.cpp @@ -0,0 +1,474 @@ +#include "WaterRenderer.h" +#include "Asset/AssetRegistry.h" +#include "Component/WaterTile.h" +#include "Graphics/Graphics.h" +#include "Graphics/Shader.h" + +using namespace Seele; + +WaterRenderer::WaterRenderer(Gfx::PGraphics graphics, PScene scene, Gfx::PDescriptorLayout viewParamsLayout) + : graphics(graphics), scene(scene) { + skyBox = AssetRegistry::findTexture("", "skyboxsun5deg_tn")->getTexture().cast(); + logN = (int)log2(params.N); + threadGroupsX = ceil(params.N / 8.0f); + threadGroupsY = ceil(params.N / 8.0f); + + materialUniforms = graphics->createUniformBuffer(UniformBufferCreateInfo{ + .sourceData = + { + .size = sizeof(MaterialParams), + .data = (uint8*)&materialParams, + }, + .dynamic = true, + .name = "WaterMaterialParams", + }); + materialUniforms->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, + Gfx::SE_ACCESS_UNIFORM_READ_BIT, + Gfx::SE_PIPELINE_STAGE_MESH_SHADER_BIT_EXT | Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + + paramsBuffer = graphics->createUniformBuffer(UniformBufferCreateInfo{ + .sourceData = + { + .size = sizeof(ComputeParams), + }, + .dynamic = true, + .name = "WaterComputeParams", + }); + paramsBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, Gfx::SE_ACCESS_UNIFORM_READ_BIT, + Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT); + + initialSpectrumTextures = graphics->createTexture2D(TextureCreateInfo{ + .format = Gfx::SE_FORMAT_R32G32B32A32_SFLOAT, + .width = params.N, + .height = params.N, + .elements = 4, + .useMip = true, + .usage = Gfx::SE_IMAGE_USAGE_STORAGE_BIT, + .name = "InitialSpectrumTextures", + }); + initialSpectrumTextures->changeLayout(Gfx::SE_IMAGE_LAYOUT_GENERAL, Gfx::SE_ACCESS_NONE, Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT, + Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT); + + boyancyData = graphics->createTexture2D(TextureCreateInfo{ + .format = Gfx::SE_FORMAT_R16_SFLOAT, + .width = params.N, + .height = params.N, + .useMip = false, + .usage = Gfx::SE_IMAGE_USAGE_STORAGE_BIT, + .name = "Bouyancy", + }); + boyancyData->changeLayout(Gfx::SE_IMAGE_LAYOUT_GENERAL, Gfx::SE_ACCESS_NONE, Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT); + + displacementTextures = graphics->createTexture2D(TextureCreateInfo{ + .format = Gfx::SE_FORMAT_R32G32B32A32_SFLOAT, + .width = params.N, + .height = params.N, + .elements = 4, + .useMip = true, + .usage = Gfx::SE_IMAGE_USAGE_STORAGE_BIT, + .name = "DisplacementTexture", + }); + displacementTextures->changeLayout(Gfx::SE_IMAGE_LAYOUT_GENERAL, Gfx::SE_ACCESS_NONE, Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT, + Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT); + + slopeTextures = graphics->createTexture2D(TextureCreateInfo{ + .format = Gfx::SE_FORMAT_R32G32_SFLOAT, + .width = params.N, + .height = params.N, + .elements = 4, + .useMip = true, + .usage = Gfx::SE_IMAGE_USAGE_STORAGE_BIT, + .name = "SlopeTextures", + }); + slopeTextures->changeLayout(Gfx::SE_IMAGE_LAYOUT_GENERAL, Gfx::SE_ACCESS_NONE, Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT, + Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT); + + spectrumTextures = graphics->createTexture2D(TextureCreateInfo{ + .format = Gfx::SE_FORMAT_R32G32B32A32_SFLOAT, + .width = params.N, + .height = params.N, + .elements = 8, + .useMip = true, + .usage = Gfx::SE_IMAGE_USAGE_STORAGE_BIT, + .name = "SpectrumTextures", + }); + spectrumTextures->changeLayout(Gfx::SE_IMAGE_LAYOUT_GENERAL, Gfx::SE_ACCESS_NONE, Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT, + Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT); + + spectrumBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{ + .sourceData = + { + .size = spectrums.size() * sizeof(SpectrumParameters), + .data = (uint8*)spectrums.data(), + }, + .numElements = 8, + .dynamic = true, + .name = "Spectrums", + }); + spectrumBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, Gfx::SE_ACCESS_SHADER_READ_BIT, + Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT); + + linearRepeatSampler = graphics->createSampler(SamplerCreateInfo{ + .magFilter = Gfx::SE_FILTER_LINEAR, + .minFilter = Gfx::SE_FILTER_LINEAR, + .addressModeU = Gfx::SE_SAMPLER_ADDRESS_MODE_REPEAT, + .addressModeV = Gfx::SE_SAMPLER_ADDRESS_MODE_REPEAT, + .addressModeW = Gfx::SE_SAMPLER_ADDRESS_MODE_REPEAT, + .anisotropyEnable = true, + .maxAnisotropy = 16, + }); + + computeLayout = graphics->createDescriptorLayout("pParams"); + computeLayout->addDescriptorBinding(Gfx::DescriptorBinding{ + .binding = 0, + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + }); + computeLayout->addDescriptorBinding(Gfx::DescriptorBinding{ + .binding = 1, + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_IMAGE, + }); + computeLayout->addDescriptorBinding(Gfx::DescriptorBinding{ + .binding = 2, + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_IMAGE, + }); + computeLayout->addDescriptorBinding(Gfx::DescriptorBinding{ + .binding = 3, + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_IMAGE, + }); + computeLayout->addDescriptorBinding(Gfx::DescriptorBinding{ + .binding = 4, + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_IMAGE, + }); + computeLayout->addDescriptorBinding(Gfx::DescriptorBinding{ + .binding = 5, + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_IMAGE, + }); + computeLayout->addDescriptorBinding(Gfx::DescriptorBinding{ + .binding = 6, + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER, + }); + computeLayout->addDescriptorBinding(Gfx::DescriptorBinding{ + .binding = 7, + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLER, + }); + computeLayout->create(); + + pipelineLayout = graphics->createPipelineLayout("WaterComputeLayout"); + pipelineLayout->addDescriptorLayout(computeLayout); + + ShaderCompilationInfo info = { + .name = "WaterCompute", + .modules = {"WaterCompute"}, + .entryPoints = + { + {"CS_InitializeSpectrum", "WaterCompute"}, + {"CS_PackSpectrumConjugate", "WaterCompute"}, + {"CS_UpdateSpectrumForFFT", "WaterCompute"}, + {"CS_HorizontalFFT", "WaterCompute"}, + {"CS_VerticalFFT", "WaterCompute"}, + {"CS_AssembleMaps", "WaterCompute"}, + }, + .rootSignature = pipelineLayout, + .dumpIntermediate = true, + }; + graphics->beginShaderCompilation(info); + initSpectrumCS = graphics->createComputeShader({0}); + packSpectrumConjugateCS = graphics->createComputeShader({1}); + updateSpectrumForFFTCS = graphics->createComputeShader({2}); + horizontalFFTCS = graphics->createComputeShader({3}); + verticalFFTCS = graphics->createComputeShader({4}); + assembleMapsCS = graphics->createComputeShader({5}); + + pipelineLayout->create(); + + initSpectrum = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{ + .computeShader = initSpectrumCS, + .pipelineLayout = pipelineLayout, + }); + packSpectrumConjugate = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{ + .computeShader = packSpectrumConjugateCS, + .pipelineLayout = pipelineLayout, + }); + updateSpectrumForFFT = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{ + .computeShader = updateSpectrumForFFTCS, + .pipelineLayout = pipelineLayout, + }); + horizontalFFT = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{ + .computeShader = horizontalFFTCS, + .pipelineLayout = pipelineLayout, + }); + verticalFFT = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{ + .computeShader = verticalFFTCS, + .pipelineLayout = pipelineLayout, + }); + assembleMaps = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{ + .computeShader = assembleMapsCS, + .pipelineLayout = pipelineLayout, + }); + + materialLayout = graphics->createDescriptorLayout("pWaterMaterial"); + materialLayout->addDescriptorBinding(Gfx::DescriptorBinding{ + .binding = 0, + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + }); + materialLayout->addDescriptorBinding(Gfx::DescriptorBinding{ + .binding = 1, + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + }); + materialLayout->addDescriptorBinding(Gfx::DescriptorBinding{ + .binding = 2, + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + }); + materialLayout->addDescriptorBinding(Gfx::DescriptorBinding{ + .binding = 3, + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + }); + materialLayout->addDescriptorBinding(Gfx::DescriptorBinding{ + .binding = 4, + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLER, + }); + materialLayout->addDescriptorBinding(Gfx::DescriptorBinding{ + .binding = 5, + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER, + }); + materialLayout->create(); + waterLayout = graphics->createPipelineLayout("WaterLayout"); + waterLayout->addDescriptorLayout(viewParamsLayout); + waterLayout->addDescriptorLayout(materialLayout); + + ShaderCompilationInfo createInfo = { + .name = "WaterTiles", + .modules = {"WaterTask", "WaterMesh", "WaterPass"}, + .entryPoints = + { + {"taskMain", "WaterTask"}, + {"meshMain", "WaterMesh"}, + {"main", "WaterPass"}, + }, + .rootSignature = waterLayout, + }; + graphics->beginShaderCompilation(createInfo); + waterTask = graphics->createTaskShader({0}); + waterMesh = graphics->createMeshShader({1}); + waterFragment = graphics->createFragmentShader({2}); + + waterLayout->create(); +} + +WaterRenderer::~WaterRenderer() {} + +void WaterRenderer::beginFrame() { + std::cout << "Test" << std::endl; + updateFFTDescriptor(); + struct WaterPayload { + Vector2 offset; + float extent; + float height; + }; + Array payloads; + scene->view([&](Component::WaterTile& tile) { + payloads.add(WaterPayload{ + .offset = Vector2(tile.location) * Component::WaterTile::DIMENSIONS, + .extent = Component::WaterTile::DIMENSIONS, + .height = tile.height, + }); + }); + waterTiles = graphics->createShaderBuffer(ShaderBufferCreateInfo{ + .sourceData = + { + .size = payloads.size() * sizeof(WaterPayload), + .data = (uint8*)payloads.data(), + }, + .numElements = payloads.size(), + .name = "WaterTiles", + }); + waterTiles->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, Gfx::SE_ACCESS_SHADER_READ_BIT, + Gfx::SE_PIPELINE_STAGE_TASK_SHADER_BIT_EXT); + + displacementTextures->changeLayout(Gfx::SE_IMAGE_LAYOUT_GENERAL, Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_SHADER_STAGE_MESH_BIT_EXT, + Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT); + + slopeTextures->changeLayout(Gfx::SE_IMAGE_LAYOUT_GENERAL, Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_SHADER_STAGE_MESH_BIT_EXT, + Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT); + + boyancyData->changeLayout(Gfx::SE_IMAGE_LAYOUT_GENERAL, Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_SHADER_STAGE_MESH_BIT_EXT, + Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT); + + Gfx::OComputeCommand updateCommand = graphics->createComputeCommand("WaterUpdate"); + updateCommand->bindPipeline(updateSpectrumForFFT); + updateCommand->bindDescriptor(computeSet); + updateCommand->dispatch(threadGroupsX, threadGroupsY, 1); + graphics->executeCommands(std::move(updateCommand)); + + spectrumTextures->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT, + Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT); + Gfx::OComputeCommand horizontalCommand = graphics->createComputeCommand("HorizontalFFT"); + horizontalCommand->bindPipeline(horizontalFFT); + horizontalCommand->bindDescriptor(computeSet); + horizontalCommand->dispatch(1, params.N, 1); + graphics->executeCommands(std::move(horizontalCommand)); + + spectrumTextures->pipelineBarrier( + Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT); + + Gfx::OComputeCommand verticalCommand = graphics->createComputeCommand("VerticalFFT"); + verticalCommand->bindPipeline(verticalFFT); + verticalCommand->bindDescriptor(computeSet); + verticalCommand->dispatch(1, params.N, 1); + graphics->executeCommands(std::move(verticalCommand)); + + spectrumTextures->pipelineBarrier( + Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT); + + Gfx::OComputeCommand assembleCommand = graphics->createComputeCommand("AssembleCommand"); + assembleCommand->bindPipeline(assembleMaps); + assembleCommand->bindDescriptor(computeSet); + assembleCommand->dispatch(threadGroupsX, threadGroupsY, 1); + graphics->executeCommands(std::move(assembleCommand)); + + // transition for mipmap gen + displacementTextures->changeLayout( + Gfx::SE_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + Gfx::SE_ACCESS_TRANSFER_READ_BIT | Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT); + + slopeTextures->changeLayout(Gfx::SE_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, Gfx::SE_ACCESS_SHADER_WRITE_BIT, + Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + Gfx::SE_ACCESS_TRANSFER_READ_BIT | Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT); + + displacementTextures->generateMipmaps(); + slopeTextures->generateMipmaps(); + + displacementTextures->changeLayout(Gfx::SE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, + Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, Gfx::SE_ACCESS_SHADER_READ_BIT, + Gfx::SE_SHADER_STAGE_MESH_BIT_EXT); + + slopeTextures->changeLayout(Gfx::SE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, + Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_SHADER_STAGE_MESH_BIT_EXT); + + boyancyData->changeLayout(Gfx::SE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, Gfx::SE_ACCESS_SHADER_WRITE_BIT, + Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_SHADER_STAGE_MESH_BIT_EXT); + + updateMaterialDescriptor(); + graphics->waitDeviceIdle(); +} + +Gfx::ORenderCommand WaterRenderer::render(Gfx::PDescriptorSet viewParamsSet) { + Gfx::ORenderCommand waterCommand = graphics->createRenderCommand("WaterRender"); + waterCommand->setViewport(viewport); + waterCommand->bindPipeline(waterPipeline); + waterCommand->bindDescriptor({viewParamsSet, materialSet}); + waterCommand->drawMesh(waterTiles->getNumElements(), 1, 1); + return waterCommand; +} + +void WaterRenderer::setViewport(Gfx::PViewport _viewport, Gfx::PRenderPass renderPass) { + viewport = _viewport; + updateFFTDescriptor(); + Gfx::MeshPipelineCreateInfo pipelineInfo = { + .taskShader = waterTask, + .meshShader = waterMesh, + .fragmentShader = waterFragment, + .renderPass = renderPass, + .pipelineLayout = waterLayout, + .multisampleState = + { + .samples = viewport->getSamples(), + }, + .rasterizationState = + { + .cullMode = Gfx::SE_CULL_MODE_BACK_BIT, + }, + .colorBlend = + { + .attachmentCount = 1, + .blendAttachments = + { + Gfx::ColorBlendState::BlendAttachment{ + .blendEnable = true, + }, + }, + }, + }; + waterPipeline = graphics->createGraphicsPipeline(std::move(pipelineInfo)); + Gfx::OComputeCommand initCmd = graphics->createComputeCommand("InitialSpectrumCompute"); + initCmd->bindPipeline(initSpectrum); + initCmd->bindDescriptor(computeSet); + initCmd->dispatch(threadGroupsX, threadGroupsY, 1); + graphics->executeCommands(std::move(initCmd)); + + initialSpectrumTextures->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT, + Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT); + + Gfx::OComputeCommand packCmd = graphics->createComputeCommand("PackConjugate"); + packCmd->bindPipeline(packSpectrumConjugate); + packCmd->bindDescriptor(computeSet); + packCmd->dispatch(threadGroupsX, threadGroupsY, 1); + graphics->executeCommands(std::move(packCmd)); + + initialSpectrumTextures->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT, + Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT); +} + +float WaterRenderer::jonswapAlpha(float fetch, float windSpeed) const { + return 0.076f * pow(params.gravity * fetch / windSpeed / windSpeed, -0.22f); +} + +float WaterRenderer::jonswapPeakFrequency(float fetch, float windSpeed) const { + return 22 * pow(windSpeed * fetch / params.gravity / params.gravity, -0.33f); +} + +void WaterRenderer::updateFFTDescriptor() { + for (uint32 i = 0; i < displaySpectrums.size(); ++i) { + spectrums[i] = { + .scale = displaySpectrums[i].scale, + .angle = displaySpectrums[i].windDirection / 180 * 3.1415f, + .spreadBlend = displaySpectrums[i].spreadBlend, + .swell = std::clamp(displaySpectrums[i].swell, 0.01f, 1.0f), + .alpha = jonswapAlpha(displaySpectrums[i].fetch, displaySpectrums[i].windSpeed), + .peakOmega = jonswapPeakFrequency(displaySpectrums[i].fetch, displaySpectrums[i].windSpeed), + .gamma = displaySpectrums[i].peakEnhancement, + .shortWavesFade = displaySpectrums[i].shortWavesFade, + }; + } + spectrumBuffer->updateContents(0, sizeof(SpectrumParameters) * spectrums.size(), spectrums.data()); + spectrumBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, Gfx::SE_ACCESS_SHADER_READ_BIT, + Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT); + params.deltaTime = Gfx::getCurrentFrameDelta(); + params.frameTime = Gfx::getCurrentFrameTime(); + paramsBuffer->updateContents(0, sizeof(ComputeParams), ¶ms); + paramsBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, Gfx::SE_ACCESS_UNIFORM_READ_BIT, + Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT); + computeLayout->reset(); + computeSet = computeLayout->allocateDescriptorSet(); + computeSet->updateBuffer(0, paramsBuffer); + computeSet->updateTexture(1, 0, Gfx::PTexture2D(spectrumTextures)); + computeSet->updateTexture(2, 0, Gfx::PTexture2D(initialSpectrumTextures)); + computeSet->updateTexture(3, 0, Gfx::PTexture2D(displacementTextures)); + computeSet->updateTexture(4, 0, Gfx::PTexture2D(slopeTextures)); + computeSet->updateTexture(5, 0, Gfx::PTexture2D(boyancyData)); + computeSet->updateBuffer(6, 0, spectrumBuffer); + computeSet->updateSampler(7, 0, linearRepeatSampler); + computeSet->writeChanges(); +} + +void WaterRenderer::updateMaterialDescriptor() { + materialLayout->reset(); + materialSet = materialLayout->allocateDescriptorSet(); + materialSet->updateBuffer(0, materialUniforms); + materialSet->updateTexture(1, Gfx::PTexture2D(displacementTextures)); + materialSet->updateTexture(2, Gfx::PTexture2D(slopeTextures)); + materialSet->updateTexture(3, Gfx::PTextureCube(skyBox)); + materialSet->updateSampler(4, linearRepeatSampler); + materialSet->updateBuffer(5, waterTiles); + materialSet->writeChanges(); +} diff --git a/src/Engine/Graphics/RenderPass/WaterRenderer.h b/src/Engine/Graphics/RenderPass/WaterRenderer.h new file mode 100644 index 0000000..3f59c02 --- /dev/null +++ b/src/Engine/Graphics/RenderPass/WaterRenderer.h @@ -0,0 +1,136 @@ +#pragma once +#include "RenderPass.h" + +namespace Seele { +class WaterRenderer { + public: + WaterRenderer(Gfx::PGraphics graphics, PScene scene, Gfx::PDescriptorLayout viewParamsLayout); + ~WaterRenderer(); + void beginFrame(); + Gfx::ORenderCommand render(Gfx::PDescriptorSet viewParamsSet); + void setViewport(Gfx::PViewport viewport, Gfx::PRenderPass renderPass); + + private: + float jonswapAlpha(float fetch, float windSpeed) const; + float jonswapPeakFrequency(float fetch, float windSpeed) const; + void updateFFTDescriptor(); + void updateMaterialDescriptor(); + Gfx::PGraphics graphics; + PScene scene; + Gfx::ODescriptorLayout computeLayout; + Gfx::PDescriptorSet computeSet; + Gfx::OPipelineLayout pipelineLayout; + + Gfx::OComputeShader initSpectrumCS; + Gfx::PComputePipeline initSpectrum; + Gfx::OComputeShader packSpectrumConjugateCS; + Gfx::PComputePipeline packSpectrumConjugate; + Gfx::OComputeShader updateSpectrumForFFTCS; + Gfx::PComputePipeline updateSpectrumForFFT; + Gfx::OComputeShader horizontalFFTCS; + Gfx::PComputePipeline horizontalFFT; + Gfx::OComputeShader verticalFFTCS; + Gfx::PComputePipeline verticalFFT; + Gfx::OComputeShader assembleMapsCS; + Gfx::PComputePipeline assembleMaps; + + struct SpectrumParameters { + float scale; + float angle; + float spreadBlend; + float swell; + float alpha; + float peakOmega; + float gamma; + float shortWavesFade; + }; + StaticArray spectrums; + struct DisplaySpectrumSettings { + float scale = 1; + float windSpeed = 1; + float windDirection = 0; + float fetch = 1; + float spreadBlend = 1; + float swell = 1; + float peakEnhancement = 1; + float shortWavesFade = 1; + }; + StaticArray displaySpectrums; + struct ComputeParams { + float frameTime; + float deltaTime; + float gravity = 9.81f; + float repeatTime = 200.0f; + float depth = 20.0f; + float lowCutoff = 0.0001f; + float highCutoff = 9000.0f; + int seed = 0; + Vector2 lambda = Vector2(1, 1); + uint32 N = 1024; + uint32 lengthScale0 = 256; + uint32 lengthScale1 = 256; + uint32 lengthScale2 = 256; + uint32 lengthScale3 = 256; + float foamBias = -0.5f; + float foamDecayRate = 0.05f; + float foamAdd = 0.5f; + float foamThreshold = 0.0f; + } params; + float speed = 1.0f; + float displacementDepthFalloff = 1.0f; + uint32 logN; + uint32 threadGroupsX; + uint32 threadGroupsY; + Gfx::OUniformBuffer paramsBuffer; + Gfx::OTexture2D spectrumTextures, initialSpectrumTextures, displacementTextures; + Gfx::OTexture2D slopeTextures; + Gfx::OTexture2D boyancyData; + Gfx::OShaderBuffer spectrumBuffer; + Gfx::OSampler linearRepeatSampler; + + struct MaterialParams { + Vector sunDirection = Vector(0, -1, 0); + float displacementDepthAttenuation = 1; + + float foamSubtract0 = 0; + float foamSubtract1 = 0; + float foamSubtract2 = 0; + float foamSubtract3 = 0; + + float normalStrength = 1; + float foamDepthAttenuation = 1; + float normalDepthAttenuation = 1; + float roughness = 0.1f; + + Vector sunIrradiance = Vector(1, 1, 1); + float foamRoughnessModifier = 1; + + Vector scatterColor = Vector(1, 1, 1); + float environmentLightStrength = 1; + + Vector bubbleColor = Vector(1, 1, 1); + float heightModifier = 1; + + float bubbleDensity = 1; + float wavePeakScatterStrength = 1; + float scatterStrength = 1; + float scatterShadowStrength = 1; + + Vector foamColor = Vector(1, 1, 1); + } materialParams; + // Water + Gfx::OUniformBuffer materialUniforms; + Gfx::PTextureCube skyBox; + Gfx::OShaderBuffer waterTiles; + Gfx::OTaskShader waterTask; + Gfx::OMeshShader waterMesh; + Gfx::OFragmentShader waterFragment; + Gfx::ODescriptorLayout materialLayout; + Gfx::PDescriptorSet materialSet; + Gfx::OPipelineLayout waterLayout; + Gfx::PGraphicsPipeline waterPipeline; + + Gfx::PViewport viewport; +}; +DEFINE_REF(WaterRenderer) +} \ No newline at end of file diff --git a/src/Engine/Graphics/StaticMeshVertexData.cpp b/src/Engine/Graphics/StaticMeshVertexData.cpp index d3169eb..6538e30 100644 --- a/src/Engine/Graphics/StaticMeshVertexData.cpp +++ b/src/Engine/Graphics/StaticMeshVertexData.cpp @@ -66,22 +66,22 @@ void StaticMeshVertexData::serializeMesh(MeshId id, uint64 numVertices, ArchiveB std::unique_lock l(vertexDataLock); offset = meshOffsets[id]; } - Array pos(numVertices); Array tex[MAX_TEXCOORDS]; for (size_t i = 0; i < MAX_TEXCOORDS; ++i) { tex[i].resize(numVertices); - texCoords[i]->readContents(offset * sizeof(Vector2), numVertices * sizeof(Vector2), tex[i].data()); + std::memcpy(tex[i].data(), texData[i].data() + offset, numVertices * sizeof(Vector2)); Serialization::save(buffer, tex[i]); } Array nor(numVertices); Array tan(numVertices); Array bit(numVertices); Array col(numVertices); - positions->readContents(offset * sizeof(Vector4), numVertices * sizeof(Vector4), pos.data()); - normals->readContents(offset * sizeof(Vector4), numVertices * sizeof(Vector4), nor.data()); - tangents->readContents(offset * sizeof(Vector4), numVertices * sizeof(Vector4), tan.data()); - biTangents->readContents(offset * sizeof(Vector4), numVertices * sizeof(Vector4), bit.data()); - colors->readContents(offset * sizeof(Vector4), numVertices * sizeof(Vector4), col.data()); + Array pos(numVertices); + std::memcpy(pos.data(), posData.data() + offset, numVertices * sizeof(Vector4)); + std::memcpy(nor.data(), norData.data() + offset, numVertices * sizeof(Vector4)); + std::memcpy(tan.data(), tanData.data() + offset, numVertices * sizeof(Vector4)); + std::memcpy(bit.data(), bitData.data() + offset, numVertices * sizeof(Vector4)); + std::memcpy(col.data(), colData.data() + offset, numVertices * sizeof(Vector4)); Serialization::save(buffer, pos); Serialization::save(buffer, nor); Serialization::save(buffer, tan); diff --git a/src/Engine/Graphics/Vulkan/Buffer.cpp b/src/Engine/Graphics/Vulkan/Buffer.cpp index 8fa4910..347615f 100644 --- a/src/Engine/Graphics/Vulkan/Buffer.cpp +++ b/src/Engine/Graphics/Vulkan/Buffer.cpp @@ -17,6 +17,7 @@ BufferAllocation::BufferAllocation(PGraphics graphics, const std::string& name, : CommandBoundResource(graphics, name), size(bufferInfo.size), owner(owner) { VK_CHECK(vmaCreateBufferWithAlignment(graphics->getAllocator(), &bufferInfo, &allocInfo, alignment, &buffer, &allocation, &info)); vmaGetAllocationMemoryProperties(graphics->getAllocator(), allocation, &properties); + assert(!name.empty()); VkDebugUtilsObjectNameInfoEXT nameInfo = { .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, .pNext = nullptr, @@ -24,11 +25,10 @@ BufferAllocation::BufferAllocation(PGraphics graphics, const std::string& name, .objectHandle = (uint64)buffer, .pObjectName = name.c_str(), }; + vkSetDebugUtilsObjectNameEXT(graphics->getDevice(), &nameInfo); if (!(properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) { bufferSize += size; } - assert(!name.empty()); - vkSetDebugUtilsObjectNameEXT(graphics->getDevice(), &nameInfo); if (bufferInfo.usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) { VkBufferDeviceAddressInfo addrInfo = { .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR, diff --git a/src/Engine/Graphics/Vulkan/Command.cpp b/src/Engine/Graphics/Vulkan/Command.cpp index 0b55cf7..1f6bd65 100644 --- a/src/Engine/Graphics/Vulkan/Command.cpp +++ b/src/Engine/Graphics/Vulkan/Command.cpp @@ -401,7 +401,7 @@ void ComputeCommand::bindDescriptor(Gfx::PDescriptorSet descriptorSet, ArraywriteDescriptors.size() == 0); boundResources.add(descriptor.getHandle()); - for (auto binding : descriptor->boundResources) { + for (const auto& binding : descriptor->boundResources) { for (auto res : binding) { res->bind(); boundResources.add(res); diff --git a/src/Engine/Graphics/Vulkan/Descriptor.cpp b/src/Engine/Graphics/Vulkan/Descriptor.cpp index 6e858cc..f552467 100644 --- a/src/Engine/Graphics/Vulkan/Descriptor.cpp +++ b/src/Engine/Graphics/Vulkan/Descriptor.cpp @@ -3,8 +3,8 @@ #include "CRC.h" #include "Command.h" #include "Graphics.h" -#include "Texture.h" #include "RayTracing.h" +#include "Texture.h" using namespace Seele; using namespace Seele::Vulkan; @@ -159,10 +159,10 @@ void DescriptorPool::reset() { } DescriptorSet::DescriptorSet(PGraphics graphics, PDescriptorPool owner) - : Gfx::DescriptorSet(owner->getLayout()), CommandBoundResource(graphics, owner->getLayout()->getName()), setHandle(VK_NULL_HANDLE), graphics(graphics), owner(owner){ + : Gfx::DescriptorSet(owner->getLayout()), CommandBoundResource(graphics, owner->getLayout()->getName()), setHandle(VK_NULL_HANDLE), + graphics(graphics), owner(owner) { boundResources.resize(owner->getLayout()->getBindings().size()); - for (uint32 i = 0; i < boundResources.size(); ++i) - { + for (uint32 i = 0; i < boundResources.size(); ++i) { boundResources[i].resize(owner->getLayout()->getBindings()[i].descriptorCount); } } @@ -245,7 +245,6 @@ void DescriptorSet::updateBuffer(uint32_t binding, Gfx::PIndexBuffer indexBuffer boundResources[binding][0] = vulkanBuffer->getAlloc(); } - void DescriptorSet::updateBuffer(uint32_t binding, uint32 index, Gfx::PShaderBuffer shaderBuffer) { PShaderBuffer vulkanBuffer = shaderBuffer.cast(); if (boundResources[binding][index] == vulkanBuffer->getAlloc()) { @@ -298,8 +297,7 @@ void DescriptorSet::updateSampler(uint32_t binding, Gfx::PSampler samplerState) boundResources[binding][0] = vulkanSampler->getHandle(); } -void DescriptorSet::updateSampler(uint32_t binding, uint32 dstArrayIndex, Gfx::PSampler samplerState) -{ +void DescriptorSet::updateSampler(uint32_t binding, uint32 dstArrayIndex, Gfx::PSampler samplerState) { PSampler vulkanSampler = samplerState.cast(); if (boundResources[binding][dstArrayIndex] == vulkanSampler->getHandle()) { return; @@ -325,7 +323,6 @@ void DescriptorSet::updateSampler(uint32_t binding, uint32 dstArrayIndex, Gfx::P boundResources[binding][dstArrayIndex] = vulkanSampler->getHandle(); } - void DescriptorSet::updateTexture(uint32_t binding, Gfx::PTexture texture, Gfx::PSampler samplerState) { TextureBase* vulkanTexture = texture.cast().getHandle(); if (boundResources[binding][0] == vulkanTexture->getHandle()) { @@ -338,12 +335,6 @@ void DescriptorSet::updateTexture(uint32_t binding, Gfx::PTexture texture, Gfx:: .imageView = vulkanTexture->getView(), .imageLayout = cast(vulkanTexture->getLayout()), }); - VkDescriptorType descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - if (samplerState != nullptr) { - descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - } else if (vulkanTexture->getUsage() & VK_IMAGE_USAGE_STORAGE_BIT) { - descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - } writeDescriptors.add(VkWriteDescriptorSet{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .pNext = nullptr, @@ -351,15 +342,14 @@ void DescriptorSet::updateTexture(uint32_t binding, Gfx::PTexture texture, Gfx:: .dstBinding = binding, .dstArrayElement = 0, .descriptorCount = 1, - .descriptorType = descriptorType, + .descriptorType = cast(layout->getBindings()[binding].descriptorType), .pImageInfo = &imageInfos.back(), }); boundResources[binding][0] = vulkanTexture->getHandle(); } -void DescriptorSet::updateTexture(uint32 binding, uint32 dstArrayIndex, Gfx::PTexture texture) -{ +void DescriptorSet::updateTexture(uint32 binding, uint32 dstArrayIndex, Gfx::PTexture texture) { TextureBase* vulkanTexture = texture.cast().getHandle(); if (boundResources[binding][dstArrayIndex] == vulkanTexture->getHandle()) { return; @@ -378,14 +368,13 @@ void DescriptorSet::updateTexture(uint32 binding, uint32 dstArrayIndex, Gfx::PTe .dstBinding = binding, .dstArrayElement = dstArrayIndex, .descriptorCount = 1, - .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .descriptorType = cast(layout->getBindings()[binding].descriptorType), .pImageInfo = &imageInfos.back(), }); boundResources[binding][dstArrayIndex] = vulkanTexture->getHandle(); } - void DescriptorSet::updateTextureArray(uint32_t binding, Array textures) { // maybe make this a parameter? uint32 arrayElement = 0; @@ -400,10 +389,6 @@ void DescriptorSet::updateTextureArray(uint32_t binding, Array .imageLayout = cast(vulkanTexture->getLayout()), }); - VkDescriptorType descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - if (vulkanTexture->getUsage() & VK_IMAGE_USAGE_STORAGE_BIT) { - descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - } boundResources[binding][arrayElement] = vulkanTexture->getHandle(); writeDescriptors.add(VkWriteDescriptorSet{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, @@ -412,13 +397,12 @@ void DescriptorSet::updateTextureArray(uint32_t binding, Array .dstBinding = binding, .dstArrayElement = arrayElement++, .descriptorCount = 1, - .descriptorType = descriptorType, + .descriptorType = cast(layout->getBindings()[binding].descriptorType), .pImageInfo = &imageInfos.back(), }); } } - void DescriptorSet::updateSamplerArray(uint32_t binding, Array samplers) { // maybe make this a parameter? uint32 arrayElement = 0; diff --git a/src/Engine/Graphics/Vulkan/Graphics.cpp b/src/Engine/Graphics/Vulkan/Graphics.cpp index 8972e4e..eb892aa 100644 --- a/src/Engine/Graphics/Vulkan/Graphics.cpp +++ b/src/Engine/Graphics/Vulkan/Graphics.cpp @@ -175,6 +175,12 @@ void Graphics::executeCommands(Array commands) { getGraphicsCommands()->getCommands()->executeCommands(std::move(commands)); } +void Graphics::executeCommands(Gfx::OComputeCommand commands) { + Array commandArray; + commandArray.add(std::move(commands)); + getComputeCommands()->getCommands()->executeCommands(std::move(commandArray)); +} + void Graphics::executeCommands(Array commands) { getComputeCommands()->getCommands()->executeCommands(std::move(commands)); } @@ -747,6 +753,7 @@ void Graphics::pickPhysicalDevice() { .pNext = &meshShaderFeatures, .storageBuffer8BitAccess = true, .uniformAndStorageBuffer8BitAccess = true, + .shaderFloat16 = true, .shaderUniformBufferArrayNonUniformIndexing = true, .shaderSampledImageArrayNonUniformIndexing = true, .shaderStorageBufferArrayNonUniformIndexing = true, @@ -770,6 +777,7 @@ void Graphics::pickPhysicalDevice() { .geometryShader = true, .fillModeNonSolid = true, .wideLines = true, + .samplerAnisotropy = true, .pipelineStatisticsQuery = true, .fragmentStoresAndAtomics = true, .shaderInt64 = true, diff --git a/src/Engine/Graphics/Vulkan/Graphics.h b/src/Engine/Graphics/Vulkan/Graphics.h index 6e9b883..1c82ade 100644 --- a/src/Engine/Graphics/Vulkan/Graphics.h +++ b/src/Engine/Graphics/Vulkan/Graphics.h @@ -41,6 +41,7 @@ class Graphics : public Gfx::Graphics { virtual void waitDeviceIdle() override; virtual void executeCommands(Array commands) override; + virtual void executeCommands(Gfx::OComputeCommand commands) override; virtual void executeCommands(Array commands) override; virtual Gfx::OTexture2D createTexture2D(const TextureCreateInfo& createInfo) override; diff --git a/src/Engine/Graphics/Vulkan/Query.cpp b/src/Engine/Graphics/Vulkan/Query.cpp index 3f31e83..0e2f710 100644 --- a/src/Engine/Graphics/Vulkan/Query.cpp +++ b/src/Engine/Graphics/Vulkan/Query.cpp @@ -46,7 +46,6 @@ void QueryPool::begin() { void QueryPool::end() { PCommand cmd = graphics->getGraphicsCommands()->getCommands(); vkCmdEndQuery(cmd->getHandle(), handle, head); - graphics->getGraphicsCommands()->submitCommands(); std::unique_lock l(queryMutex); head = (head + 1) % numQueries; queryCV.notify_all(); diff --git a/src/Engine/Graphics/Vulkan/Texture.cpp b/src/Engine/Graphics/Vulkan/Texture.cpp index 4847c55..8be183f 100644 --- a/src/Engine/Graphics/Vulkan/Texture.cpp +++ b/src/Engine/Graphics/Vulkan/Texture.cpp @@ -3,9 +3,9 @@ #include "Enums.h" #include "Graphics/Enums.h" #include "Graphics/Initializer.h" +#include #include #include -#include using namespace Seele; using namespace Seele::Vulkan; @@ -29,10 +29,13 @@ VkImageAspectFlags getAspectFromFormat(Gfx::SeFormat format) { } TextureHandle::TextureHandle(PGraphics graphics, VkImageViewType viewType, const TextureCreateInfo& createInfo, VkImage existingImage) - : CommandBoundResource(graphics, createInfo.name), image(existingImage), width(createInfo.width), height(createInfo.height), depth(createInfo.depth), - arrayCount(createInfo.elements), layerCount(createInfo.layers), mipLevels(createInfo.mipLevels), samples(createInfo.samples), + : CommandBoundResource(graphics, createInfo.name), image(existingImage), width(createInfo.width), height(createInfo.height), + depth(createInfo.depth), arrayCount(createInfo.elements), mipLevels(1), layerCount(createInfo.layers), samples(createInfo.samples), format(createInfo.format), usage(createInfo.usage), layout(Gfx::SE_IMAGE_LAYOUT_UNDEFINED), aspect(getAspectFromFormat(createInfo.format)), ownsImage(false), owner(createInfo.sourceData.owner) { + if (createInfo.useMip) { + mipLevels = static_cast(std::floor(std::log2(std::max(width, height)))) + 1; + } if (existingImage == VK_NULL_HANDLE) { VkImageType type = VK_IMAGE_TYPE_MAX_ENUM; VkImageCreateFlags flags = 0; @@ -84,6 +87,14 @@ TextureHandle::TextureHandle(PGraphics graphics, VkImageViewType viewType, const .usage = VMA_MEMORY_USAGE_AUTO, }; VK_CHECK(vmaCreateImage(graphics->getAllocator(), &info, &allocInfo, &image, &allocation, nullptr)); + VkDebugUtilsObjectNameInfoEXT nameInfo = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, + .pNext = nullptr, + .objectType = VK_OBJECT_TYPE_IMAGE, + .objectHandle = (uint64)image, + .pObjectName = name.c_str(), + }; + vkSetDebugUtilsObjectNameEXT(graphics->getDevice(), &nameInfo); ownsImage = true; } const DataSource& sourceData = createInfo.sourceData; @@ -103,7 +114,8 @@ TextureHandle::TextureHandle(PGraphics graphics, VkImageViewType viewType, const .flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT, .usage = VMA_MEMORY_USAGE_AUTO, }; - OBufferAllocation stagingAlloc = new BufferAllocation(graphics, fmt::format("{}Staging", createInfo.name), stagingInfo, alloc, Gfx::QueueType::TRANSFER); + OBufferAllocation stagingAlloc = + new BufferAllocation(graphics, fmt::format("{}Staging", createInfo.name), stagingInfo, alloc, Gfx::QueueType::TRANSFER); vmaMapMemory(graphics->getAllocator(), stagingAlloc->allocation, &data); std::memcpy(data, sourceData.data, sourceData.size); vmaUnmapMemory(graphics->getAllocator(), stagingAlloc->allocation); diff --git a/src/Engine/Graphics/Vulkan/Window.cpp b/src/Engine/Graphics/Vulkan/Window.cpp index 0cb161b..0802eb7 100644 --- a/src/Engine/Graphics/Vulkan/Window.cpp +++ b/src/Engine/Graphics/Vulkan/Window.cpp @@ -11,6 +11,9 @@ using namespace Seele::Vulkan; double currentFrameDelta = 0; double Gfx::getCurrentFrameDelta() { return currentFrameDelta; } +double currentFrameTime = 0; +double Gfx::getCurrentFrameTime() { return currentFrameTime; } + uint32 currentFrameIndex = 0; uint32 Gfx::getCurrentFrameIndex() { return currentFrameIndex; } @@ -98,6 +101,11 @@ void Window::beginFrame() { imageAvailableFences[currentSemaphoreIndex]->submit(); graphics->getGraphicsCommands()->getCommands()->waitForSemaphore(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, imageAvailableSemaphores[currentSemaphoreIndex]); + static double start = glfwGetTime(); + double end = glfwGetTime(); + currentFrameDelta = end - start; + currentFrameTime += currentFrameDelta; + start = end; } void Window::endFrame() { @@ -261,7 +269,6 @@ void Window::createSwapChain() { .width = extent.width, .height = extent.height, .depth = 1, - .mipLevels = 1, .layers = 1, .elements = 1, .samples = 1, diff --git a/src/Engine/Graphics/slang-compile.cpp b/src/Engine/Graphics/slang-compile.cpp index 2dbcba7..8e44edb 100644 --- a/src/Engine/Graphics/slang-compile.cpp +++ b/src/Engine/Graphics/slang-compile.cpp @@ -48,7 +48,7 @@ void Seele::beginCompilation(const ShaderCompilationInfo& info, SlangCompileTarg option[3].value.intValue0 = SLANG_DEBUG_INFO_FORMAT_PDB; option[4].name = slang::CompilerOptionName::DumpIntermediates; option[4].value.kind = slang::CompilerOptionValueKind::Int; - option[4].value.intValue0 = 0; + option[4].value.intValue0 = info.dumpIntermediate; sessionDesc.compilerOptionEntries = option.data(); sessionDesc.compilerOptionEntryCount = option.size(); @@ -124,6 +124,7 @@ void Seele::beginCompilation(const ShaderCompilationInfo& info, SlangCompileTarg layout->addMapping("pLightEnv", 3); layout->addMapping("pRayTracingParams", 5); layout->addMapping("pScene", 2); + layout->addMapping("pWaterMaterial", 1); } Pair, std::string> Seele::generateShader(const ShaderCreateInfo& createInfo) { diff --git a/test.py b/test.py new file mode 100644 index 0000000..6f377ec --- /dev/null +++ b/test.py @@ -0,0 +1,18 @@ + +i = 12 +positions = [] +for x in range(i): + for y in range(i): + positions.append(f"float2({x}.0f / 11, {y}.0f / 11)") +indices = [] +for y in range(i - 1): + for x in range(i - 1): + indices.append(f'uint3({(x) + i * (y)}, {(x + 1) + i * (y)}, {(x) + i * (y + 1)})') + indices.append(f'uint3({(x) + i * (y + 1)}, {(x + 1) + i * (y)}, {(x + 1) + i * (y + 1)})') +print(f"Dim {i}") +print(len(positions)) +print(len(indices)) +print(positions) +print(indices) + +