/* * Copyright © 2013 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 blit.c * * Section 4.3.2(Reading and Copying Pixels) From GL spec 3.2 core: * If the read framebuffer is layered (see section 4.4.7), pixel values are * read from layer zero. If the draw framebuffer is layered, pixel values are * written to layer zero. If both read and draw framebuffers are layered, the * blit operation is still performed only on layer zero. * * Test Layout * *-------*-------* test1: * | | | Source tex is layered, destination tex is layered * | test3 | test4 | test2: * | | | Source tex is layered, destination tex is not layered * *-------*-------* test3: * | | | Source tex is not layered, destination tex is layered * | test1 | test2 | test4: * | | | Source tex is not layered, destination tex is not layered * *-------*-------* * * src dst Each Test * *---*---* Display source tex layers on left * | | | layer 1 Blit source tex to destination tex * *---*---* Display resulting layers * | | | layer 2 * *---*---* */ #include "piglit-util-gl.h" PIGLIT_GL_TEST_CONFIG_BEGIN config.supports_gl_compat_version = 32; config.supports_gl_core_version = 32; config.window_visual = PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_DOUBLE; config.khr_no_error_support = PIGLIT_NO_ERRORS; PIGLIT_GL_TEST_CONFIG_END /* Values Set in piglit init */ static const int texWidth = 32; static const int texHeight = 32; static const int texDepth = 2; static const float srcColors[2][3] = { {0.5, 0.4, 0.3}, {0, 1, 0} }; static const float dstColors[2][3] = { {0, 0, 1}, {0, 1, 1} }; /* * Blit the passed texture to the screen. If texture is layered, * loops through each layer and blit it to the screen. Otherwise scales * the layer zero vertically with a factor of texDepth. */ bool display_texture(int x, int y, GLuint tex, int layers) { GLuint tempFBO; GLenum fbStatus; /* Gen temp fbo to work with */ glGenFramebuffers(1, &tempFBO); if (layers == 1) { glBindFramebuffer(GL_FRAMEBUFFER, tempFBO); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); /* Blit layer to screen */ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, piglit_winsys_fbo); glBindFramebuffer(GL_READ_FRAMEBUFFER, tempFBO); glBlitFramebuffer(0, 0, texWidth, texHeight, x, y, x + texWidth, y + texDepth * texHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); } else { int i; /* loop through each layer */ for (i = 0; i < layers; i++) { /* Bind new layer to display */ glBindFramebuffer(GL_FRAMEBUFFER, tempFBO); glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, i); fbStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (fbStatus != GL_FRAMEBUFFER_COMPLETE) { printf("Framebuffer Status: %s\n", piglit_get_gl_enum_name(fbStatus)); return false; } /* Blit layer to screen */ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, piglit_winsys_fbo); glBindFramebuffer(GL_READ_FRAMEBUFFER, tempFBO); glBlitFramebuffer(0, 0, texWidth, texHeight, x, y + i * texHeight, x + texWidth, y + (i + 1) * texHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); } } /* Cleanup temp fbo */ glBindFramebuffer(GL_FRAMEBUFFER, piglit_winsys_fbo); glDeleteFramebuffers(1, &tempFBO); return piglit_check_gl_error(GL_NO_ERROR); } float * gen_color_data(int layers, bool useSrcTex) { int i, j; float *colorData = malloc(layers * texWidth * texHeight * 3 * sizeof(float)); for (j = 0; j < layers; j++) { for (i = 0; i < texWidth * texHeight; i++) { int offset = j * texWidth * texHeight * 3 + i * 3; if (useSrcTex) { colorData[offset + 0] = srcColors[j][0]; colorData[offset + 1] = srcColors[j][1]; colorData[offset + 2] = srcColors[j][2]; } else { colorData[offset + 0] = dstColors[j][0]; colorData[offset + 1] = dstColors[j][1]; colorData[offset + 2] = dstColors[j][2]; } } } return colorData; } GLuint create_bind_texture(GLenum textureType, bool useSrcTex) { GLuint texture = 0; float *colorData = NULL; piglit_check_gl_error(GL_NO_ERROR); glGenTextures(1, &texture); glBindTexture(textureType, texture); glTexParameteri(textureType, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(textureType, GL_TEXTURE_MAG_FILTER, GL_LINEAR); switch (textureType) { case GL_TEXTURE_2D: colorData = gen_color_data(1, useSrcTex); glTexImage2D(textureType, 0, GL_RGB, texWidth, texHeight, 0, GL_RGB, GL_FLOAT, colorData); break; case GL_TEXTURE_3D: colorData = gen_color_data(texDepth, useSrcTex); glTexImage3D(textureType, 0, GL_RGB, texWidth, texHeight, texDepth, 0, GL_RGB, GL_FLOAT, colorData); break; } if (!piglit_check_gl_error(GL_NO_ERROR)) { glDeleteTextures(1, &texture); texture = 0; } if (colorData != NULL) free(colorData); return texture; } bool testFramebufferBlitLayered(int x, int y, bool srcLayered, bool dstLayered) { bool pass = true; GLuint srcFBO, dstFBO; GLuint srcTex, dstTex; GLenum fbStatus; /* Set up source fbo */ glGenFramebuffers(1, &srcFBO); glBindFramebuffer(GL_FRAMEBUFFER, srcFBO); piglit_check_gl_error(GL_NO_ERROR); if (srcLayered) { srcTex = create_bind_texture(GL_TEXTURE_3D, true); glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, srcTex, 0); } else { srcTex = create_bind_texture(GL_TEXTURE_2D, true); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, srcTex, 0); } /* Check source framebuffer status */ fbStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (fbStatus != GL_FRAMEBUFFER_COMPLETE) { printf("testFramebufferBlitLayered srcFBO Status: %s\n", piglit_get_gl_enum_name(fbStatus)); return false; } /* Set up dstt fbo */ glGenFramebuffers(1, &dstFBO); glBindFramebuffer(GL_FRAMEBUFFER, dstFBO); if (dstLayered) { dstTex = create_bind_texture(GL_TEXTURE_3D, false); glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dstTex, 0); } else { dstTex = create_bind_texture(GL_TEXTURE_2D, false); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dstTex, 0); } /* Check destination framebuffer status */ fbStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (fbStatus != GL_FRAMEBUFFER_COMPLETE) { printf("testFramebufferBlitLayered dstFBO Status: %s\n", piglit_get_gl_enum_name(fbStatus)); return false; } /* Check for if any errors have occured */ if (!piglit_check_gl_error(GL_NO_ERROR)) { printf("Error setting up framebuffers for test.\n"); return false; } /* Blit from source to destination framebuffers */ glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFBO); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFBO); glBlitFramebuffer(0, 0, texWidth, texHeight, 0, 0, texWidth, texHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); /* Display the results */ display_texture(x, y, srcTex, srcLayered ? texDepth : 1); display_texture(x + texWidth, y, dstTex, dstLayered ? texDepth : 1); /* Check for pass condition */ if (dstLayered) { pass = piglit_probe_rect_rgb(x + texWidth, y, texWidth, texHeight, srcColors[0]) && pass; pass = piglit_probe_rect_rgb(x + texWidth, y + texHeight, texWidth, texHeight, dstColors[1]) && pass; } else { pass = piglit_probe_rect_rgb(x + texWidth, y, texWidth, texDepth * texHeight, srcColors[0]) && pass; } /* Clean up */ glBindFramebuffer(GL_FRAMEBUFFER, piglit_winsys_fbo); glDeleteFramebuffers(1, &srcFBO); glDeleteFramebuffers(1, &dstFBO); glDeleteTextures(1, &srcTex); glDeleteTextures(1, &dstTex); /* Check for if any errors have occured */ if (!piglit_check_gl_error(GL_NO_ERROR)) { printf("Error setting up framebuffers for test.\n"); return false; } return pass; } void piglit_init(int argc, char **argv) { } enum piglit_result piglit_display(void) { bool pass = true; glBindFramebuffer(GL_FRAMEBUFFER, piglit_winsys_fbo); glClearColor(1,1,1,1); glClear(GL_COLOR_BUFFER_BIT); /* Source is layered, destination is layered */ pass = testFramebufferBlitLayered(0, 0, true, true) && pass; /* Source is layered, destination is not layered */ pass = testFramebufferBlitLayered(2 * texWidth, 0, true, false) && pass; /* Source not is layered, destination is layered */ pass = testFramebufferBlitLayered(0, texDepth * texHeight, false, true) && pass; /* Source not is layered, destination is not layered */ pass = testFramebufferBlitLayered(2 * texWidth, texDepth * texHeight, false, false) && pass; /* Check for if any errors have occured */ pass = piglit_check_gl_error(GL_NO_ERROR) && pass; piglit_present_results(); return pass ? PIGLIT_PASS : PIGLIT_FAIL; }