research(standalone): GPU first port -- marching cubes in D3D11 compute, exact vs WARP; field still CPU

- Compute shaders classify cells from CPU sign bits, scan output offsets, emit vertex/index buffers
  and indirect-draw args. Two 32^3 tiles: 0 topology differences hardware vs WARP; two runs on the
  RX 7900 XTX identical; max CPU/GPU vertex distance 0.000122 cm (LOD0), 0.000244 cm (LOD1).
- GPU kernels 0.049 / 0.071 ms vs CPU tile 2.33 / 1.99 ms, but CPU input preparation dominates
  (7.25 / 2.84 ms wall): no whole-view gain until the field itself runs on the GPU.
- VoxelForgeFieldShared.h: first shared C++/HLSL field math (integer noise hash, ...).
CPU path unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-06 06:44:43 +02:00
1 parent 566d1f342a
commit d4b4377d30
6 files changed
+1809

No files matched your search

+173
View File
@@ -0,0 +1,173 @@
#pragma once
// Restricted scalar field math shared by the standalone C++ GPU adapter and its HLSL.
// Define VF_FIELD_HLSL before including this file from a shader. Keep this header free of
// containers, engine types, and vector intrinsics so it remains usable by both compilers.
#if defined(VF_FIELD_HLSL)
#define VF_FIELD_INLINE
typedef int VF_FieldI32;
typedef uint VF_FieldU32;
#define VF_FIELD_CAST_I32(v) int(v)
#define VF_FIELD_CAST_U32(v) uint(v)
#define VF_FIELD_CAST_F32(v) float(v)
#define VF_FIELD_FLOOR(v) floor(v)
#else
#include <cmath>
#include <cstdint>
#define VF_FIELD_INLINE inline
typedef std::int32_t VF_FieldI32;
typedef std::uint32_t VF_FieldU32;
#define VF_FIELD_CAST_I32(v) static_cast<VF_FieldI32>(v)
#define VF_FIELD_CAST_U32(v) static_cast<VF_FieldU32>(v)
#define VF_FIELD_CAST_F32(v) static_cast<float>(v)
#define VF_FIELD_FLOOR(v) std::floor(v)
#endif
VF_FIELD_INLINE VF_FieldU32 VF_FieldMix(VF_FieldU32 x)
{
x ^= x >> 16;
x *= 0x7FEB352Du;
x ^= x >> 15;
x *= 0x846CA68Bu;
x ^= x >> 16;
return x;
}
VF_FIELD_INLINE VF_FieldU32 VF_FieldNoiseHash(VF_FieldI32 x, VF_FieldI32 y,
VF_FieldI32 z, VF_FieldU32 seed)
{
VF_FieldU32 h = VF_FieldMix(seed ^ 0xB5297A4Du);
h = VF_FieldMix(h ^ VF_FIELD_CAST_U32(x) * 0x68E31DA4u);
h = VF_FieldMix(h ^ VF_FIELD_CAST_U32(y) * 0x1B56C4E9u);
return VF_FieldMix(h ^ VF_FIELD_CAST_U32(z) * 0x9E3779B9u);
}
VF_FIELD_INLINE float VF_FieldNoiseValue(VF_FieldI32 x, VF_FieldI32 y,
VF_FieldI32 z, VF_FieldU32 seed)
{
return VF_FIELD_CAST_F32(VF_FieldNoiseHash(x, y, z, seed) >> 8)
* (2.0f / 16777215.0f) - 1.0f;
}
VF_FIELD_INLINE float VF_FieldFade(float t)
{
return t * t * (3.0f - 2.0f * t);
}
VF_FIELD_INLINE float VF_FieldLerp(float a, float b, float t)
{
return a + (b - a) * t;
}
VF_FIELD_INLINE float VF_FieldValueNoise(float x, float y, float z,
VF_FieldI32 wavelength, VF_FieldU32 seed)
{
const float inv = 1.0f / VF_FIELD_CAST_F32(wavelength);
const float fx = x * inv, fy = y * inv, fz = z * inv;
const VF_FieldI32 x0 = VF_FIELD_CAST_I32(VF_FIELD_FLOOR(fx));
const VF_FieldI32 y0 = VF_FIELD_CAST_I32(VF_FIELD_FLOOR(fy));
const VF_FieldI32 z0 = VF_FIELD_CAST_I32(VF_FIELD_FLOOR(fz));
const float tx = VF_FieldFade(fx - VF_FIELD_CAST_F32(x0));
const float ty = VF_FieldFade(fy - VF_FIELD_CAST_F32(y0));
const float tz = VF_FieldFade(fz - VF_FIELD_CAST_F32(z0));
const float z00 = VF_FieldLerp(VF_FieldNoiseValue(x0, y0, z0, seed),
VF_FieldNoiseValue(x0 + 1, y0, z0, seed), tx);
const float z10 = VF_FieldLerp(VF_FieldNoiseValue(x0, y0 + 1, z0, seed),
VF_FieldNoiseValue(x0 + 1, y0 + 1, z0, seed), tx);
const float z01 = VF_FieldLerp(VF_FieldNoiseValue(x0, y0, z0 + 1, seed),
VF_FieldNoiseValue(x0 + 1, y0, z0 + 1, seed), tx);
const float z11 = VF_FieldLerp(VF_FieldNoiseValue(x0, y0 + 1, z0 + 1, seed),
VF_FieldNoiseValue(x0 + 1, y0 + 1, z0 + 1, seed), tx);
return VF_FieldLerp(VF_FieldLerp(z00, z10, ty), VF_FieldLerp(z01, z11, ty), tz);
}
VF_FIELD_INLINE float VF_FieldSurfaceRelief(float x, float y, float z, VF_FieldU32 seed)
{
const float macro = VF_FieldValueNoise(x, y, z, 32, seed ^ 0xB5297A4Du);
const float mid = VF_FieldValueNoise(x, y, z, 16, seed ^ 0x63D83595u);
const float fine = VF_FieldValueNoise(x, y, z, 4, seed ^ 0xA511E9B3u);
return 1.20f * macro + (0.80f + 0.25f * macro) * (0.40f * mid + 0.60f * fine);
}
VF_FIELD_INLINE float VF_FieldSmoothUnit(float value)
{
#if defined(VF_FIELD_HLSL)
value = clamp(value, 0.0f, 1.0f);
#else
value = value < 0.0f ? 0.0f : (value > 1.0f ? 1.0f : value);
#endif
return value * value * (3.0f - 2.0f * value);
}
VF_FIELD_INLINE float VF_FieldSmoothMin(float a, float b, float width)
{
if (width <= 0.0f)
return a < b ? a : b;
const float delta = a - b;
#if defined(VF_FIELD_HLSL)
const float absolute = abs(delta);
const float minimum = min(a, b);
const float h = max(width - absolute, 0.0f) / width;
#else
const float absolute = std::abs(delta);
const float minimum = a < b ? a : b;
const float h = (width - absolute) > 0.0f ? (width - absolute) / width : 0.0f;
#endif
return minimum - (h * h * h) * (width / 6.0f);
}
// CPU and GPU use the same edge-root rule. The optional midpoint is the exact analytic
// field evaluation used by the reference LOD0 mesher for roots close to an edge midpoint.
VF_FIELD_INLINE float VF_FieldRefineRoot(float d1, float d2, float midpoint,
VF_FieldU32 hasMidpoint)
{
float t = (d2 - d1 < 1.0e-4f && d1 - d2 < 1.0e-4f)
? 0.5f : (-d1) / (d2 - d1);
#if defined(VF_FIELD_HLSL)
t = clamp(t, 0.0f, 1.0f);
#else
t = t < 0.0f ? 0.0f : (t > 1.0f ? 1.0f : t);
#endif
// hasMidpoint is an integer CPU decision made from the reference edge parameter. Do not
// repeat its threshold test in floating point on different GPU implementations.
if (hasMidpoint != 0u)
{
if (midpoint < 1.0e-6f && midpoint > -1.0e-6f)
return 0.5f;
if ((midpoint < 0.0f) == (d1 < 0.0f))
{
const float denominator = d2 - midpoint;
if (denominator < -1.0e-4f || denominator > 1.0e-4f)
{
float half = (-midpoint) / denominator;
#if defined(VF_FIELD_HLSL)
half = clamp(half, 0.0f, 1.0f);
#else
half = half < 0.0f ? 0.0f : (half > 1.0f ? 1.0f : half);
#endif
return 0.5f + 0.5f * half;
}
}
else
{
const float denominator = midpoint - d1;
if (denominator < -1.0e-4f || denominator > 1.0e-4f)
{
float half = (-d1) / denominator;
#if defined(VF_FIELD_HLSL)
half = clamp(half, 0.0f, 1.0f);
#else
half = half < 0.0f ? 0.0f : (half > 1.0f ? 1.0f : half);
#endif
return 0.5f * half;
}
}
}
return t;
}
#undef VF_FIELD_INLINE
#undef VF_FIELD_CAST_I32
#undef VF_FIELD_CAST_U32
#undef VF_FIELD_CAST_F32
#undef VF_FIELD_FLOOR