[Piglit] [PATCH 20/20] msaa: Test that MSAA works properly for all core FBO color formats.
Anuj Phogat
anuj.phogat at gmail.com
Wed Jun 6 17:52:16 PDT 2012
On Tue, Jun 5, 2012 at 5:03 PM, Paul Berry <stereotype441 at gmail.com> wrote:
> This test builds on the existing FBO and MSAA testing infrastructure
> to verify proper functioning of MSAA for various formats.
>
> All core formats which are framebufferbuffer complete are tested. All
> formats which are not framebuffer complete are skipped.
>
> Tests for non-core and depth/stencil formats will be added in later
> patches.
>
> Verified using the proprietary nVidia driver for Linux--all formats
> pass except the LUMINANCE_ALPHA formats, which fail due to a driver
> bug (when rendering to these formats, the nVidia driver maps the red
> channel to both luminance and alpha, instead of mapping red to
> luminance and alpha to alpha).
Paul, On AMD's catalyst driver test fails for formats other than
LUMINANCE_ALPHA.
Here is the test out put: http://pastebin.com/YxJGBKGh
Most of these failures are due to mismatch in luminance and intensity
values. I'm not sure what's the cause.
Just loosen up the tolerance to fix failures in GL_RGBA2 and GL_RGBA4.
> ---
> tests/all.tests | 6 +
> .../ext_framebuffer_multisample/CMakeLists.gl.txt | 1 +
> tests/spec/ext_framebuffer_multisample/formats.cpp | 441 ++++++++++++++++++++
> 3 files changed, 448 insertions(+), 0 deletions(-)
>
> diff --git a/tests/all.tests b/tests/all.tests
> index 93716a8..129a923 100644
> --- a/tests/all.tests
> +++ b/tests/all.tests
> @@ -1373,6 +1373,12 @@ for num_samples in (2, 4, 8, 16, 32):
> test_name)
> ext_framebuffer_multisample[test_name] = PlainExecTest(executable)
>
> +for num_samples in (2, 4, 8, 16, 32):
> + test_name = ' '.join(['formats', str(num_samples)])
> + executable = 'ext_framebuffer_multisample-{0} -auto'.format(
> + test_name)
> + ext_framebuffer_multisample[test_name] = PlainExecTest(executable)
> +
> ext_framebuffer_object = Group()
> spec['EXT_framebuffer_object'] = ext_framebuffer_object
> add_fbo_stencil_tests(ext_framebuffer_object, 'GL_STENCIL_INDEX1')
> diff --git a/tests/spec/ext_framebuffer_multisample/CMakeLists.gl.txt b/tests/spec/ext_framebuffer_multisample/CMakeLists.gl.txt
> index 155190f..1660067 100644
> --- a/tests/spec/ext_framebuffer_multisample/CMakeLists.gl.txt
> +++ b/tests/spec/ext_framebuffer_multisample/CMakeLists.gl.txt
> @@ -11,6 +11,7 @@ link_libraries (
>
> piglit_add_executable (ext_framebuffer_multisample-accuracy common.cpp accuracy.cpp)
> piglit_add_executable (ext_framebuffer_multisample-dlist dlist.c)
> +piglit_add_executable (ext_framebuffer_multisample-formats common.cpp formats.cpp)
> piglit_add_executable (ext_framebuffer_multisample-line-smooth common.cpp line-smooth.cpp)
> piglit_add_executable (ext_framebuffer_multisample-minmax minmax.c)
> piglit_add_executable (ext_framebuffer_multisample-multisample-blit common.cpp multisample-blit.cpp)
> diff --git a/tests/spec/ext_framebuffer_multisample/formats.cpp b/tests/spec/ext_framebuffer_multisample/formats.cpp
> new file mode 100644
> index 0000000..18f1e21
> --- /dev/null
> +++ b/tests/spec/ext_framebuffer_multisample/formats.cpp
> @@ -0,0 +1,441 @@
> +/*
> + * Copyright © 2012 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + */
> +
> +/**
> + * \file formats.cpp
> + *
> + * Verify the proper functioning of multisample antialiasing for all
> + * possible buffer formats.
> + *
> + * This test operates by rendering an MSAA image twice: once in a
> + * standard RGBA buffer (the behaviour of which is well tested by the
> + * other MSAA tests), and once in a buffer with some other format.
> + * Then it blits both images to corresponding single-sample buffers
> + * and uses glReadPixels to make sure the same image was drawn in both
> + * cases (to within the expected tolerance considering the bit depth
> + * of the two images).
> + *
> + * Finally, the images that were compared are drawn on screen to make
> + * it easier to diagnose failures.
> + */
> +
> +#include "common.h"
> +#include "../../fbo/fbo-formats.h"
> +
> +int piglit_width = 512, piglit_height = 256;
> +int piglit_window_mode = GLUT_DOUBLE | GLUT_RGBA | GLUT_ALPHA;
> +
> +namespace {
> +
> +const int pattern_width = 256; const int pattern_height = 256;
> +
> +int num_samples;
> +
> +TestPattern *test_pattern;
> +
> +
> +/**
> + * This class encapsulates the code necessary to draw the test pattern
> + * in either the reference GL_RGBA format or the format under test,
> + * downsample it, read the rendered pixels into memory, and draw a
> + * visualization of the result.
> + */
> +class PatternRenderer
> +{
> +public:
> + bool try_setup(GLenum internalformat);
> + void set_piglit_tolerance();
> + void draw();
> + float *read_image(GLenum base_format);
> +
> + /**
> + * Number of bits in each color channel. E.g. color_bits[2]
> + * == number of bits in blue color channel.
> + */
> + GLint color_bits[4];
> +
> + Fbo fbo_msaa;
> + Fbo fbo_downsampled;
> +};
> +
> +
> +/**
> + * Try to set up the necessary framebuffers to render to the given
> + * MSAA format. Return false if one or more of the framebuffers is
> + * incomplete.
> + */
> +bool
> +PatternRenderer::try_setup(GLenum internalformat)
> +{
> + FboConfig config_downsampled(0, pattern_width, pattern_height);
> + config_downsampled.color_internalformat = internalformat;
> +
> + FboConfig config_msaa = config_downsampled;
> + config_msaa.num_samples = num_samples;
> +
> + if (!(fbo_downsampled.try_setup(config_downsampled) &&
> + fbo_msaa.try_setup(config_msaa)))
> + return false;
> +
> + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_downsampled.handle);
> + glGetFramebufferAttachmentParameteriv(
> + GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
> + GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, &color_bits[0]);
> + glGetFramebufferAttachmentParameteriv(
> + GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
> + GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE, &color_bits[1]);
> + glGetFramebufferAttachmentParameteriv(
> + GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
> + GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE, &color_bits[2]);
> + glGetFramebufferAttachmentParameteriv(
> + GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
> + GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE, &color_bits[3]);
> +
> + return true;
> +}
> +
> +
> +/**
> + * Set the piglit tolerance appropriately based on the number of bits
> + * in each channel.
> + */
> +void PatternRenderer::set_piglit_tolerance()
> +{
> + int tolerance_bits[4];
> +
> + for (int i = 0; i < 4; ++i) {
> + if (color_bits[i] == 0) {
> + /* For channels that have 0 bits, test to 8
> + * bits precision so we can verify that the
> + * blit puts in the appropriate value.
> + */
> + tolerance_bits[i] = 8;
> + } else if (color_bits[i] > 8) {
> + /* For channels that have >8 bits, test to 8
> + * bits precision because we only use an 8-bit
> + * reference image.
> + */
> + tolerance_bits[i] = 8;
> + } else {
> + tolerance_bits[i] = color_bits[i];
> + }
> + }
> +
> + piglit_set_tolerance_for_bits(tolerance_bits[0], tolerance_bits[1],
> + tolerance_bits[2], tolerance_bits[3]);
> +}
> +
> +
> +/**
> + * Draw the test pattern into the MSAA framebuffer, and then blit it
> + * to the downsampled FBO to force an MSAA resolve.
> + */
> +void
> +PatternRenderer::draw()
> +{
> + /* Draw into the MSAA fbo */
> + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_msaa.handle);
> + fbo_msaa.set_viewport();
> + test_pattern->draw(TestPattern::no_projection);
> +
> + /* Blit to the downsampled fbo, forcing the image to be downsampled */
> + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_msaa.handle);
> + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_downsampled.handle);
> + glBlitFramebuffer(0, 0, pattern_width, pattern_height,
> + 0, 0, pattern_width, pattern_height,
> + GL_COLOR_BUFFER_BIT, GL_NEAREST);
> +}
> +
> +
> +/**
> + * Read the image from the downsampled FBO into a newly allocated
> + * array of floats and return it.
> + */
> +float *
> +PatternRenderer::read_image(GLenum base_format)
> +{
> + unsigned components = piglit_num_components(base_format);
> + unsigned size = sizeof(float)*components*pattern_width*pattern_height;
> + float *image = (float *) malloc(size);
> + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_downsampled.handle);
> + if (base_format == GL_INTENSITY) {
> + /* GL_INTENSITY is not allowed for ReadPixels so
> + * substitute GL_LUMINANCE.
> + */
> + base_format = GL_LUMINANCE;
> + }
> + glReadPixels(0, 0, pattern_width, pattern_height, base_format, GL_FLOAT,
> + image);
> + return image;
> +}
> +
> +
> +/**
> + * PatternRenderer used to render the image under test.
> + */
> +PatternRenderer test_renderer;
> +
> +
> +/**
> + * PatternRenderer used to render the reference image (in GL_RGBA
> + * format).
> + */
> +PatternRenderer ref_renderer;
> +
> +
> +/**
> + * Convert the image into a format that can be easily understood by
> + * visual inspection, and display it on the screen.
> + *
> + * Luminance and intensity values are converted to a grayscale value.
> + * Alpha values are visualized by blending the image with a grayscale
> + * checkerboard.
> + */
> +void
> +visualize_image(float *img, GLenum base_internal_format, bool rhs)
> +{
> + unsigned components = piglit_num_components(base_internal_format);
> + float *visualization =
> + (float *) malloc(sizeof(float)*3*pattern_width*pattern_height);
> + for (int y = 0; y < pattern_height; ++y) {
> + for (int x = 0; x < pattern_width; ++x) {
> + float r = 0, g = 0, b = 0, a = 1;
> + float *pixel =
> + &img[(y * pattern_width + x) * components];
> + switch (base_internal_format) {
> + case GL_ALPHA:
> + a = pixel[0];
> + break;
> + case GL_RGBA:
> + a = pixel[3];
> + /* Fall through */
> + case GL_RGB:
> + r = pixel[0];
> + g = pixel[1];
> + b = pixel[2];
> + break;
> + case GL_LUMINANCE_ALPHA:
> + a = pixel[1];
> + /* Fall through */
> + case GL_INTENSITY:
> + case GL_LUMINANCE:
> + r = pixel[0];
> + g = pixel[0];
> + b = pixel[0];
> + break;
> + }
> + float checker = ((x ^ y) & 0x10) ? 0.75 : 0.25;
> + r = r * a + checker * (1 - a);
> + g = g * a + checker * (1 - a);
> + b = b * a + checker * (1 - a);
> + visualization[(y * pattern_width + x) * 3] = r;
> + visualization[(y * pattern_width + x) * 3 + 1] = g;
> + visualization[(y * pattern_width + x) * 3 + 2] = b;
> + }
> + }
> + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
> + glViewport(0, 0, piglit_width, piglit_height);
> + glUseProgram(0);
> + glRasterPos2f(rhs ? 0 : -1, -1);
> + glDrawPixels(pattern_width, pattern_height, GL_RGB, GL_FLOAT,
> + visualization);
> + free(visualization);
> +}
> +
> +
> +/**
> + * Transform the reference image (which is in GL_RGBA format) to an
> + * expected image for a given base internal format, using the the
> + * transformation described in the GL 3.0 spec, table 3.15 (Conversion
> + * from RGBA, depth, and stencil pixel components to internal texture,
> + * table, or filter components). In short, the mapping is as follows:
> + *
> + * base_internal_format mapping
> + * GL_ALPHA A -> A
> + * GL_LUMINANCE R -> L
> + * GL_LUMINANCE_ALPHA R,A -> L,A
> + * GL_INTENSITY R -> I
> + * GL_RED R -> R
> + * GL_RG R,G -> R,G
> + * GL_RGB R,G,B -> R,G,B
> + * GL_RGBA R,G,B,A -> R,G,B,A
> + */
> +float *
> +compute_expected_image(const float *ref_image, GLenum base_internal_format)
> +{
> + unsigned components = piglit_num_components(base_internal_format);
> + unsigned num_pixels = pattern_width*pattern_height;
> + unsigned size = sizeof(float)*components*num_pixels;
> + float *expected_image = (float *) malloc(size);
> + for (unsigned i = 0; i < num_pixels; ++i) {
> + float *expected = &expected_image[components*i];
> + const float *ref = &ref_image[4*i];
> + for (unsigned j = 0; j < components; ++j) {
> + switch (base_internal_format) {
> + case GL_ALPHA:
> + expected[j] = ref[3];
> + break;
> + case GL_LUMINANCE_ALPHA:
> + expected[j] = ref[j ? 3 : 0];
> + break;
> + default:
> + expected[j] = ref[j];
> + break;
> + }
> + }
> + }
> + return expected_image;
> +}
> +
> +
> +/**
> + * Test a given internal format.
> + */
> +enum piglit_result
> +test_format(const struct format_desc *format)
> +{
> + bool pass = true;
> +
> + /* Caller messes with the clear color. Reset it to the
> + * default.
> + */
> + glClearColor(0, 0, 0, 0);
> +
> + printf("Testing %s\n", format->name);
> +
> + /* Set up the framebuffers for rendering the reference image.
> + * This shouldn't fail.
> + */
> + bool setup_success = ref_renderer.try_setup(GL_RGBA);
> + if (!piglit_check_gl_error(GL_NO_ERROR)) {
> + printf("Error setting up reference renderbuffers\n");
> + return PIGLIT_FAIL;
> + }
> + if (!setup_success) {
> + printf("Reference framebuffer combination is unsupported\n");
> + return PIGLIT_FAIL;
> + }
> +
> + /* Set up the framebuffers for rendering the test image. This
> + * might fail if the format we're testing isn't supported as a
> + * render target, and that's ok.
> + *
> + * Note: in order to be sure we test all formats which the
> + * implementations supports as render targets, we try all of
> + * them, even formats that the spec doesn't define as
> + * color-renderable (e.g. GL_LUMINANCE8, which is supported as
> + * a render target format by some drivers even though it's not
> + * officially color-renderable). If we tried to request a
> + * color-renderable format and it wasn't supported, we would
> + * expect the framebuffer to be incomplete. If we tried to
> + * request a non-color-renderable format and it wasn't
> + * supported, we might have received a GL error. In either
> + * case just skip to the next format.
> + */
> + setup_success = test_renderer.try_setup(format->internalformat);
> + if (glGetError() != GL_NO_ERROR) {
> + printf("Error setting up test renderbuffers\n");
> + return PIGLIT_SKIP;
> + }
> + if (!setup_success) {
> + printf("Unsupported framebuffer combination\n");
> + return PIGLIT_SKIP;
> + }
> +
> + /* Draw test and reference images, and read them into memory */
> + test_renderer.set_piglit_tolerance();
> + test_renderer.draw();
> + float *test_image =
> + test_renderer.read_image(format->base_internal_format);
> + ref_renderer.draw();
> + float *ref_image = ref_renderer.read_image(GL_RGBA);
> +
> + /* Compute the expected image from the reference image */
> + float *expected_image =
> + compute_expected_image(ref_image,
> + format->base_internal_format);
> +
> + /* Check that the test image was correct */
> + glBindFramebuffer(GL_READ_FRAMEBUFFER,
> + test_renderer.fbo_downsampled.handle);
> + pass = piglit_probe_image_color(0, 0, pattern_width, pattern_height,
> + format->base_internal_format,
> + expected_image) && pass;
> +
> + /* Show both the test and expected images on screen so that
> + * the user can diagnose problems.
> + */
> + visualize_image(test_image, format->base_internal_format, false);
> + visualize_image(expected_image, format->base_internal_format, true);
> +
> + /* Finally, if any error occurred, count that as a failure. */
> + pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
> +
> + free(test_image);
> + free(ref_image);
> + free(expected_image);
> +
> + return pass ? PIGLIT_PASS : PIGLIT_FAIL;
> +}
> +
> +
> +void
> +print_usage_and_exit(char *prog_name)
> +{
> + printf("Usage: %s <num_samples>\n", prog_name);
> + piglit_report_result(PIGLIT_FAIL);
> +}
> +
> +
> +extern "C" void
> +piglit_init(int argc, char **argv)
> +{
> + if (argc < 2)
> + print_usage_and_exit(argv[0]);
> + char *endptr = NULL;
> + num_samples = strtol(argv[1], &endptr, 0);
> + if (endptr != argv[1] + strlen(argv[1]))
> + print_usage_and_exit(argv[0]);
> +
> + piglit_require_gl_version(30);
> + piglit_require_GLSL_version(130);
I think this check is redundant. GLSL version is implied by OpenGL 3.0
> +
> + /* Skip the test if num_samples > GL_MAX_SAMPLES */
> + GLint max_samples;
> + glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
> + if (num_samples > max_samples)
> + piglit_report_result(PIGLIT_SKIP);
> +
> + fbo_formats_init_test_set(0 /* core formats */,
> + GL_TRUE /* print_options */);
> + test_pattern = new ColorGradientSunburst();
> + test_pattern->compile();
> +}
> +
> +extern "C" enum piglit_result
> +piglit_display()
> +{
> + return fbo_formats_display(test_format);
> +}
> +
> +};
> --
> 1.7.7.6
>
More information about the Piglit
mailing list