/** * 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; }
/** * Create two textures with different reference values. Draw both of * the textures to the framebuffer and save the reference images with * glReadPixels. * * Loop: * - Create another texture with the same initial values as the first * texture * - replace a random sub-region of the texture image with values from * the 2nd texture * - draw the texture to the framebuffer and read back with glReadPixels * - compare reference images to test image choosing either the first * or second reference image for each pixel depending on whether it * is within the updated region * \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 = DEFAULT_TEX_WIDTH; GLuint h = DEFAULT_TEX_HEIGHT; GLuint d = DEFAULT_TEX_DEPTH; GLuint tex, i, j, k, n, t; GLubyte *original_img, *original_ref; GLubyte *updated_img, *updated_ref; GLubyte *testImg; GLboolean pass = GL_TRUE; GLuint bw, bh, bb, wMask, hMask, dMask; GLuint pbo = 0; piglit_get_compressed_block_size(intFormat, &bw, &bh, &bb); wMask = ~(bw-1); hMask = ~(bh-1); dMask = ~0; if (target == GL_TEXTURE_CUBE_MAP_ARRAY_ARB) { w = h; d *= 6; } else if (target != GL_TEXTURE_3D && target != GL_TEXTURE_2D_ARRAY) { d = 1; } if (target == GL_TEXTURE_1D) h = 1; original_img = (GLubyte *) malloc(w * h * d * 4); original_ref = (GLubyte *) malloc(w * h * d * 4); updated_img = (GLubyte *) malloc(w * h * d * 4); updated_ref = (GLubyte *) malloc(w * h * d * 4); testImg = (GLubyte *) malloc(w * h * d * 4); /* fill source tex images */ n = 0; for (i = 0; i < d; i++) { for (j = 0; j < h; j++) { for (k = 0; k < w; k++) { original_img[n + 0] = j * 4; original_img[n + 1] = k * 2; original_img[n + 2] = i * 128 / d; original_img[n + 3] = 255; /* Swizzle the components in the * updated image */ updated_img[n + 0] = original_img[n + 1]; updated_img[n + 1] = original_img[n + 2]; updated_img[n + 2] = original_img[n + 0]; updated_img[n + 3] = original_img[n + 3]; n += 4; } } } if (use_pbo) { glGenBuffers(1, &pbo); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); glBufferData(GL_PIXEL_UNPACK_BUFFER, w * h * d * 4, updated_img, GL_STATIC_DRAW); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); } glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); /* draw original reference image */ tex = create_texture(target, intFormat, w, h, d, srcFormat, original_img); glClear(GL_COLOR_BUFFER_BIT); draw_and_read_texture(w, h, d, original_ref); glDeleteTextures(1, &tex); /* draw updated reference image */ tex = create_texture(target, intFormat, w, h, d, srcFormat, updated_img); glClear(GL_COLOR_BUFFER_BIT); draw_and_read_texture(w, h, d, updated_ref); glDeleteTextures(1, &tex); 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; /* Recreate the original texture */ tex = create_texture(target, intFormat, w, h, d, srcFormat, original_img); assert(tx + tw <= w); assert(ty + th <= h); assert(tz + td <= d); if (use_pbo) glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); /* replace texture region with data from updated image */ glPixelStorei(GL_UNPACK_SKIP_PIXELS, tx); glPixelStorei(GL_UNPACK_SKIP_ROWS, ty); glPixelStorei(GL_UNPACK_SKIP_IMAGES, tz); if (d > 1) { glTexSubImage3D(target, 0, tx, ty, tz, tw, th, td, srcFormat, GL_UNSIGNED_BYTE, use_pbo ? NULL : updated_img); } else if (h > 1) { glTexSubImage2D(target, 0, tx, ty, tw, th, srcFormat, GL_UNSIGNED_BYTE, use_pbo ? NULL : updated_img); } else if (w > 1) { glTexSubImage1D(target, 0, tx, tw, srcFormat, GL_UNSIGNED_BYTE, use_pbo ? NULL : updated_img); } else { assert(!"Unknown image dimensions"); } if (use_pbo) glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); /* draw test image */ glClear(GL_COLOR_BUFFER_BIT); draw_and_read_texture(w, h, d, testImg); glDeleteTextures(1, &tex); piglit_present_results(); if (!equal_images(target, original_ref, updated_ref, testImg, w, h, d, tx, ty, tz, tw, th, td)) { printf("texsubimage failed\n"); printf(" target: %s\n", piglit_get_gl_enum_name(target)); printf(" internal format: %s\n", piglit_get_gl_enum_name(intFormat)); printf(" region: %d, %d %d x %d\n", tx, ty, tw, th); pass = GL_FALSE; break; } } free(original_img); free(original_ref); free(updated_img); free(updated_ref); free(testImg); if (use_pbo) glDeleteBuffers(1, &pbo); return pass; }