/** * Draw each image of the texture to the framebuffer and then save the * entire thing to a buffer with glReadPixels(). */ static void draw_and_read_texture(GLuint w, GLuint h, GLuint d, GLubyte *ref) { int i; for (i = 0; i < d; i++) { float tz = (i + 0.5f) / d; piglit_draw_rect_tex3d(i / 8 * w, i % 8 * h, /* x/y */ w, h, 0.0, 0.0, /* tx/ty */ 1.0, 1.0, /* tw/th */ tz, tz /* tz0/tz1 */); } for (i = 0; i < d; i += 8) { glReadPixels(i / 8 * w, i % 8 * h, w, h * MIN2(8, d - i), GL_RGBA, GL_UNSIGNED_BYTE, ref); ref += 8 * w * h * 4; } }
/** * Create a texture image with reference values. Draw a textured quad. * Save reference image with glReadPixels(). * Loop: * replace a sub-region of the texture image with same values * draw test textured quad * read test image with glReadPixels * compare reference image to test image * \param target GL_TEXTURE_1D/2D/3D * \param intFormat the internal texture format */ static GLboolean test_format(GLenum target, GLenum intFormat) { const GLenum srcFormat = GL_RGBA; GLuint w = 128, h = 64, d = 8; GLuint tex, i, j, k, n, t; GLubyte *img, *ref, *testImg; GLboolean pass = GL_TRUE; GLuint bw, bh, wMask, hMask, dMask; get_format_block_size(intFormat, &bw, &bh); wMask = ~(bw-1); hMask = ~(bh-1); dMask = ~0; if (target != GL_TEXTURE_3D) d = 1; if (target == GL_TEXTURE_1D) h = 1; img = (GLubyte *) malloc(w * h * d * 4); ref = (GLubyte *) malloc(w * h * d * 4); testImg = (GLubyte *) malloc(w * h * d * 4); /* fill source tex image */ n = 0; for (i = 0; i < d; i++) { for (j = 0; j < h; j++) { for (k = 0; k < w; k++) { img[n++] = j * 4; img[n++] = k * 2; img[n++] = i * 16; img[n++] = 255; } } } glPixelStorei(GL_UNPACK_ROW_LENGTH, w); glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, h); glGenTextures(1, &tex); glBindTexture(target, tex); glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0); if (target == GL_TEXTURE_1D) { glTexImage1D(target, 0, intFormat, w, 0, srcFormat, GL_UNSIGNED_BYTE, img); } else if (target == GL_TEXTURE_2D) { glTexImage2D(target, 0, intFormat, w, h, 0, srcFormat, GL_UNSIGNED_BYTE, img); } else if (target == GL_TEXTURE_3D) { glTexImage3D(target, 0, intFormat, w, h, d, 0, srcFormat, GL_UNSIGNED_BYTE, img); } glEnable(target); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); /* draw reference image */ glClear(GL_COLOR_BUFFER_BIT); piglit_draw_rect_tex3d(0, 0, w, h, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0); glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ref); for (t = 0; t < 10; t++) { /* Choose random region of texture to update. * Use sizes and positions that are multiples of * the compressed block size. */ GLint tw = (rand() % w) & wMask; GLint th = (rand() % h) & hMask; GLint td = (rand() % d) & dMask; GLint tx = (rand() % (w - tw)) & wMask; GLint ty = (rand() % (h - th)) & hMask; GLint tz = (rand() % (d - td)) & dMask; assert(tx + tw <= w); assert(ty + th <= h); assert(tz + td <= d); /* replace texture region (with same data) */ glPixelStorei(GL_UNPACK_SKIP_PIXELS, tx); glPixelStorei(GL_UNPACK_SKIP_ROWS, ty); glPixelStorei(GL_UNPACK_SKIP_IMAGES, tz); if (target == GL_TEXTURE_1D) { glTexSubImage1D(target, 0, tx, tw, srcFormat, GL_UNSIGNED_BYTE, img); } else if (target == GL_TEXTURE_2D) { glTexSubImage2D(target, 0, tx, ty, tw, th, srcFormat, GL_UNSIGNED_BYTE, img); } else if (target == GL_TEXTURE_2D) { glTexSubImage3D(target, 0, tx, ty, tz, tw, th, td, srcFormat, GL_UNSIGNED_BYTE, img); } /* draw test image */ glClear(GL_COLOR_BUFFER_BIT); piglit_draw_rect_tex3d(0, 0, w, h, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0); glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, testImg); glutSwapBuffers(); if (!equal_images(ref, testImg, w, h)) { printf("texsubimage failed\n"); printf(" target: 0x%x\n", target); printf(" internal format: 0x%x\n", intFormat); printf(" region: %d, %d %d x %d\n", tx, ty, tw, th); pass = GL_FALSE; break; } } glDisable(target); free(img); free(ref); free(testImg); glDeleteTextures(1, &tex); return pass; }