c++ - how to correctly use libpng -
edit: i'm using libpng 1.6 on windows 7
i'm convinced usage of libpng causing memory leak (edit: confirmed) loading images using function causes spike in memory when unload images , reload them memory usage sky rockets. instead of being few meg in memory app using hundreds. i'm unable see problem code, i've done best free resources. i'd second opinion memory leak didn't exist when using different method load textures.
here function:
#define png_sig_bytes (8) /* bytes in png file signature. */ gluint loadpngtexturergba(const string filename, int &width, int &height) { file* fp = null; #ifdef __linux__ fp = fopen(filename.c_str(), "rb"); #elif defined(_win32) fopen_s(&fp, filename.c_str(), "rb"); #endif if (fp == null) { #ifdef __linux std::cout << "unable load png texture file" << std::endl; #else messagebox(0, l"unable load texture", l"error", mb_ok); exit(0); #endif } png_byte magic[png_sig_bytes]; /* (signature byte buffer) */ png_structp png_ctx; png_infop info_ctx; png_uint_32 img_width, img_height, row; png_byte img_depth, img_color_type; /* 'volatile' qualifier forces reload in setjmp cleanup: */ png_byte *volatile img_data = null; png_bytep *volatile row_data = null; ;//*buf = null; /* assumed 'longjmp' can invoked within * code efficiently unwind resources *all* errors. */ /* png structures , resource unwinding: */ if ((png_ctx = png_create_read_struct( png_libpng_ver_string, null, null, null)) == null) return (1); /* enomem (?) */ if ((info_ctx = png_create_info_struct(png_ctx)) == null) { png_destroy_read_struct(&png_ctx, null, null); return (1); /* enomem (?) */ } if (setjmp(png_jmpbuf(png_ctx)) != 0) { png_destroy_read_struct(&png_ctx, &info_ctx, null); free(img_data); free(row_data); return (1); /* libpng feedback (?) */ } /* check png file signature: */ if (fread(magic, (1), png_sig_bytes, fp) != png_sig_bytes) png_error(png_ctx, "invalid png file"); if (png_sig_cmp(magic, 0, png_sig_bytes)) png_error(png_ctx, "invalid png file"); /* set input file stream , png image info: */ png_init_io(png_ctx, fp); png_set_sig_bytes(png_ctx, png_sig_bytes); png_read_info(png_ctx, info_ctx); img_width = png_get_image_width(png_ctx, info_ctx); img_height = png_get_image_height(png_ctx, info_ctx); #if (1) /* png doesn't support 0 area image? */ if (img_width == 0 || img_height == 0) png_error(png_ctx, "zero area png image"); #endif if (png_rgba_pixel_limit2(img_width, img_height)) png_error(png_ctx, "png image exceeds pixel limits"); img_depth = png_get_bit_depth(png_ctx, info_ctx); img_color_type = png_get_color_type(png_ctx, info_ctx); /* ignored image interlacing, compression , filtering. */ /* force 8-bit color channels: */ if (img_depth == 16) png_set_strip_16(png_ctx); else if (img_depth < 8) png_set_packing(png_ctx); /* force formats rgb: */ if (img_color_type != png_color_type_rgba) png_set_expand(png_ctx); if (img_color_type == png_color_type_palette) png_set_palette_to_rgb(png_ctx); if (img_color_type == png_color_type_gray) png_set_gray_to_rgb(png_ctx); if (img_color_type == png_color_type_gray_alpha) png_set_gray_to_rgb(png_ctx); /* add full opacity alpha channel if required: */ if (img_color_type != png_color_type_rgba) png_set_filler(png_ctx, 0xff, png_filler_after); /* apply output transforms before reading image data: */ png_read_update_info(png_ctx, info_ctx); /* allocate rgba image data: */ img_data = (png_byte *) malloc((size_t)(img_width * img_height * (4))); if (img_data == null) png_error(png_ctx, "error allocating image buffer"); /* allocate row pointers: */ row_data = (png_bytep *) malloc((size_t)(img_height * sizeof(png_bytep))); if (row_data == null) png_error(png_ctx, "error allocating row pointers"); /* set row pointers , read rgba image data: */ (row = 0; row < img_height; row++) row_data[row] = img_data + (img_height - (row + 1)) * (img_width * (4)); png_read_image(png_ctx, row_data); /* libpng , dynamic resource unwinding: */ png_read_end(png_ctx, null); png_destroy_info_struct(png_ctx, (png_infopp)&info_ctx); png_destroy_read_struct(&png_ctx, &info_ctx, (png_infopp)null); free(row_data); //*w = (unsigned) img_width, *h = (unsigned) img_height; width = img_width; height = img_height; //*buf = img_data; /* (asserts png_byte unsigned char) */ //now generate opengl texture object gluint texture; glgentextures(1, &texture); glbindtexture(gl_texture_2d, texture); glpixelstorei(gl_unpack_alignment, 1); // important! // manual mip map attempt? //gltexparameteri(gl_texture_2d, gl_texture_base_level, 0); //gltexparameteri(gl_texture_2d, gl_texture_max_level, 0); glteximage2d(gl_texture_2d, 0, gl_rgba, width, height, 0, gl_rgba, gl_unsigned_byte, (glvoid*)img_data); bool auto_mipmap = true; if (dqoi_mipmaps_disabled) auto_mipmap = false; if (auto_mipmap) { glgeneratemipmap(gl_texture_2d); //generate num_mipmaps number of mipmaps here. gltexparameteri(gl_texture_2d, gl_texture_wrap_s, gl_repeat); gltexparameteri(gl_texture_2d, gl_texture_wrap_t, gl_repeat); gltexparameteri(gl_texture_2d, gl_texture_mag_filter, gl_linear); gltexparameteri(gl_texture_2d, gl_texture_min_filter, gl_linear_mipmap_linear); } else { gltexparameteri(gl_texture_2d, gl_texture_wrap_s, gl_repeat); gltexparameteri(gl_texture_2d, gl_texture_wrap_t, gl_repeat); gltexparameteri(gl_texture_2d, gl_texture_min_filter, gl_nearest); gltexparameterf(gl_texture_2d, gl_texture_mag_filter, gl_linear); } fclose(fp); free(img_data); return texture; }
edit: second revision, still have same problem
gluint loadpngtexturergba(const string filename, int &width, int &height) { png_byte header[png_sig_bytes]; file *fp = null; #ifdef __linux__ fp = fopen(filename.c_str(), "rb"); #elif defined(_win32) fopen_s(&fp, filename.c_str(), "rb"); #endif if (!fp) { #ifdef __linux std::cout << "unable load png texture file" << std::endl; #else messagebox(0, l"unable load texture", l"error", mb_ok); #endif return texture_load_error; } if (fread(header, 1, png_sig_bytes, fp) != png_sig_bytes) { fclose(fp); //png_error(header, "invalid png file"); return texture_load_error; } //test if png int is_png = !png_sig_cmp(header, 0, 8); if (!is_png) { fclose(fp); return texture_load_error; } /* png structures , resource unwinding: */ png_structp png_ptr; if ((png_ptr = png_create_read_struct(png_libpng_ver_string, null, null, null)) == null) { fclose(fp); return texture_load_error; /* enomem (?) */ } png_infop info_ptr; if (!(info_ptr = png_create_info_struct(png_ptr))) { png_destroy_read_struct(&png_ptr, (png_infopp)null, (png_infopp)null); fclose(fp); return texture_load_error; /* enomem (?) */ } //create png info struct png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)null); fclose(fp); return (texture_load_error); } /* assumed 'longjmp' can invoked within * code efficiently unwind resources *all* errors. */ png_byte *image_data = null; png_bytep *row_pointers = null; if (setjmp(png_jmpbuf(png_ptr)) != 0) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); delete[] image_data; delete[] row_pointers; fclose(fp); return (texture_load_error); } //init png reading png_init_io(png_ptr, fp); //let libpng know read first 8 bytes png_set_sig_bytes(png_ptr, 8); // read info image data png_read_info(png_ptr, info_ptr); //variables pass info int bit_depth, color_type; png_uint_32 twidth, theight; // info png png_get_ihdr(png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type, null, null, null); //update width , height based on png info width = twidth; height = theight; if (width == 0 || height == 0) png_error(png_ptr, "zero area png image"); if (png_rgba_pixel_limit2(width, height)) png_error(png_ptr, "png image exceeds pixel limits"); /* force 8-bit color channels: */ if (bit_depth == 16) png_set_strip_16(png_ptr); else if (bit_depth < 8) png_set_packing(png_ptr); /* force formats rgb: */ if (color_type != png_color_type_rgba) png_set_expand(png_ptr); if (color_type == png_color_type_palette) png_set_palette_to_rgb(png_ptr); if (color_type == png_color_type_gray) png_set_gray_to_rgb(png_ptr); if (color_type == png_color_type_gray_alpha) png_set_gray_to_rgb(png_ptr); /* add full opacity alpha channel if required: */ if (color_type != png_color_type_rgba) png_set_filler(png_ptr, 0xff, png_filler_after); // update png info struct. png_read_update_info(png_ptr, info_ptr); // row size in bytes. int rowbytes = png_get_rowbytes(png_ptr, info_ptr); // allocate image_data big block, given opengl image_data = new png_byte[rowbytes * height]; if (!image_data) { //clean memory , close stuff png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); return texture_load_error; } //row_pointers pointing image_data reading png libpng row_pointers = new png_bytep[height]; if (!row_pointers) { //clean memory , close stuff png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); delete[] image_data; fclose(fp); return texture_load_error; } // set individual row_pointers point @ correct offsets of image_data (int = 0; < height; ++i) row_pointers[height - 1 - i] = image_data + * rowbytes; //read png image_data through row_pointers png_read_image(png_ptr, row_pointers); //now generate opengl texture object gluint texture; glgentextures(1, &texture); glbindtexture(gl_texture_2d, texture); glpixelstorei(gl_unpack_alignment, 1); // important! bool auto_mipmap = true; if (dqoi_mipmaps_disabled) auto_mipmap = false; if (auto_mipmap) { glgeneratemipmap(gl_texture_2d); //generate num_mipmaps number of mipmaps here. gltexparameteri(gl_texture_2d, gl_texture_wrap_s, gl_repeat); gltexparameteri(gl_texture_2d, gl_texture_wrap_t, gl_repeat); gltexparameteri(gl_texture_2d, gl_texture_mag_filter, gl_linear); gltexparameteri(gl_texture_2d, gl_texture_min_filter, gl_linear_mipmap_linear); } else { gltexparameteri(gl_texture_2d, gl_texture_wrap_s, gl_repeat); gltexparameteri(gl_texture_2d, gl_texture_wrap_t, gl_repeat); // default // gltexparameteri(gl_texture_2d, gl_texture_min_filter, gl_nearest); gltexparameterf(gl_texture_2d, gl_texture_mag_filter, gl_linear); // default // // gltexparameteri(gl_texture_2d, gl_texture_mag_filter, gl_nearest); //gltexparameteri(gl_texture_2d, gl_texture_min_filter, gl_nearest); } glteximage2d(gl_texture_2d, 0, gl_rgba, width, height, 0, gl_rgba, gl_unsigned_byte, (glvoid*)image_data); //clean memory , close stuff png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); delete[] image_data; delete[] row_pointers; fclose(fp); return texture; }
Comments
Post a Comment