Files
hand-motion-pipeline/third_party/nvdiffrast/csrc/torch/torch_antialias.cpp
T
liyang ae28d55f81 Update to 2026-09-17 pipeline snapshot; add weights, L20 assets and recording via Git LFS
Source: RGB-D -> Dyn-HaMR -> L20 retargeting -> FoundationPose -> reference repair -> SPIDER,
documented in docs/PIPELINE_LATEST.md and docs/SETUP_AND_WEIGHTS.md. Adds FoundationPose and
nvdiffrast upstream snapshots, requirements/pipeline_venv.txt and the FoundationPose weight
manifest/downloader.

Assets (Git LFS): weights/ (WiLoR detector, HandFlow denoiser, UniDepth-L), FoundationPose
checkpoints, HaMeR checkpoint, Dyn-HaMR HMP model and BMC constraints, L20 URDF/meshes, the
20260915_171525 D405 recording and the two box CADs. MANO models are not redistributed
(third_party/hamer/_DATA/data/mano/README.txt). Environments, caches and run outputs excluded.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 11:43:37 +08:00

244 lines
12 KiB
C++

// Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto. Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
#include "torch_common.inl"
#include "torch_types.h"
#include "../common/common.h"
#include "../common/antialias.h"
//------------------------------------------------------------------------
// Kernel prototypes.
void AntialiasFwdMeshKernel (const AntialiasKernelParams p);
void AntialiasFwdDiscontinuityKernel(const AntialiasKernelParams p);
void AntialiasFwdAnalysisKernel (const AntialiasKernelParams p);
void AntialiasGradKernel (const AntialiasKernelParams p);
//------------------------------------------------------------------------
// Topology hash construction.
TopologyHashWrapper antialias_construct_topology_hash(torch::Tensor tri)
{
const at::cuda::OptionalCUDAGuard device_guard(device_of(tri));
cudaStream_t stream = at::cuda::getCurrentCUDAStream();
AntialiasKernelParams p = {}; // Initialize all fields to zero.
// Check inputs.
NVDR_CHECK_DEVICE(tri);
NVDR_CHECK_CONTIGUOUS(tri);
NVDR_CHECK_I32(tri);
NVDR_CHECK(tri.sizes().size() == 2 && tri.size(0) > 0 && tri.size(1) == 3, "tri must have shape [>0, 3]");
// Fill in kernel parameters.
p.numTriangles = tri.size(0);
p.numVertices = 0x7fffffff; // Let's not require vertex positions just to enable an error check.
p.tri = tri.data_ptr<int>();
// Kernel parameters.
p.allocTriangles = 64;
while (p.allocTriangles < p.numTriangles)
p.allocTriangles <<= 1; // Must be power of two.
// Construct the hash tensor and get pointer.
torch::TensorOptions opts = torch::TensorOptions().dtype(torch::kInt32).device(torch::kCUDA);
torch::Tensor ev_hash = torch::zeros({(uint64_t)p.allocTriangles * AA_HASH_ELEMENTS_PER_TRIANGLE(p.allocTriangles) * 4}, opts);
p.evHash = (uint4*)(ev_hash.data_ptr<int>());
// Check alignment.
NVDR_CHECK(!((uintptr_t)p.evHash & 15), "ev_hash internal tensor not aligned to int4");
// Populate the hash.
void* args[] = {&p};
NVDR_CHECK_CUDA_ERROR(cudaLaunchKernel((void*)AntialiasFwdMeshKernel, (p.numTriangles - 1) / AA_MESH_KERNEL_THREADS_PER_BLOCK + 1, AA_MESH_KERNEL_THREADS_PER_BLOCK, args, 0, stream));
// Return.
TopologyHashWrapper hash_wrap;
hash_wrap.ev_hash = ev_hash;
return hash_wrap;
}
//------------------------------------------------------------------------
// Forward op.
std::tuple<torch::Tensor, torch::Tensor> antialias_fwd(torch::Tensor color, torch::Tensor rast, torch::Tensor pos, torch::Tensor tri, TopologyHashWrapper topology_hash_wrap)
{
const at::cuda::OptionalCUDAGuard device_guard(device_of(color));
cudaStream_t stream = at::cuda::getCurrentCUDAStream();
AntialiasKernelParams p = {}; // Initialize all fields to zero.
p.instance_mode = (pos.sizes().size() > 2) ? 1 : 0;
torch::Tensor& topology_hash = topology_hash_wrap.ev_hash; // Unwrap.
// Check inputs.
NVDR_CHECK_DEVICE(color, rast, pos, tri, topology_hash);
NVDR_CHECK_CONTIGUOUS(color, rast, pos, tri, topology_hash);
NVDR_CHECK_F32(color, rast, pos);
NVDR_CHECK_I32(tri, topology_hash);
// Sanity checks.
NVDR_CHECK(color.sizes().size() == 4 && color.size(0) > 0 && color.size(1) > 0 && color.size(2) > 0 && color.size(3) > 0, "color must have shape[>0, >0, >0, >0]");
NVDR_CHECK(rast.sizes().size() == 4 && rast.size(0) > 0 && rast.size(1) > 0 && rast.size(2) > 0 && rast.size(3) == 4, "rast must have shape[>0, >0, >0, 4]");
NVDR_CHECK(tri.sizes().size() == 2 && tri.size(0) > 0 && tri.size(1) == 3, "tri must have shape [>0, 3]");
NVDR_CHECK(color.size(1) == rast.size(1) && color.size(2) == rast.size(2), "color and rast inputs must have same spatial dimensions");
if (p.instance_mode)
{
NVDR_CHECK(pos.sizes().size() == 3 && pos.size(0) > 0 && pos.size(1) > 0 && pos.size(2) == 4, "pos must have shape [>0, >0, 4] or [>0, 4]");
NVDR_CHECK(rast.size(0) == color.size(0) && pos.size(0) == color.size(0), "minibatch size mismatch between inputs color, rast, pos");
}
else
{
NVDR_CHECK(pos.sizes().size() == 2 && pos.size(0) > 0 && pos.size(1) == 4, "pos must have shape [>0, >0, 4] or [>0, 4]");
NVDR_CHECK(rast.size(0) == color.size(0), "minibatch size mismatch between inputs color, rast");
}
// Extract input dimensions.
p.numVertices = pos.size(p.instance_mode ? 1 : 0);
p.numTriangles = tri.size(0);
p.n = color.size(0);
p.height = color.size(1);
p.width = color.size(2);
p.channels = color.size(3);
// Get input pointers.
p.color = color.data_ptr<float>();
p.rasterOut = rast.data_ptr<float>();
p.tri = tri.data_ptr<int>();
p.pos = pos.data_ptr<float>();
p.evHash = (uint4*)(topology_hash.data_ptr<int>());
// Misc parameters.
p.xh = .5f * (float)p.width;
p.yh = .5f * (float)p.height;
// Determine hash allocation size.
p.allocTriangles = 64;
while (p.allocTriangles < p.numTriangles)
p.allocTriangles <<= 1; // Must be power of two.
// Allocate output tensors.
torch::Tensor out = color.detach().clone(); // Use color as base.
torch::TensorOptions opts = torch::TensorOptions().dtype(torch::kFloat32).device(torch::kCUDA);
torch::Tensor work_buffer = torch::empty({p.n * p.width * p.height * 8 + 4}, opts); // 8 int for a maximum of two work items per pixel.
p.output = out.data_ptr<float>();
p.workBuffer = (int4*)(work_buffer.data_ptr<float>());
// Clear the work counters.
NVDR_CHECK_CUDA_ERROR(cudaMemsetAsync(p.workBuffer, 0, sizeof(int4), stream));
// Verify that buffers are aligned to allow float2/float4 operations.
NVDR_CHECK(!((uintptr_t)p.pos & 15), "pos input tensor not aligned to float4");
NVDR_CHECK(!((uintptr_t)p.rasterOut & 7), "raster_out input tensor not aligned to float2");
NVDR_CHECK(!((uintptr_t)p.workBuffer & 15), "work_buffer internal tensor not aligned to int4");
NVDR_CHECK(!((uintptr_t)p.evHash & 15), "topology_hash internal tensor not aligned to int4");
// Choose launch parameters for the discontinuity finder kernel and launch.
void* args[] = {&p};
dim3 blockSize(AA_DISCONTINUITY_KERNEL_BLOCK_WIDTH, AA_DISCONTINUITY_KERNEL_BLOCK_HEIGHT, 1);
dim3 gridSize = getLaunchGridSize(blockSize, p.width, p.height, p.n);
NVDR_CHECK_CUDA_ERROR(cudaLaunchKernel((void*)AntialiasFwdDiscontinuityKernel, gridSize, blockSize, args, 0, stream));
// Determine optimum block size for the persistent analysis kernel and launch.
int device = 0;
int numCTA = 0;
int numSM = 0;
NVDR_CHECK_CUDA_ERROR(cudaGetDevice(&device));
NVDR_CHECK_CUDA_ERROR(cudaOccupancyMaxActiveBlocksPerMultiprocessor(&numCTA, (void*)AntialiasFwdAnalysisKernel, AA_ANALYSIS_KERNEL_THREADS_PER_BLOCK, 0));
NVDR_CHECK_CUDA_ERROR(cudaDeviceGetAttribute(&numSM, cudaDevAttrMultiProcessorCount, device));
NVDR_CHECK_CUDA_ERROR(cudaLaunchKernel((void*)AntialiasFwdAnalysisKernel, numCTA * numSM, AA_ANALYSIS_KERNEL_THREADS_PER_BLOCK, args, 0, stream));
// Return results.
return std::tuple<torch::Tensor, torch::Tensor>(out, work_buffer);
}
//------------------------------------------------------------------------
// Gradient op.
std::tuple<torch::Tensor, torch::Tensor> antialias_grad(torch::Tensor color, torch::Tensor rast, torch::Tensor pos, torch::Tensor tri, torch::Tensor dy, torch::Tensor work_buffer)
{
const at::cuda::OptionalCUDAGuard device_guard(device_of(color));
cudaStream_t stream = at::cuda::getCurrentCUDAStream();
AntialiasKernelParams p = {}; // Initialize all fields to zero.
p.instance_mode = (pos.sizes().size() > 2) ? 1 : 0;
// Check inputs.
NVDR_CHECK_DEVICE(color, rast, pos, tri, dy, work_buffer);
NVDR_CHECK_CONTIGUOUS(color, rast, pos, tri, work_buffer);
NVDR_CHECK_F32(color, rast, pos, dy, work_buffer);
NVDR_CHECK_I32(tri);
// Sanity checks.
NVDR_CHECK(dy.sizes().size() == 4 && dy.size(0) > 0 && dy.size(1) > 0 && dy.size(2) > 0 && dy.size(3) > 0, "dy must have shape[>0, >0, >0, >0]");
NVDR_CHECK(color.sizes().size() == 4 && color.size(0) > 0 && color.size(1) > 0 && color.size(2) > 0 && color.size(3) > 0, "color must have shape[>0, >0, >0, >0]");
NVDR_CHECK(rast.sizes().size() == 4 && rast.size(0) > 0 && rast.size(1) > 0 && rast.size(2) > 0 && rast.size(3) == 4, "raster_out must have shape[>0, >0, >0, 4]");
NVDR_CHECK(tri.sizes().size() == 2 && tri.size(0) > 0 && tri.size(1) == 3, "tri must have shape [>0, 3]");
NVDR_CHECK(color.size(1) == rast.size(1) && color.size(2) == rast.size(2), "color and raster_out inputs must have same spatial dimensions");
NVDR_CHECK(color.size(1) == dy.size(1) && color.size(2) == dy.size(2) && color.size(3) == dy.size(3), "color and dy inputs must have same dimensions");
if (p.instance_mode)
{
NVDR_CHECK(pos.sizes().size() == 3 && pos.size(0) > 0 && pos.size(1) > 0 && pos.size(2) == 4, "pos must have shape [>0, >0, 4] or [>0, 4]");
NVDR_CHECK(rast.size(0) == color.size(0) && pos.size(0) == color.size(0), "minibatch size mismatch between inputs color, raster_out, pos");
NVDR_CHECK(dy.size(0) == color.size(0) && rast.size(0) == color.size(0) && pos.size(0) ==color.size(0), "minibatch size mismatch between inputs dy, color, raster_out, pos");
}
else
{
NVDR_CHECK(pos.sizes().size() == 2 && pos.size(0) > 0 && pos.size(1) == 4, "pos must have shape [>0, >0, 4] or [>0, 4]");
NVDR_CHECK(rast.size(0) == color.size(0), "minibatch size mismatch between inputs color, raster_out");
NVDR_CHECK(dy.size(0) == color.size(0) && rast.size(0) == color.size(0), "minibatch size mismatch between inputs dy, color, raster_out");
}
// Extract input dimensions.
p.numVertices = pos.size(p.instance_mode ? 1 : 0);
p.numTriangles = tri.size(0);
p.n = color.size(0);
p.height = color.size(1);
p.width = color.size(2);
p.channels = color.size(3);
// Ensure dy is contiguous.
torch::Tensor dy_ = dy.contiguous();
// Get input pointers.
p.color = color.data_ptr<float>();
p.rasterOut = rast.data_ptr<float>();
p.tri = tri.data_ptr<int>();
p.pos = pos.data_ptr<float>();
p.dy = dy_.data_ptr<float>();
p.workBuffer = (int4*)(work_buffer.data_ptr<float>());
// Misc parameters.
p.xh = .5f * (float)p.width;
p.yh = .5f * (float)p.height;
// Allocate output tensors.
torch::Tensor grad_color = dy_.detach().clone(); // Use dy as base.
torch::Tensor grad_pos = torch::zeros_like(pos);
p.gradColor = grad_color.data_ptr<float>();
p.gradPos = grad_pos.data_ptr<float>();
// Clear gradient kernel work counter.
NVDR_CHECK_CUDA_ERROR(cudaMemsetAsync(&p.workBuffer[0].y, 0, sizeof(int), stream));
// Verify that buffers are aligned to allow float2/float4 operations.
NVDR_CHECK(!((uintptr_t)p.pos & 15), "pos input tensor not aligned to float4");
NVDR_CHECK(!((uintptr_t)p.workBuffer & 15), "work_buffer internal tensor not aligned to int4");
// Determine optimum block size for the gradient kernel and launch.
void* args[] = {&p};
int device = 0;
int numCTA = 0;
int numSM = 0;
NVDR_CHECK_CUDA_ERROR(cudaGetDevice(&device));
NVDR_CHECK_CUDA_ERROR(cudaOccupancyMaxActiveBlocksPerMultiprocessor(&numCTA, (void*)AntialiasGradKernel, AA_GRAD_KERNEL_THREADS_PER_BLOCK, 0));
NVDR_CHECK_CUDA_ERROR(cudaDeviceGetAttribute(&numSM, cudaDevAttrMultiProcessorCount, device));
NVDR_CHECK_CUDA_ERROR(cudaLaunchKernel((void*)AntialiasGradKernel, numCTA * numSM, AA_GRAD_KERNEL_THREADS_PER_BLOCK, args, 0, stream));
// Return results.
return std::tuple<torch::Tensor, torch::Tensor>(grad_color, grad_pos);
}
//------------------------------------------------------------------------