HNHacker News
TopNewBestAskShowJobs

ack_complete

833 karma · joined January 8, 2022

submissionscomments
ack_complete··on Oldest GUI application that still runs on Windows 11
As someone who does raw Win32 API based UI... no. The Win32 UI system has been neglected for many years and is missing very basic functionality by modern standards, including dark mode support, antialiased rendering, hardware accelerated image stretching, and wide color gamut / HDR support. You're going to be working around a lot of ancient restrictions compared to a more modern UI and rendering layers on top of it.
ack_complete··on C vs. C#: racing VLC's Gaussian blur
It's also a basic implementation, doing a divide per sample to renormalize and not taking advantage of the symmetry of the kernel.

Even on a GPU, you wouldn't use an algorithm this simple in production. For small radii, leveraging bilinear filtering halves the number of samples. For larger radii, hierarchical pyramid approximations are popular.

ack_complete··on Laptop Based on 6502 CPU
Nitpick, the laptop mentioned is actually using a 65C02 which does have STP (stop clock) and WAI (wait for interrupt) instructions.
ack_complete··on Laptop Based on 6502 CPU
Segment overrides were also painless to use, a single byte segment prefix byte was all that was needed to revector a memory operand to a different segment selector for the next instruction. With bank switching you'd have to use extra instructions and/or registers to switch the banking window to the desired bank and back, and possibly bounce to a routine in RAM to do that if you only had one banking window (which was quite common).

Banking registers also weren't always readable, in which case either you'd need to shadow the banking register or avoid nested/interrupt scenarios.

I'd prefer 8086 segmentation any day over the headache of trying to execute 6502 code from a bank-switched cartridge with a single banking window and a write-only banking register.

ack_complete··on PalmOS Lemmings
It was not at the time: https://www.engadget.com/2010-07-02-unofficial-lemmings-for-...
ack_complete··on I love software rendering
Precise and consistent fill conventions don't need barycentric coordinates, it simply needs some care in rasterization. Chris Hecker's 1985 texture mapping series in Game Developer covered how to do this properly in a traditional software scanline rasterizer. The necessary prestepping isn't expensive.
ack_complete··on MS Paint Adds Freeform Rotation (2026)
One of the sillier regressions, which was thankfully fixed, was that the new Paint used to draw the marching ants animation around a selection regardless of whether the app was in the foreground. An instance of Paint with a rectangular selection would eat 5% of the GPU continuously in the background.
ack_complete··on Who is vfmaddrnd231pd?
You're assuming that the asm syntax is targeted at human readability, when it's at least as much to ease the complexity of the assembler and disassembler.

If the FMA instruction syntax was designed for readability, then it would have used 4-argument syntax with a requirement for two registers to match instead of using the 1/2/3 encodings. But the reason why it uses those names instead is that it's more consistent with the instruction encoding and the format of most other vector instructions: the register/memory argument is last.

Similarly, x86 vector instructions that take an immediate byte cram a bunch of options into that byte, such as shuffle masks or operation options. The assembly syntax does not help constructing this byte at all. But that's because it's meant to map straightforwardly to the instruction encoding, not to be easy to manually read or write.

ARM assembly tends to be a bit more consistent, but has some similar quirks. The majority of ARM instructions are dst,src, but store instructions are reversed as src,dst so they have the memory argument second just like load instructions.

ack_complete··on If somebody tries to hot-patch an already-hot-patched function
No. API Sets use forwarding within the loader and are largely transparent to regular/delayed binding and GetProcAddress(). That would be fine. This is overwriting the prologue of the function in user32.dll similar to any other user-space hooking library.
ack_complete··on If somebody tries to hot-patch an already-hot-patched function
They've also used Detours within Windows itself. The auto super resolution (AutoSR) feature works by dxgi.dll detouring specific calls in user32.dll, in-process, to virtualize certain monitor metrics. I found this out because it was broken for a while on Windows 11 ARM64 when it couldn't handle PAC-enabled function prologs and enabling it would just crash programs by corrupting user32 functions.
ack_complete··on Integer multiplication below n log n
This looks more like word salad instead of any other FFT algorithm paper I've seen, such as the tangent FFT paper that broke the lower bound previously established by split-radix. I'd have to defer to someone who might be able to decode this.
ack_complete··on Shipping JPEG XL in Chrome
WIC is reasonably widely used since it's used by WPF to load images. The problem is that a plugin codec structure exposes you to bad codecs. We had a tool at work break because someone installed a fast image viewer that overrode the default WIC JPEG decoder with a faster one that crashed loading our tool's splash screen image.
ack_complete··on Integer multiplication below n log n
It's potentially very interesting because there are a number of critical algorithms that are all related and share asymptotic lower bounds as a result. My first thought on seeing this was whether a proven result here would also open the door for FFTs to go below O(n log n).
ack_complete··on The state of SIMD in Rust in 2026
>So? AVX-512 shouldn't exist because it can't be retroactively enabled on older hardware? or because Intel can't say goodbye to Skylake? I don't understand the logic.

No one's saying it shouldn't exist, but it's a different story to ship software that requires it unconditionally, particularly if you are targeting the consumer market instead of only servers.

Not sure why you keep referring to Skylake since Intel hasn't shipped a Skylake-based CPU in years, and the most problematic CPUs currently shipping that lack AVX-512 support are several architectural generations ahead of Skylake, for both the P-cores and E-cores.

> Good thing Intel hasn't shipped a viable consumer-level CPU in years either. What should never have happened is Intel removing AVX-512.

Agreed on not removing, but saying that Intel hasn't shipped a viable consumer-level CPU in years is silly. They still ship huge volumes of CPUs, especially in laptops where AMD is still underrepresented.

> At one point, Intel integrated graphics were literally the most common individual GPU in the Steam Hardware Survey - Intel HD 4000 held the #1 spot until the GTX 970 overtook it in late 2015. Does that mean developers shouldn't have targeted discrete GPUs either, just because most survey participants didn't have the hardware they wanted to target?

Targeting a discrete GPU is different than not supporting integrated GPUs at all, which would be analogous. And many games do have to support integrated graphics even if the performance is not great, precisely because they don't aim high enough in the market to be able to ignore iGPUs entirely.

I also mention the Steam Hardware Survey because it tends to overrepresent users with higher end rigs. If you look at the non-gaming market, the hardware level tends to be considerably worse, and as a result a lot of productivity programs still ship plain SSE2 as their baseline required target.

ack_complete··on The state of SIMD in Rust in 2026
AVX2 is much more prevalent than AVX-512 and thus tenable to require. RHEL is switching to x86-64-v3 baseline, for instance, which requires AVX2. AVX-512, on the other hand, has been moving backwards since Intel has not shipped any consumer-level CPUs with it for years now. The Steam Hardware Survey has AVX2 at 95.4% while AVX512F is still far behind at 23.9%.
ack_complete··on The state of SIMD in Rust in 2026
Both. The specific documentation I'm referring to is their optimization guides, such as the Cortex-A72 optimization guide:

https://support.arm.com/documentation/uan0016/a/

This has detailed information on latencies and throughput, which are important when optimizing SIMD code. But ARM doesn't publish optimization guides for all their cores.

On top of that, the cores are often modified in significant ways. Snapdragon CPUs, for instance, have used modified Cortex cores in the past and can have performance differences from the original core.

To be fair, Intel's been slacking a lot on this too, not even bothering to update their own optimization guide for their latest cores. But that's made up for the community mining this information in great detail on sites like uops.info, and also being a lot less x86 cores to deal with. On the ARM side, there's practically not much analogous other than the Apple M1 microarchitecture analysis.

ack_complete··on C's Flexible Integer Sizes Were Not a Design Mistake
The 68000 was a practical example of where mapping int as the "most convenient" size isn't very clear even within a single CPU. The instruction set handled 32-bit integers well, but execution-wise 16-bit integers were faster. Some compilers like Lattice C defined int as int32, while others like Aztec C mapped it to int16.

One result of this is that a fair amount of C code targeted at 68000 systems used short instead int everywhere, and then had to be subsequently updated for CPUs that preferred int32 to int16. Occasionally collateral damage can be seen from this in mysterious comments like "check if the buffer is too int."

ack_complete··on The state of SIMD in Rust in 2026
Pretty sure it only actually currently needs SSE4, since they started compiling it with POPCNT for x86. The official system requirement is Intel 8th gen CPU, but Intel made Kaby Lake and Coffee Lake CPUs that lack AVX.
ack_complete··on The state of SIMD in Rust in 2026
AArch64 definitely has a much more comprehensive baseline than x86-64, but there are some optional extensions that are situationally impactful, including the Crypto extension and some of the newer accumulation / dot product instructions. And unlike Intel, ARM has no portable equivalent to CPUID for querying feature flags and is terrible at documenting which intrinsics require specific FEAT_* flags.

The ARM-based CPU manufacturers make this worse by posting almost no low-level documentation for their CPUs. For basically any mainstream x86 CPU, it's trivial to find documentation listing what ISA level it supports and general execution widths and latencies for common operations. For the majority of ARM CPUs, there's absolutely nothing. ARM only has optimization guides for selected Cortex cores, and NVIDIA published info for their Olympus core. But execution details had to be reverse engineered for Apple M1, and there is nothing for Oryon. This is especially bad for in-order cores, which unfortunately is still relevant because new CPUs are still being shipped with in-order efficiency cores.

ack_complete··on Amiga Screens: A Primer
No, there is actually a difference between an interlaced and non-interlaced signal. A non-interlaced signal has an integral number of lines per field without the half-line that an interlaced signal would have. With a non-interlaced signal, a classic CRT will scan all of the fields with the same alignment instead of interleaving even/odd fields vertically. There was a definite visual difference between a non-interlaced mode and an interlaced mode repeating the same screen for both fields.
ack_complete··on C++26: Trivial infinite loops are no longer undefined behaviour
Yes, but the compiler does have to preserve any observable behavior produced by the call to the standard library function. Being able to omit this inserted yield() by the as if rule would mean that it isn't observable, which would also mean that the compiler could already add or not add it anywhere as needed without changing the behavior of the program. Which would seemingly make the inserted yield() pointless as it would have no effect.
ack_complete··on C++26: Trivial infinite loops are no longer undefined behaviour
What I'm most annoyed at with the variable initialization change is that:

  - It's potentially a performance change in every single function, especially ones that have sizable fixed-size buffers
  - If you have regressions you have to spray [[indeterminate]] everywhere, because there is no coarser way of suppressing it.
  - While the language says unrecognized attributes are ignored, compilers frequently warn on unrecognized attributes. Clang, for instance, currently warns on [[indeterminate]].
  - There is no defined macro name for backwards compatibility.
Which means that libraries are going have to all declare their own macros for [[indeterminate]] and pepper their code with it.
ack_complete··on Subnormal floating-point numbers are expensive on Intel processors
> AFAIK ARM NEON always works in that mode

This was only true for ARMv7 NEON (32-bit). ARMv8 / AArch64 NEON is IEEE compliant.

ack_complete··on Accurate Models of AMD Matrix Cores
Pretty sure the internal precision setting works the same way on the 8087, it's documented in the original 8087 datasheet. Windows sets it to 53-bit so there are no excess precision surprises with doubles, and you could run Windows 95 with an 80386 + 80287.
ack_complete··on On Binary Translation and Its Consequences
> though it seems to be off by default since MSVC2022

This seems to be a typo in the docs, VS2022 is 17.x and still generates volatile metadata. VS2026 is 18.x.

Last time I tested it, the penalty in Prism for running x64 code without volatile metadata was ~25% on Snapdragon X.

ARM64EC code is essentially x64 code pre-translated to ARM64. It's built against the x64 emulation ABI conventions but runs directly as native ARM64 code. Translation thunking conventions allow for cross-calling between ARM64EC and emulated x64 code.

A lot of the OS libs are shipped in Windows 11 ARM as ARM64X, so they're hybrid ARM64EC+ARM64. x86 libs like MSVCRT.DLL do still seem to be compiled with volatile metadata. DUMPBIN /LOADCONFIG reveals if volatile metadata has been included.

ack_complete··on Microcode in Intel's 8087 floating-point chip: the scale instruction
Strange, because .NET was specifically designed to be a JITted environment and taking advantage of SSE2 when available would ordinarily be an advantage of a JIT. But sure enough, .NET 4.0 x86 still uses x87 instructions for math. It's not even good x87, this is surprisingly bad:

  01b2086a 8975e4          mov     dword ptr [ebp-1Ch],esi
  01b2086d db45e4          fild    dword ptr [ebp-1Ch]
  01b20870 d95de4          fstp    dword ptr [ebp-1Ch]
  01b20873 d945e4          fld     dword ptr [ebp-1Ch]
  01b20876 d80dcc08b201    fmul    dword ptr ds:[1B208CCh]
  01b2087c d95804          fstp    dword ptr [eax+4]
And that should be with optimization enabled, I didn't start it from the debugger.

But clearly it has some support for using SSE2 when available, because it does use it for zeroing memory:

  01b20884 0f57c0          xorps   xmm0,xmm0
  01b20887 660fd607        movq    mmword ptr [edi],xmm0
  01b2088b 660fd64708      movq    mmword ptr [edi+8],xmm0
ack_complete··on Microcode in Intel's 8087 floating-point chip: the scale instruction
There is a significant difference between a stack-based ISA and a stack-based bytecode. In bytecode, it's fine or even a requirement to empty the stack between loop iterations. The JIT will then enregister variables across the loop as appropriate.

With x87, however, that causes extra overhead from loads and stores that's best avoided. Unused stack space can be used to cache frequently used variables, but as operations must use ST(0) as one parameter, FXCH instructions must be used to swap around variables. Matching the x87 stack state on entry and exit of the loop is tricky and compilers historically have had trouble doing it. Different FPUs also differed on the efficiency of FXCH so there were often situations where a particular arrangement would double the speed of a routine on one CPU model and halve it on another.

ack_complete··on Show HN: Compute polynomials twice as fast
The answer's all over the place with each successive CPU generation. Originally Intel CPUs had adds faster than multiplies, then both went through the FMA unit so they were the same, then they added a fast FP adder, etc. And current timings on uops.info now show FP fma 4c and mul 3c over two multiply units, and add 2c over two separate addition units.
ack_complete··on Implementation of GCC's Nested Functions (vs. C++ Lambdas)
Sadly, I've never seen a C++ compiler use this (old) technique for lambda reference captures. The main compilers all seem to just use individual references for each capture instead of a single reference to the stack frame, which makes the lambdas with a lot of reference captures more expensive.
ack_complete··on Paint.net 5.2 alpha now runs on Linux
Direct2D has some complex algorithms because it was designed for high-quality antialiased rasterization on DX9-class hardware, particularly tesselation, and suitable not only for vector graphics but also text glyphs. This bleeds over into the API, which is quite complex and somewhat annoying at times. It revives the GDI-style interface of needing to create and select a solid brush object instead of just passing a color, and drawing text with colored spans is embarrassingly involved (it involves writing a custom rendering bridge between Direct2D and DirectWrite).

The other problem is that Wine has only implemented a minimal amount of the Direct2D API to get specific programs working that aren't heavy graphics programs. Two major omissions, the last time I looked, were that Wine's implementation does not support antialiasing at all, and its ArcTo() draws a line.

Page 1 of 11Next →