Understanding Sample In Interpolation in GLSL

This article examines the sample in interpolation qualifier in GLSL fragment shaders, detailing how it alters variable interpolation and fragment shader execution during multisample anti-aliasing (MSAA). It covers the default behavior of MSAA shading, how the sample qualifier forces per-sample evaluation, the syntactic usage, and the associated performance implications.

Default MSAA vs. Sample Interpolation

In standard OpenGL multisample anti-aliasing (MSAA), depth and coverage tests occur at individual subpixel sample locations, but the fragment shader typically executes only once per pixel. By default, inputs qualified with smooth or evaluated without an explicit qualifier are interpolated at the pixel's center. If the pixel center lies outside the geometry boundary, this can produce extrapolation artifacts. While the centroid qualifier restricts interpolation to the center of the covered samples within the pixel, it still executes the fragment shader once per primitive per pixel.

The Behavior of the sample Qualifier

The sample qualifier modifies this pipeline behavior entirely. When applied to an input variable, it mandates that the variable must be interpolated independently at each individual sample location rather than at the pixel center or centroid.

Key behaviors include:

  • Forced Per-Sample Shading: Declaring any fragment input with sample in causes the GPU to execute the fragment shader at sample frequency rather than pixel frequency for covered samples. If a pixel has 4x MSAA enabled and all four samples are covered, the fragment shader runs four separate times for that pixel.
  • Exact Sample Locations: For each invocation, inputs marked with sample in are evaluated directly at the specific subpixel coordinate of the corresponding sample point, eliminating geometric interpolation artifacts and edge aliasing caused by center evaluation.
  • Interaction with Built-in Variables: Using sample in has an effect equivalent to referencing gl_SampleID or gl_SamplePosition. Either condition requires the pipeline to switch from per-pixel shading to per-sample shading.

Syntax and Usage

The sample keyword acts as an auxiliary storage qualifier and can be combined with interpolation qualifiers such as smooth (perspective-correct, default) or flat.

#version 450 core

// Evaluated independently at each sample position
sample in vec2 v_TexCoord;
sample smooth in vec4 v_Color;

out vec4 fragColor;

void main()
{
    fragColor = texture(u_Texture, v_TexCoord) * v_Color;
}

If an input is declared as flat, the sample qualifier has no effect on the value itself (since flat values are not interpolated), but declaring it as sample flat in will still trigger per-sample fragment shader execution.

Performance Considerations

Using sample in significantly increases the computational load on the GPU. Because the fragment shader executes once for every covered sample rather than once per pixel, fragment processing costs scale directly with the MSAA sample count (e.g., up to 4x or 8x the arithmetic and texture fetch load). Consequently, sample in should only be used when high-frequency variations inside a primitive—such as alpha testing, procedural patterns, or subpixel shading details—require true supersampling quality at geometry edges.