Is it possible to find out how many fragments made it through the stencil test? I have an OpenGL application which uses stencil tests quite extensively to render irregular shapes (a bit like a simple 2-D CSG). If I could find out how many fragments passed the stencil test and were actually rendered, this would be very helpful in simplifying some computations down the line. Specifically, it would allow me to determine the area of the rendered shape for free instead of having to approximate it with a Monte Carlo simulation later on.

I know that there is a similar concept for primitives emitted from the geometry shader, called transform feedback. I'd like to know if a similar concept exists for fragments and the stencil test.
One possible approach could be the use of Hardware Occlusion Query.

You can use the facts that, by specification, the Stencil Test is executed before the depth test, and only the fragments that pass the depth test are counted by the Occlusion Query.

A simple example (not tested) would be like:

    GLuint samples_query = 0;
    GLuint samples_passed = 0;
    glGenQueries(1, &amp;samples_query);
    // Initialize your buffers and textures ...
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_STENCIL_TEST);

    // Set up the values on the stencil buffer ...

    // Now we count the fragments that pass the stencil test
    glDepthFunc(GL_ALWAYS); // Set up the depth test to always pass
    glBeginQuery(GL_SAMPLES_PASSED, samples_query);
    // Render your meshes here
    glEndQuery(GL_SAMPLES_PASSED);
    glGetQueryObjectuiv(samples_query, GL_QUERY_RESULT, &amp;samples_passed);
    // samples_passed holds the number of fragments that passed the stencil test (if any)

    // Release your resources ...
    glDeleteQueries(1, &amp;samples_query);


Note that the call to obtain the number of samples will call forcibly the flush of the pipeline and wait for the query to finish.
If you need a more asynchronous approach you can query wether the occlusion query is done or not by using:

    GLuint query_done = 0;
    glGetQueryObjectuiv(samples_query, GL_QUERY_RESULT_AVAILABLE, &amp;query_done);
    if (query_done != 0)
        // Your query result is ready
    else
        // Maybe check the next frame?