On Tue, Jun 5, 2012 at 5:03 PM, Paul Berry <[email protected]> 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 > _______________________________________________ Piglit mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/piglit
