HNHacker News
TopNewBestAskShowJobs

exDM69

10,584 karma · joined February 2, 2010

submissionscomments
exDM69··on Ask HN: What Are You Working On? (June 2025)
Admirable perseverance!

I've always also had a side project or two in this domain but I've never managed to stick with one for more than 3-5 years.

exDM69··on No More Shading Languages: Compiling C++ to Vulkan Shaders [pdf]
> How would you use shared/local memory in GLSL?

In compute shaders the `shared` keyword is for this.

exDM69··on Rendering Crispy Text on the GPU
Thanks for the words of encouragement. I need more time to turn this prototype into a practical piece of software and/or a publication (blog post or research paper). Unfortunately there are only so many hours in a day.

To actually render text I would still need to add text shaping to get from strings of text to pixels on the screen.

But a bigger problem is how to integrate it into someone else's software project. I have the rasterizer GPU shader and some CPU preprocessing code and the required 3d API code (I'm using Vulkan). I'm not sure how people usually integrate this kind of components to their software, do they just want the shader and preprocessor or do they expect the 3d API code too. Packaging it into a library that has the Vulkan code too has its own problems with interoperability.

You need to hope that it rains during my summer vacation, maybe this project will see some progress :)

exDM69··on Rendering Crispy Text on the GPU
> What's a "monotonic Bezier curve"?

Good question!

It's a Bezier curve that has a non-zero derivative for t=0..1 (exclusive).

Just your high school calculus definition of monotonic.

To get from a general quadratic Bezier to monotonic sections, you solve the derivative for zeros in x and y direction (a linear equation). If the zeros are between 0 and 1 (exclusive), split the Bezier curve using de Casteljau's at t=t_0x and t=t_0y. For each quadratic Bezier you get one to three monotonic sections.

> every Bezier curve is contained within its control points' convex hull.

This is true, but only monotonic Bezier curves are contained between the AABB formed by the two end points (so control points in the middle don't need to be considered outside the AABB).

For a quadratic Bezier this means that it is monotonic iff the middle control point is inside the AABB of the two end points.

The monotonicity is a requirement for all the GPU warp level AABB magic to happen (which is a nice 10x to 20x perf increase in my benchmarks). At worst you'd have to deal with 3x the number of curves after splitting (still a win), but because most curves in fonts are monotonic the splitting doesn't increase the the number of curves a lot in practice.

Monotonicity also implies that the quadratic equations have only one unique solution for any horizontal or vertical line. No need to classify the roots as in Lengyel's method.

exDM69··on Rendering Crispy Text on the GPU
Very cool stuff, text rendering is a really hairy problem.

I also got nerd sniped by Sebastian Lague's recent video on text rendering [0] (also linked to in the article) and started writing my own GPU glyph rasterizer.

In the video, Lague makes a key observation: most curves in fonts (at least for Latin alphabet) are monotonic. Monotonic Bezier curves are contained within the bounding box of its end points (applies to any monotonic curve, not just Bezier). The curves that are not monotonic are very easy to split by solving the zeros of the derivative (linear equation) and then split the curve at that point. This is also where Lague went astray and attempted a complex procedure using geometric invariants, when it's trivially easy to split Beziers using de Casteljau's algorithm as described in [1]. It made for entertaining video content but I was yelling at the screen for him to open Pomax's Bezier curve primer [1] and just get on with it.

For monotonic curves, it is computationally easy to solve the winding number for any pixel outside the bounding box of the curve. It's +1 if the pixel is to the right or below the bounding box, -1 if left or above and 0 if outside of the "plus sign" shaped region off to the diagonals.

Further more, this can be expanded to solving the winding number for an entire axis aligned box. This can be done for an entire GPU warp (32 to 64 threads): each thread in a warp looks at one curve and checks if the winding number is the same for the whole warp and accumulate, if not, set a a bit that this curve needs to be evaluated per thread.

In this way, very few pixels actually need to solve the quadratic equation for a curve in the contour.

There's still one optimization I haven't done: solving the quadratic equation in for 2x2 pixel quads. I solve both vertical and horizontal winding number for good robustness of horizontal and vertical lines. But the solution for the horizontal quadratic for a pixel and the pixel below it is the same +/- 1, and ditto for vertical. So you can solve the quadratic for two curves (a square root and a division, expensive arithmetic ops) for the price of one if you do it for 2x2 quads and use warp level swap to exchange the results and add or subtract 1. This can only be done in orthographic projection without rotation, but the rest of the method also works in with perspective, rotation and skew.

For a bit of added robustness, Jim Blinn's "How to solve a quadratic equation?" [2] can be used to get rid of some pesky numerical instability.

I'm not quite done yet, and I've only got a rasterizer, not the other parts you need for a text rendering system (font file i/o, text shaping etc).

But the results are promising: I started at 250 ms per frame at a 4k rendering of a '@' character with 80 quadratic Bezier curves, evaluating each curve at each pixel, but I got down to 15 ms per frame by applying the warp vs. monotonic bounding box optimizations.

These numbers are not very impressive because they are measured on a 10 year old integrated laptop GPU. It's so much faster on a discrete gaming GPU that I could stop optimizing here if it was my target HW. But it's already fast enough for real time in practical use on the laptop because I was drawing an entire screen sized glyphs for the benchmark.

[0] https://www.youtube.com/watch?v=SO83KQuuZvg [1] https://pomax.github.io/bezierinfo/#splitting [2] https://ieeexplore.ieee.org/document/1528437

exDM69··on Air-dried vs. Kiln-dried Wood
Cool. I've also built a bar stool with green wood but it's a fairly crude shop stool rather than a fine chair.

A green wood specialty in my neck of the woods is sauna ladles (used for throwing water). You can buy wooden ones but they are made from seasoned lumber with CNC machines and don't survive more than a year before they crack. The one I made from green wood is still going strong after 7 years in extreme humidity and temperature environment.

exDM69··on Air-dried vs. Kiln-dried Wood
Yeah, the coefficients are the same but the initial moisture content in green wood is much higher than the wood will ever get to after seasoning, it won't suck that much moisture from the air (unless you're in a swamp or something). So the annual absolute change in millimeters is lower than from green to seasoned.

I have my woodworking projects in temperatures ranging from -25C to +100C (sauna) and extreme humidity changes from near zero to 100% RH. It is a form of art to make wooden things survive that, and I don't always succeed.

exDM69··on Air-dried vs. Kiln-dried Wood
The figures I gave are annual movement. Initial shrinkage is larger when drying from green wood. The numbers (from the calculator) match my empirical observations very closely.

By the way your relative humidity figures assume constant temperature. Wood cares about absolute humidity (mass of vapor per volume of air), and temperature is the dominant factor in absolute humidity. Rainy day at +1C (100% RH) is less absolute humidity than a sunny day at +30C.

This matters to me a lot because half of my woodworking projects are outdoors or not temperature controlled indoors.

exDM69··on Air-dried vs. Kiln-dried Wood
4 years is more than enough time for drying. Rule of thumb is year per inch of thickness.

I'm just speculating here but probably the support structure didn't allow for wood movement. You need something to keep the table top flat while allowing it to move. Screwing it to a stiff frame (steel or cross grain wodo) is certain to crack when the wood moves.

Breadboard ends, sliding dovetails or steel support with elongated holes (going to a threaded insert and bolt) are good ways to support a table top.

The wood was probably stabilized to your shop atmosphere but indoors in the dry winter, maybe with air conditioning or a fire place, and there's going to be movement.

Kiln drying does not stop seasonal wood movement.

If you share a picture we can take an educated guess what caused the table to warp and crack.

exDM69··on Air-dried vs. Kiln-dried Wood
Green woodworking is an entire field of its own. Not very common in industrial scale but it was a common method a few centuries ago.

Examples of things where green woodworking is common: spoon carving, bowl turning, chair making, etc.

The idea is that wood is worked while green to make 80% finished blanks, which are dried slowly for some months or years before finishing the rest of it. This gives less distortion to the shape as it dries. And the drying times are faster because it's all small pieces at that point. The time from tree to product is shorter.

It is an almost extinct craft but it is a lot of fun for woodworkers not under schedule pressure.

exDM69··on Air-dried vs. Kiln-dried Wood
A good mental model for wood is that trees are a bunch of stacked cones (growth rings) on top of each other.

In the spring it fills with water and the diameter grows but the tree does not get longer because it needs to support a large mass on top and the lengthwise fibers are not able to grow and shrink (they need to be stiff to carry the weight).

Because of this, the circumference of the outermost growth rings need to grow more than the inner ones.

Now cut a board out of it and look at the end grain. Think what happens when the rings closer to the outside need to shrink more than the inner ones for the same humidity change. For a flat sawn board, you will always see it cup so that the concave side is on the outside.

This doesn't explain why boards twist or bow but cupping is the most prevalent wood movement in typical flat sawn boards.

exDM69··on Air-dried vs. Kiln-dried Wood
This is correct but the numbers are off by an order of magnitude. The annual movement of wood is maybe 2% width wise and almost negligible lengthwise.

This is for wood that is dried and stabilized, the shrinking is a bit more from green wood to seasoned lumber (but not an order of magnitude more).

You can use online calculators such as this one for estimates based on the species of wood and your location: https://kmtools.com/pages/wood-movement-calculator

The numbers here match my experience, a 600mm wide spruce table top shrunk and expanded by about 12mm during a year of being outdoors but under a roof at temperatures from -25C to +30C. The structure had sliding dovetails to allow growth but keep it flat.

exDM69··on Faster sorting with SIMD CUDA intrinsics (2024)
A 32 way GPU sorting algorithm might be just what I need for sorting and deduplicating triangle id's in a visibility buffer renderer I am working on.

Thanks for sharing.

exDM69··on Procedural Textures with Hash Functions
Hey, this might be exactly what I'm looking for!

To test some 3d graphics code, I need to generate a lot of textures. From a technical standpoint, just a single color texture would do but having some recognizable patterns that are easy to distinguish by eye would be useful to check for correctness and glitches.

Thanks for sharing.

exDM69··on Shadertoys Ported to Rust GPU
> Yeah, that will work fine for byte address buffers, to lesser extent constant buffers (they don’t convert data types but the access sematic and alignment are a bit tricky), but not much else.

This is where sharing the CPU and GPU side struct declaration is helpful. With scalar block layout (VK_EXT_scalar_block_layout in Vulkan, not sure how about d3d land) you don't even need to worry about alignment rules because they're the same for GPU and CPU (just make sure your binding base address/offset is aligned).

> Vertex buffers, textures, and texel buffers / typed buffers in D3D are all widely used in real-time graphics.

Of course. You don't get to share "structs" here between CPU and GPU here transparently because you need to program the GPU hardware (vertex input, texture samplers) to match.

There are some reflection based trickery that can help here but rust-gpu afaik doesn't do that. I've seen some projects use proc macros to generate vertex input layout config for GL/Vulkan from Rust structs with some custom #[attribute] annotations.

> Pretty sure it’s hardware.

Now this is just guessing.

> Emulating anisotropic texture sampler with HLSL codes would need hundreds of instructions...

Texture sampling / interpolation is certainly hardware.

But the conversion from rgba8_unorm to rgba32f, for example? Or r10g10b10a2?

I've not seen any conclusive benchmark results that suggest whether it's faster to just grab these from a storage buffer in a shader and do the few arithmetic instructions or whether it's faster to use an texel buffer. Images are a different beast entirely due to tiling formats (you can't really memory map them so the point of sharing struct declarations is irrelevant).

> Here’s a benchmark for vertex buffers

I am familiar with this benchmark from 8 years ago, which is highly specific to vertex buffers (and post transform cache etc). It's a nicely done benchmark but it has two small flaws in it: the hw tested is quite old by now and it doesn't take into account the benefit of improved batching / reduced draw calls that can only be done with custom vertex fetch (so you don't need BindVertex/IndexBuffer calls). It would be great if this benchmark could be re-run with some newer hw.

But this benchmark doesn't answer the question whether the typed buffer format conversions are faster than doing it in a shader (outside of vertex input).

> however on nVidia Maxwell vertex buffers were 2-4 times faster.

The relevant hardware got revamped in Turing series to facilitate mesh shaders, so can't extrapolate the results to present day hardware.

Fwiw. I've been using custom vertex fetch with buffer device address in my projects for a few years now and I haven't noticed adverse performance implications on any hw I've used (Intel, NV and AMD). But I haven't done rigorous benchmarking that would compare to using vertex input stage.

I'm not using rust-gpu for shaders at the moment, but if I was, it would be helpful to just use the same struct declarations. All my vertex data, instance data, constant buffers and compute buffers are an 1:1 translation from Rust to GLSL struct declarations which is just redundant work.

exDM69··on Shadertoys Ported to Rust GPU
> Traditionally they're a black box without any assert() equivalent

Thankfully these days we have printf in shaders that you can use for "asserts". You can detect if the shader printed anything and consider it a failure.

You can even add a conditional print in your pixel shader, run your app in renderdoc and find the pixel(s) that printed something. Once you find one, you can step through it in the shader debugger.

This seemingly simple feature is a huge time saver.

exDM69··on Shadertoys Ported to Rust GPU
If you are using plain buffers the GPU and the CPU access data pretty much exactly the same way. With scalar block layout all the alignments are pretty much the same too.

To get the format conversion stuff you talk about, you need to use images, vertex input or texel buffers and configure the format conversion explicitly.

It's a good question how much of these conversions are actually done by GPU hardware and how much of it is just software (which you could write yourself in a shader and get same perf). I have not seen an apples to apples benchmark about these format conversions.

exDM69··on OpenVertebrate Presents a Database of 13,000 3D Scans of Specimens
There are meshes in morphosource too. Didn't try downloading any but they are available as STL files with 1-2 million polygons per model. Some meshes are individual bones or skulls, others are complete specimens. The interface is a bit clumsy but you can use "mesh" in your search string
exDM69··on Zlib-rs is faster than C
They are marked as unsafe because there are hundreds and hundreds of intrinsics, some of which do memory access, some have side effects and others are arithmetic only. Someone would have to individually review them and explicitly mark the safe ones.

There was a bug open about it and the rationale was that no one with the expertise (some of these are quite arcane) was stepping up to do it. (edit: other comments in this thread suggest that this effort is now underway and first changes were committed a few weeks ago)

You can do safe SIMD using std::simd but it is nightly only at this point.

exDM69··on Planes are having their GPS hacked. Could new clocks keep them safe?
Yes, airports in eastern Europe are now using the old ground based VHF radio beacons (VOR, DME and ILS).

However, they were not in use a few years ago. Some airports never had the ground based equipment installed, others still had the beacons functional but the procedures (STAR, SID) had been phased out in favor of the easier and cheaper satellite based GNSS RNAV procedures.

Some airports had brand new VHF equipment installed, others had the old procedures reinstated.

But aviation is a slow moving, risk averse, cost sensitive business so several airports were inaccessible (apart from visual approach) for a few months.

exDM69··on Show HN: Rust Vector and Quaternion Lib
I'm using Rust (nightly) std::simd for my 3d math stuff. It doesn't come with matrix and quaternion functions but they were relatively simple to implement based on known good algorithms. But you do get basic arithmetic operators without having to implement std::ops by hand (or with macros).

What was/is not pretty is adding some generics so the same code can work with f32 and f64. I did manage to get something that works but it's so ugly that I didn't want to release it. I'm sure it could be improved but what I got works well enough and I haven't needed to touch it in a few years.

std::simd is quite pleasant to work with and most importantly it allows a zero cost fallback to CPU specific intrinsics when needed.

exDM69··on 'Shadow fleets' and sabotage: are Europe's undersea cables under attack?
All of the well documented cases of the past few years have occured in international waters.
exDM69··on 3,200% CPU Utilization
Yes, this is a good idea. I've done this before with binary search and tree structures. I avoid unbounded loops wherever possible and the unavoidable cases are rather rare.

It's not a fix but it is a good mitigation strategy.

Infinite loops are one of the nastiest kind of bugs. Although they are easy to spot in a debugger they can have really unfriendly consequences like OP's "can barely ssh in" situation.

Infinite loops in library code are particularly unpleasant.

exDM69··on US Space Force reveals first look at secretive X-37B space plane in orbit
Correct.

Burns don't have to happen only at perigee/apogee so there's more flexibility in practice. And counter intuitive stuff like bi-elliptic transfers.

exDM69··on US Space Force reveals first look at secretive X-37B space plane in orbit
Burns at perigee have best efficiency to make in-plane changes (raise or lower orbit) due to the Oberth effect.

Burns at apogee have best efficiency for out-of-plane maneuvers (change orbital inclination plane) due to lowest velocity of the spacecraft.

Highly elliptical orbits can do both at a few hours' notice.

exDM69··on DOGE has 'god mode' access to government data
Neither is really true at least for Finland.

Addresses are not public information, you can opt out from having your info public. They are not even a national registry (one exists, not public) but your telco will put you in "the phone book" if you don't opt out.

Taxes are public information but only to a degree. You can opt out from having them shared en masse (primarily to the media) but you can still inquire someone else's paid taxes from the tax office but it requires you to know their full given name, year of birth and home town.

Salary is not public information, only the total amount of paid income taxes. You can correlate them to some degree but you won't be able to know how many jobs a person has or where their capital gains are from.

Access to this information can also be limited in exceptional cases (politicians, harassment victims, identity theft etc).

exDM69··on Asahi Linux lead developer Hector Martin resigns from Linux kernel
> It was perfectly clear what Hellwig meant by "cancer".

No, it is not perfectly clear.

The generous interpretation is that they meant it is "viral", spreading through dependencies across the codebase (which I don't think is technically accurate as long as CONFIG_RUST=n exists).

The less generous way to interpret it is "harmful". The later messages in the thread suggests that this is more likely.

But I'm left guessing here, and I'm willing to give some some benefit of doubt here.

That said, the response to this comment was incredibly bad as well.

exDM69··on Asahi Linux lead developer Hector Martin resigns from Linux kernel
> The position of the DMA maintainer seems also to make sense for me, to keep code maintainable over decades it must remain in a nice and tidy state.

Perhaps so, but that discussion was two or three years ago. Stalling other contributors' work now is counterproductive, especially for changes that do not touch files maintained by them.

This does not justify any brigading behavior, though.

exDM69··on No-Panic Rust: A Nice Technique for Systems Programming
I'm well aware of this and good that the option exists to bail out with abort instead.

But there are still cases where you would like to fsync your mmaps, print out a warning message or just make sure your #[should_panic] negative tests don't trigger false positives in your tooling (like leak detectors or GPU validators) or abort the whole test run.

It's not perfect by any means but it's better than potentially corrupting your data when a trivial assert fires or making negative tests spew warnings in ci runs.

It's very easy to opt out from, and I don't consider the price of panic handlers and unwinding very expensive for most use cases.

exDM69··on No-Panic Rust: A Nice Technique for Systems Programming
Panics also unwind the stack and run all your Drop destructors.

Setting `panic = abort` disables unwinding and this means leaking memory, not closing file descriptors, not unlocking mutexes and not rolling back database transactions on panic. It's fine for some applications to leave this to the operating system on process exit but I would argue that the default unwinding behavior is better for typical userspace applications.

← PreviousPage 4 of 34Next →