diff options
Diffstat (limited to 'indra/integration_tests')
| -rw-r--r-- | indra/integration_tests/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | indra/integration_tests/llimage_libtest/CMakeLists.txt | 131 | ||||
| -rw-r--r-- | indra/integration_tests/llimage_libtest/llimage_libtest.cpp | 429 | ||||
| -rw-r--r-- | indra/integration_tests/llimage_libtest/llimage_libtest.h | 29 | 
4 files changed, 590 insertions, 0 deletions
| diff --git a/indra/integration_tests/CMakeLists.txt b/indra/integration_tests/CMakeLists.txt index 67e8fbf1f2..5935f23fe9 100644 --- a/indra/integration_tests/CMakeLists.txt +++ b/indra/integration_tests/CMakeLists.txt @@ -1,3 +1,4 @@  # -*- cmake -*-  add_subdirectory(llui_libtest) +add_subdirectory(llimage_libtest) diff --git a/indra/integration_tests/llimage_libtest/CMakeLists.txt b/indra/integration_tests/llimage_libtest/CMakeLists.txt new file mode 100644 index 0000000000..f59440be6b --- /dev/null +++ b/indra/integration_tests/llimage_libtest/CMakeLists.txt @@ -0,0 +1,131 @@ +# -*- cmake -*- + +# Integration tests of the llimage library (JPEG2000, PNG, jpeg, etc... images reading and writing) + +project (llimage_libtest) + +include(00-Common) +include(LLCommon) +include(Linking) +include(LLSharedLibs) +include(LLImage) +include(LLImageJ2COJ)  +include(LLKDU) +include(LLMath) +include(LLVFS) + +include_directories( +    ${LLCOMMON_INCLUDE_DIRS} +    ${LLVFS_INCLUDE_DIRS} +    ${LLIMAGE_INCLUDE_DIRS} +    ${LLMATH_INCLUDE_DIRS} +    ) + +set(llimage_libtest_SOURCE_FILES +    llimage_libtest.cpp +    ) + +set(llimage_libtest_HEADER_FILES +    CMakeLists.txt +    llimage_libtest.h +    ) + +set_source_files_properties(${llimage_libtest_HEADER_FILES} +                            PROPERTIES HEADER_FILE_ONLY TRUE) + +list(APPEND llimage_libtest_SOURCE_FILES ${llimage_libtest_HEADER_FILES}) + +add_executable(llimage_libtest +    WIN32 +    MACOSX_BUNDLE +    ${llimage_libtest_SOURCE_FILES} +) + +set_target_properties(llimage_libtest +    PROPERTIES +    WIN32_EXECUTABLE +    FALSE +) + +# OS-specific libraries +if (DARWIN) +  include(CMakeFindFrameworks) +  find_library(COREFOUNDATION_LIBRARY CoreFoundation) +  set(OS_LIBRARIES ${COREFOUNDATION_LIBRARY}) +elseif (WINDOWS) +#  set(OS_LIBRARIES) +elseif (LINUX) +#  set(OS_LIBRARIES) +else (DARWIN) +  message(FATAL_ERROR "Unknown platform") +endif (DARWIN) + +# Libraries on which this application depends on +# Sort by high-level to low-level +target_link_libraries(llimage_libtest +	${LLCOMMON_LIBRARIES} +	${LLVFS_LIBRARIES} +    ${LLIMAGE_LIBRARIES} +    ${LLKDU_LIBRARIES} +    ${KDU_LIBRARY} +    ${LLIMAGEJ2COJ_LIBRARIES} +    ${OS_LIBRARIES} +    ) +	 +if (DARWIN) +  # Path inside the app bundle where we'll need to copy libraries +  set(LLIMAGE_LIBTEST_DESTINATION_DIR +    ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llimage_libtest.app/Contents/Resources +  ) +  # Create the Contents/Resources directory +  add_custom_command( +    TARGET llimage_libtest POST_BUILD +    COMMAND ${CMAKE_COMMAND} +    ARGS +      -E +      make_directory +      ${LLIMAGE_LIBTEST_DESTINATION_DIR} +    COMMENT "Creating Resources directory in app bundle." +  )  +else (DARWIN) +  set(LLIMAGE_LIBTEST_DESTINATION_DIR +    ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/ +  ) +endif (DARWIN) + +get_target_property(BUILT_LLCOMMON llcommon LOCATION) +add_custom_command(TARGET llimage_libtest POST_BUILD +  COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_LLCOMMON}  ${LLIMAGE_LIBTEST_DESTINATION_DIR} +  DEPENDS ${BUILT_LLCOMMON} +) + +if (DARWIN) +  # Copy the required libraries to the package app +  add_custom_command(TARGET llimage_libtest POST_BUILD +    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libapr-1.0.3.7.dylib ${LLIMAGE_LIBTEST_DESTINATION_DIR} +    DEPENDS ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libapr-1.0.3.7.dylib +  ) + add_custom_command(TARGET llimage_libtest POST_BUILD +    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libaprutil-1.0.3.8.dylib ${LLIMAGE_LIBTEST_DESTINATION_DIR} +    DEPENDS ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libaprutil-1.0.3.8.dylib +  ) +  add_custom_command(TARGET llimage_libtest POST_BUILD +    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libexception_handler.dylib ${LLIMAGE_LIBTEST_DESTINATION_DIR} +    DEPENDS ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libexception_handler.dylib +  ) +  add_custom_command(TARGET llimage_libtest POST_BUILD +    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libexpat.0.5.0.dylib ${LLIMAGE_LIBTEST_DESTINATION_DIR} +    DEPENDS ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libexpat.0.5.0.dylib +  ) +endif (DARWIN) + +if (WINDOWS) +  # Check indra/test_apps/llplugintest/CMakeLists.txt for an example of what to copy over for Windows and how +endif (WINDOWS) + +# Ensure people working on the viewer don't break this library +# *NOTE: This could be removed, or only built by TeamCity, if the build +# and link times become too long. +add_dependencies(viewer llimage_libtest) + +ll_deploy_sharedlibs_command(llimage_libtest)  diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp new file mode 100644 index 0000000000..2a1a2ae843 --- /dev/null +++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp @@ -0,0 +1,429 @@ +/**  + * @file llimage_libtest.cpp + * @author Merov Linden + * @brief Integration test for the llimage library + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ +#include "linden_common.h" +#include "llpointer.h" +#include "lltimer.h" + +#include "llimage_libtest.h" + +// Linden library includes +#include "llimage.h" +#include "llimagejpeg.h" +#include "llimagepng.h" +#include "llimagebmp.h" +#include "llimagetga.h" +#include "llimagej2c.h" +#include "lldir.h" + +// system libraries +#include <iostream> + +// doc string provided when invoking the program with --help  +static const char USAGE[] = "\n" +"usage:\tllimage_libtest [options]\n" +"\n" +" -h, --help\n" +"        Print this help\n" +" -i, --input <file1 .. file2>\n" +"        List of image files to load and convert. Patterns with wild cards can be used.\n" +" -o, --output <file1 .. file2> OR <type>\n" +"        List of image files to create (assumes same order as for input files)\n" +"        OR 3 letters file type extension to convert each input file into.\n" +" -log, --logmetrics <metric>\n" +"        Log performance data for <metric>. Results in <metric>.slp\n" +"        Note: so far, only ImageCompressionTester has been tested.\n" +" -r, --analyzeperformance\n" +"        Create a report comparing <metric>_baseline.slp with current <metric>.slp\n" +"        Results in <metric>_report.csv" +" -s, --image-stats\n" +"        Output stats for each input and output image.\n" +"\n"; + +// true when all image loading is done. Used by metric logging thread to know when to stop the thread. +static bool sAllDone = false; + +// Create an empty formatted image instance of the correct type from the filename +LLPointer<LLImageFormatted> create_image(const std::string &filename) +{ +	std::string exten = gDirUtilp->getExtension(filename); +	U32 codec = LLImageBase::getCodecFromExtension(exten); +	 +	LLPointer<LLImageFormatted> image; +	switch (codec) +	{ +		case IMG_CODEC_BMP: +			image = new LLImageBMP(); +			break; +		case IMG_CODEC_TGA: +			image = new LLImageTGA(); +			break; +		case IMG_CODEC_JPEG: +			image = new LLImageJPEG(); +			break; +		case IMG_CODEC_J2C: +			image = new LLImageJ2C(); +			break; +		case IMG_CODEC_PNG: +			image = new LLImagePNG(); +			break; +		default: +			return NULL; +	} +	 +	return image; +} + +void output_image_stats(LLPointer<LLImageFormatted> image, const std::string &filename) +{ +	// Print out some statistical data on the image +	std::cout << "Image stats for : " << filename << ", extension : " << image->getExtension() << std::endl; + +	std::cout << "    with : " << (int)(image->getWidth())       << ", height : " << (int)(image->getHeight())       << std::endl; +	std::cout << "    comp : " << (int)(image->getComponents())  << ", levels : " << (int)(image->getDiscardLevel()) << std::endl; +	std::cout << "    head : " << (int)(image->calcHeaderSize()) << ",   data : " << (int)(image->getDataSize())     << std::endl; + +	return; +} + +// Load an image from file and return a raw (decompressed) instance of its data +LLPointer<LLImageRaw> load_image(const std::string &src_filename, bool output_stats) +{ +	LLPointer<LLImageFormatted> image = create_image(src_filename); + +	if (!image->load(src_filename)) +	{ +		return NULL; +	} +	 +	if(	(image->getComponents() != 3) && (image->getComponents() != 4) ) +	{ +		std::cout << "Image files with less than 3 or more than 4 components are not supported\n"; +		return NULL; +	} +	 +	if (output_stats) +	{ +		output_image_stats(image, src_filename); +	} +	 +	LLPointer<LLImageRaw> raw_image = new LLImageRaw; +	if (!image->decode(raw_image, 0.0f)) +	{ +		return NULL; +	} +	 +	return raw_image; +} + +// Save a raw image instance into a file +bool save_image(const std::string &dest_filename, LLPointer<LLImageRaw> raw_image, bool output_stats) +{ +	LLPointer<LLImageFormatted> image = create_image(dest_filename); +	 +	if (!image->encode(raw_image, 0.0f)) +	{ +		return false; +	} +	 +	if (output_stats) +	{ +		output_image_stats(image, dest_filename); +	} + +	return image->save(dest_filename); +} + +void store_input_file(std::list<std::string> &input_filenames, const std::string &path) +{ +	// Break the incoming path in its components +	std::string dir = gDirUtilp->getDirName(path); +	std::string name = gDirUtilp->getBaseFileName(path); +	std::string exten = gDirUtilp->getExtension(path); + +	// std::cout << "store_input_file : " << path << ", dir : " << dir << ", name : " << name << ", exten : " << exten << std::endl; +	 +	// If extension is not an image type or "*", exit +	// Note: we don't support complex patterns for the extension like "j??" +	// Note: on most shells, the pattern expansion is done by the shell so that pattern matching limitation is actually not a problem +	if ((exten.compare("*") != 0) && (LLImageBase::getCodecFromExtension(exten) == IMG_CODEC_INVALID)) +	{ +		return; +	} + +	if ((name.find('*') != -1) || ((name.find('?') != -1))) +	{ +		// If file name is a pattern, iterate to get each file name and store +		std::string next_name; +		while (gDirUtilp->getNextFileInDir(dir,name,next_name)) +		{ +			std::string file_name = dir + gDirUtilp->getDirDelimiter() + next_name; +			input_filenames.push_back(file_name); +		} +	} +	else +	{ +		// Verify that the file does exist before storing  +		if (gDirUtilp->fileExists(path)) +		{ +			input_filenames.push_back(path); +		} +		else +		{ +			std::cout << "store_input_file : the file " << path << " could not be found" << std::endl; +		} +	}	 +} + +void store_output_file(std::list<std::string> &output_filenames, std::list<std::string> &input_filenames, const std::string &path) +{ +	// Break the incoming path in its components +	std::string dir = gDirUtilp->getDirName(path); +	std::string name = gDirUtilp->getBaseFileName(path); +	std::string exten = gDirUtilp->getExtension(path); +	 +	// std::cout << "store_output_file : " << path << ", dir : " << dir << ", name : " << name << ", exten : " << exten << std::endl; +	 +	if (dir.empty() && exten.empty()) +	{ +		// If dir and exten are empty, we interpret the name as a file extension type name and will iterate through input list to populate the output list +		exten = name; +		// Make sure the extension is an image type +		if (LLImageBase::getCodecFromExtension(exten) == IMG_CODEC_INVALID) +		{ +			return; +		} +		std::string delim = gDirUtilp->getDirDelimiter(); +		std::list<std::string>::iterator in_file  = input_filenames.begin(); +		std::list<std::string>::iterator end = input_filenames.end(); +		for (; in_file != end; ++in_file) +		{ +			dir = gDirUtilp->getDirName(*in_file); +			name = gDirUtilp->getBaseFileName(*in_file,true); +			std::string file_name = dir + delim + name + "." + exten; +			output_filenames.push_back(file_name); +		} +	} +	else +	{ +		// Make sure the extension is an image type +		if (LLImageBase::getCodecFromExtension(exten) == IMG_CODEC_INVALID) +		{ +			return; +		} +		// Store the path +		output_filenames.push_back(path); +	} +} + +// Holds the metric gathering output in a thread safe way +class LogThread : public LLThread +{ +public: +	std::string mFile; + +	LogThread(std::string& test_name) : LLThread("llimage_libtest log") +	{ +		std::string file_name = test_name + std::string(".slp"); +		mFile = file_name; +	} +		 +	void run() +	{ +		std::ofstream os(mFile.c_str()); +			 +		while (!sAllDone) +		{ +			LLFastTimer::writeLog(os); +			os.flush(); +			ms_sleep(32); +		} +		LLFastTimer::writeLog(os); +		os.flush(); +		os.close(); +	}		 +}; + +int main(int argc, char** argv) +{ +	// List of input and output files +	std::list<std::string> input_filenames; +	std::list<std::string> output_filenames; +	bool analyze_performance = false; +	bool image_stats = false; + +	// Init whatever is necessary +	ll_init_apr(); +	LLImage::initClass(); +	LogThread* fast_timer_log_thread = NULL;	// For performance and metric gathering + +	// Analyze command line arguments +	for (int arg = 1; arg < argc; ++arg) +	{ +		if (!strcmp(argv[arg], "--help") || !strcmp(argv[arg], "-h")) +		{ +            // Send the usage to standard out +            std::cout << USAGE << std::endl; +			return 0; +		} +		else if ((!strcmp(argv[arg], "--input") || !strcmp(argv[arg], "-i")) && arg < argc-1) +		{ +			std::string file_name = argv[arg+1]; +			while (file_name[0] != '-')		// if arg starts with '-', we consider it's not a file name but some other argument +			{ +				// std::cout << "input file name : " << file_name << std::endl;				 +				store_input_file(input_filenames, file_name); +				arg += 1;					// Skip that arg now we know it's a file name +				if ((arg + 1) == argc)		// Break out of the loop if we reach the end of the arg list +					break; +				file_name = argv[arg+1];	// Next argument and loop over +			} +		} +		else if ((!strcmp(argv[arg], "--output") || !strcmp(argv[arg], "-o")) && arg < argc-1) +		{ +			std::string file_name = argv[arg+1]; +			while (file_name[0] != '-')		// if arg starts with '-', we consider it's not a file name but some other argument +			{ +				// std::cout << "output file name : " << file_name << std::endl;				 +				store_output_file(output_filenames, input_filenames, file_name); +				arg += 1;					// Skip that arg now we know it's a file name +				if ((arg + 1) == argc)		// Break out of the loop if we reach the end of the arg list +					break; +				file_name = argv[arg+1];	// Next argument and loop over +			} +		} +		else if (!strcmp(argv[arg], "--logmetrics") || !strcmp(argv[arg], "-log")) +		{ +			// '--logmetrics' needs to be specified with a named test metric argument +			// Note: for the moment, only ImageCompressionTester has been tested +			std::string test_name; +			if ((arg + 1) < argc) +			{ +				test_name = argv[arg+1]; +			} +			if (((arg + 1) >= argc) || (test_name[0] == '-')) +			{ +				// We don't have an argument left in the arg list or the next argument is another option +				std::cout << "No --logmetrics argument given, no perf data will be gathered" << std::endl; +			} +			else +			{ +				LLFastTimer::sMetricLog = TRUE; +				LLFastTimer::sLogName = test_name; +				arg += 1;					// Skip that arg now we know it's a valid test name +				if ((arg + 1) == argc)		// Break out of the loop if we reach the end of the arg list +					break; +			} +		} +		else if (!strcmp(argv[arg], "--analyzeperformance") || !strcmp(argv[arg], "-r")) +		{ +			analyze_performance = true; +		} +		else if (!strcmp(argv[arg], "--image-stats") || !strcmp(argv[arg], "-s")) +		{ +			image_stats = true; +		} +	} +		 +	// Check arguments consistency. Exit with proper message if inconsistent. +	if (input_filenames.size() == 0) +	{ +		std::cout << "No input file, nothing to do -> exit" << std::endl; +		return 0; +	} +	if (analyze_performance && !LLFastTimer::sMetricLog) +	{ +		std::cout << "Cannot create perf report if no perf gathered (i.e. use argument -log <perf> with -r) -> exit" << std::endl; +		return 0; +	} +	 + +	// Create the logging thread if required +	if (LLFastTimer::sMetricLog) +	{ +		LLFastTimer::sLogLock = new LLMutex(NULL); +		fast_timer_log_thread = new LogThread(LLFastTimer::sLogName); +		fast_timer_log_thread->start(); +	} +	 +	// Perform action on each input file +	std::list<std::string>::iterator in_file  = input_filenames.begin(); +	std::list<std::string>::iterator out_file = output_filenames.begin(); +	std::list<std::string>::iterator in_end = input_filenames.end(); +	std::list<std::string>::iterator out_end = output_filenames.end(); +	for (; in_file != in_end; ++in_file) +	{ +		// Load file +		LLPointer<LLImageRaw> raw_image = load_image(*in_file, image_stats); +		if (!raw_image) +		{ +			std::cout << "Error: Image " << *in_file << " could not be loaded" << std::endl; +			continue; +		} +	 +		// Save file +		if (out_file != out_end) +		{ +			if (!save_image(*out_file, raw_image, image_stats)) +			{ +				std::cout << "Error: Image " << *out_file << " could not be saved" << std::endl; +			} +			else +			{ +				std::cout << *in_file << " -> " << *out_file << std::endl; +			} +			++out_file; +		} +	} + +	// Stop the perf gathering system if needed +	if (LLFastTimer::sMetricLog) +	{ +		LLMetricPerformanceTesterBasic::deleteTester(LLFastTimer::sLogName); +		sAllDone = true; +	} +	 +	// Output perf data if requested by user +	if (analyze_performance) +	{ +		std::cout << "Analyzing performance" << std::endl; +		 +		std::string baseline_name = LLFastTimer::sLogName + "_baseline.slp"; +		std::string current_name  = LLFastTimer::sLogName + ".slp";  +		std::string report_name   = LLFastTimer::sLogName + "_report.csv"; +		 +		LLMetricPerformanceTesterBasic::doAnalysisMetrics(baseline_name, current_name, report_name); +	} +	 +	// Cleanup and exit +	LLImage::cleanupClass(); +	if (fast_timer_log_thread) +	{ +		fast_timer_log_thread->shutdown(); +	} +	 +	return 0; +} diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.h b/indra/integration_tests/llimage_libtest/llimage_libtest.h new file mode 100644 index 0000000000..63f3d46b50 --- /dev/null +++ b/indra/integration_tests/llimage_libtest/llimage_libtest.h @@ -0,0 +1,29 @@ +/**  + * @file llimage_libtest.h + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ +#ifndef LLIMAGE_LIBTEST_H +#define LLIMAGE_LIBTEST_H + + +#endif | 
