diff options
21 files changed, 752 insertions, 125 deletions
@@ -86,3 +86,4 @@ f1827b441e05bf37c68e2c15ebc6d09e9b03f527 2.6.0-start c5bdef3aaa2744626aef3c217ce29e1900d357b3 2.6.1-start 9e4641f4a7870c0f565a25a2971368d5a29516a1 DRTVWR-41_2.6.0-beta2 9e4641f4a7870c0f565a25a2971368d5a29516a1 2.6.0-beta2 +56b2778c743c2a964d82e1caf11084d76a87de2c 2.6.2-start 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..365f5f758c --- /dev/null +++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp @@ -0,0 +1,437 @@ +/** + * @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; + if (!dir.empty()) + { + file_name = dir + delim + name + "." + exten; + } + else + { + file_name = 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 diff --git a/indra/llcommon/llmetricperformancetester.cpp b/indra/llcommon/llmetricperformancetester.cpp index 5fa3a5ea07..41d3eb0bf3 100644 --- a/indra/llcommon/llmetricperformancetester.cpp +++ b/indra/llcommon/llmetricperformancetester.cpp @@ -63,7 +63,18 @@ BOOL LLMetricPerformanceTesterBasic::addTester(LLMetricPerformanceTesterBasic* t sTesterMap.insert(std::make_pair(name, tester)); return TRUE; } - + +/*static*/ +void LLMetricPerformanceTesterBasic::deleteTester(std::string name) +{ + name_tester_map_t::iterator tester = sTesterMap.find(name); + if (tester != sTesterMap.end()) + { + delete tester->second; + sTesterMap.erase(tester); + } +} + /*static*/ LLMetricPerformanceTesterBasic* LLMetricPerformanceTesterBasic::getTester(std::string name) { @@ -83,7 +94,78 @@ BOOL LLMetricPerformanceTesterBasic::isMetricLogRequested(std::string name) return (LLFastTimer::sMetricLog && ((LLFastTimer::sLogName == name) || (LLFastTimer::sLogName == DEFAULT_METRIC_NAME))); } +/*static*/ +LLSD LLMetricPerformanceTesterBasic::analyzeMetricPerformanceLog(std::istream& is) +{ + LLSD ret; + LLSD cur; + + while (!is.eof() && LLSDSerialize::fromXML(cur, is)) + { + for (LLSD::map_iterator iter = cur.beginMap(); iter != cur.endMap(); ++iter) + { + std::string label = iter->first; + + LLMetricPerformanceTesterBasic* tester = LLMetricPerformanceTesterBasic::getTester(iter->second["Name"].asString()) ; + if(tester) + { + ret[label]["Name"] = iter->second["Name"] ; + + S32 num_of_metrics = tester->getNumberOfMetrics() ; + for(S32 index = 0 ; index < num_of_metrics ; index++) + { + ret[label][ tester->getMetricName(index) ] = iter->second[ tester->getMetricName(index) ] ; + } + } + } + } + + return ret; +} + +/*static*/ +void LLMetricPerformanceTesterBasic::doAnalysisMetrics(std::string baseline, std::string target, std::string output) +{ + if(!LLMetricPerformanceTesterBasic::hasMetricPerformanceTesters()) + { + return ; + } + + // Open baseline and current target, exit if one is inexistent + std::ifstream base_is(baseline.c_str()); + std::ifstream target_is(target.c_str()); + if (!base_is.is_open() || !target_is.is_open()) + { + llwarns << "'-analyzeperformance' error : baseline or current target file inexistent" << llendl; + base_is.close(); + target_is.close(); + return; + } + //analyze baseline + LLSD base = analyzeMetricPerformanceLog(base_is); + base_is.close(); + + //analyze current + LLSD current = analyzeMetricPerformanceLog(target_is); + target_is.close(); + + //output comparision + std::ofstream os(output.c_str()); + + os << "Label, Metric, Base(B), Target(T), Diff(T-B), Percentage(100*T/B)\n"; + for(LLMetricPerformanceTesterBasic::name_tester_map_t::iterator iter = LLMetricPerformanceTesterBasic::sTesterMap.begin() ; + iter != LLMetricPerformanceTesterBasic::sTesterMap.end() ; ++iter) + { + LLMetricPerformanceTesterBasic* tester = ((LLMetricPerformanceTesterBasic*)iter->second) ; + tester->analyzePerformance(&os, &base, ¤t) ; + } + + os.flush(); + os.close(); +} + + //---------------------------------------------------------------------------------------------- // LLMetricPerformanceTesterBasic : Tester instance methods //---------------------------------------------------------------------------------------------- diff --git a/indra/llcommon/llmetricperformancetester.h b/indra/llcommon/llmetricperformancetester.h index 1372f48dcf..1a18cdf36f 100644 --- a/indra/llcommon/llmetricperformancetester.h +++ b/indra/llcommon/llmetricperformancetester.h @@ -62,6 +62,8 @@ public: */ virtual void analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current) ; + static void doAnalysisMetrics(std::string baseline, std::string target, std::string output) ; + /** * @return Returns the number of the test metrics in this tester instance. */ @@ -116,6 +118,7 @@ protected: private: void preOutputTestResults(LLSD* sd) ; void postOutputTestResults(LLSD* sd) ; + static LLSD analyzeMetricPerformanceLog(std::istream& is) ; std::string mName ; // Name of this tester instance S32 mCount ; // Current record count @@ -135,6 +138,12 @@ public: static LLMetricPerformanceTesterBasic* getTester(std::string name) ; /** + * @return Delete the named tester from the list + * @param[in] name - Name of the tester instance to delete. + */ + static void deleteTester(std::string name); + + /** * @return Returns TRUE if that metric *or* the default catch all metric has been requested to be logged * @param[in] name - Name of the tester queried. */ diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h index d22c879243..488ec5b239 100644 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -29,7 +29,7 @@ const S32 LL_VERSION_MAJOR = 2; const S32 LL_VERSION_MINOR = 6; -const S32 LL_VERSION_PATCH = 2; +const S32 LL_VERSION_PATCH = 3; const S32 LL_VERSION_BUILD = 0; const char * const LL_CHANNEL = "Second Life Developer"; diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 825b9aab1a..18444f3934 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -266,13 +266,13 @@ public: // subclasses must return a prefered file extension (lowercase without a leading dot) virtual std::string getExtension() = 0; // calcHeaderSize() returns the maximum size of header; - // 0 indicates we don't know have a header and have to lead the entire file + // 0 indicates we don't have a header and have to read the entire file virtual S32 calcHeaderSize() { return 0; }; // calcDataSize() returns how many bytes to read to load discard_level (including header) virtual S32 calcDataSize(S32 discard_level); // calcDiscardLevelBytes() returns the smallest valid discard level based on the number of input bytes virtual S32 calcDiscardLevelBytes(S32 bytes); - // getRawDiscardLevel()by default returns mDiscardLevel, but may be overridden (LLImageJ2C) + // getRawDiscardLevel() by default returns mDiscardLevel, but may be overridden (LLImageJ2C) virtual S8 getRawDiscardLevel() { return mDiscardLevel; } BOOL load(const std::string& filename); diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index cb2a85fa91..80fec7f8a0 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -474,6 +474,7 @@ LLImageCompressionTester::LLImageCompressionTester() : LLMetricPerformanceTester LLImageCompressionTester::~LLImageCompressionTester() { + outputTestResults(); LLImageJ2C::sTesterp = NULL; } diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index d4ec377e03..c0c9ea1451 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -793,21 +793,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL if ( chat.mSourceType == CHAT_SOURCE_OBJECT && chat.mFromID.notNull()) { // for object IMs, create a secondlife:///app/objectim SLapp - std::string url = LLSLURL("objectim", chat.mFromID, "").getSLURLString(); - url += "?name=" + chat.mFromName; - url += "&owner=" + chat.mOwnerID.asString(); - - std::string slurl = args["slurl"].asString(); - if (slurl.empty()) - { - LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent); - if(region) - { - LLSLURL region_slurl(region->getName(), chat.mPosAgent); - slurl = region_slurl.getLocationString(); - } - } - url += "&slurl=" + LLURI::escape(slurl); + std::string url = LLViewerChat::getSenderSLURL(chat, args); // set the link for the object name to be the objectim SLapp // (don't let object names with hyperlinks override our objectim Url) diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp index 899e0431e7..8584885bc9 100644 --- a/indra/newview/llchatitemscontainerctrl.cpp +++ b/indra/newview/llchatitemscontainerctrl.cpp @@ -213,17 +213,6 @@ void LLNearbyChatToastPanel::init(LLSD& notification) { LLStyle::Params style_params_name; - std::string href; - - if (mSourceType == CHAT_SOURCE_AGENT) - { - href = LLSLURL("agent", mFromID, "about").getSLURLString(); - } - else - { - href = LLSLURL("object", mFromID, "inspect").getSLURLString(); - } - LLColor4 user_name_color = LLUIColorTable::instance().getColor("HTMLLinkColor"); style_params_name.color(user_name_color); @@ -232,7 +221,7 @@ void LLNearbyChatToastPanel::init(LLSD& notification) style_params_name.font.name(font_name); style_params_name.font.size(font_style_size); - style_params_name.link_href = href; + style_params_name.link_href = notification["sender_slurl"].asString(); style_params_name.is_link = true; msg_text->appendText(str_sender, FALSE, style_params_name); diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index 2bafb9a4a7..6e78ea6bbe 100755 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -1538,36 +1538,6 @@ void LLFastTimerView::doAnalysisDefault(std::string baseline, std::string target os.close(); } -//------------------------- -//static -LLSD LLFastTimerView::analyzeMetricPerformanceLog(std::istream& is) -{ - LLSD ret; - LLSD cur; - - while (!is.eof() && LLSDSerialize::fromXML(cur, is)) - { - for (LLSD::map_iterator iter = cur.beginMap(); iter != cur.endMap(); ++iter) - { - std::string label = iter->first; - - LLMetricPerformanceTesterBasic* tester = LLMetricPerformanceTesterBasic::getTester(iter->second["Name"].asString()) ; - if(tester) - { - ret[label]["Name"] = iter->second["Name"] ; - - S32 num_of_metrics = tester->getNumberOfMetrics() ; - for(S32 index = 0 ; index < num_of_metrics ; index++) - { - ret[label][ tester->getMetricName(index) ] = iter->second[ tester->getMetricName(index) ] ; - } - } - } - } - - return ret; -} - //static void LLFastTimerView::outputAllMetrics() { @@ -1583,48 +1553,6 @@ void LLFastTimerView::outputAllMetrics() } //static -void LLFastTimerView::doAnalysisMetrics(std::string baseline, std::string target, std::string output) -{ - if(!LLMetricPerformanceTesterBasic::hasMetricPerformanceTesters()) - { - return ; - } - - // Open baseline and current target, exit if one is inexistent - std::ifstream base_is(baseline.c_str()); - std::ifstream target_is(target.c_str()); - if (!base_is.is_open() || !target_is.is_open()) - { - llwarns << "'-analyzeperformance' error : baseline or current target file inexistent" << llendl; - base_is.close(); - target_is.close(); - return; - } - - //analyze baseline - LLSD base = analyzeMetricPerformanceLog(base_is); - base_is.close(); - - //analyze current - LLSD current = analyzeMetricPerformanceLog(target_is); - target_is.close(); - - //output comparision - std::ofstream os(output.c_str()); - - os << "Label, Metric, Base(B), Target(T), Diff(T-B), Percentage(100*T/B)\n"; - for(LLMetricPerformanceTesterBasic::name_tester_map_t::iterator iter = LLMetricPerformanceTesterBasic::sTesterMap.begin() ; - iter != LLMetricPerformanceTesterBasic::sTesterMap.end() ; ++iter) - { - LLMetricPerformanceTesterBasic* tester = ((LLMetricPerformanceTesterBasic*)iter->second) ; - tester->analyzePerformance(&os, &base, ¤t) ; - } - - os.flush(); - os.close(); -} - -//static void LLFastTimerView::doAnalysis(std::string baseline, std::string target, std::string output) { if(LLFastTimer::sLog) @@ -1635,7 +1563,7 @@ void LLFastTimerView::doAnalysis(std::string baseline, std::string target, std:: if(LLFastTimer::sMetricLog) { - doAnalysisMetrics(baseline, target, output) ; + LLMetricPerformanceTesterBasic::doAnalysisMetrics(baseline, target, output) ; return ; } } diff --git a/indra/newview/llfasttimerview.h b/indra/newview/llfasttimerview.h index c409445d86..ea8251191b 100644 --- a/indra/newview/llfasttimerview.h +++ b/indra/newview/llfasttimerview.h @@ -42,8 +42,6 @@ public: private: static void doAnalysisDefault(std::string baseline, std::string target, std::string output) ; - static void doAnalysisMetrics(std::string baseline, std::string target, std::string output) ; - static LLSD analyzeMetricPerformanceLog(std::istream& is) ; static LLSD analyzePerformanceLogDefault(std::istream& is) ; static void exportCharts(const std::string& base, const std::string& target); diff --git a/indra/newview/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp index de5439e4e0..0d9daeb44e 100644 --- a/indra/newview/llnearbychathandler.cpp +++ b/indra/newview/llnearbychathandler.cpp @@ -558,6 +558,7 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, const LLSD &args) } */ + // Add a nearby chat toast. LLUUID id; id.generate(); @@ -583,6 +584,10 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, const LLSD &args) notification["text_color"] = r_color_name; notification["color_alpha"] = r_color_alpha; notification["font_size"] = (S32)LLViewerChat::getChatFontSize() ; + + // Pass sender info so that it can be rendered properly (STORM-1021). + notification["sender_slurl"] = LLViewerChat::getSenderSLURL(chat_msg, args); + channel->addNotification(notification); } diff --git a/indra/newview/llviewerchat.cpp b/indra/newview/llviewerchat.cpp index 0af850a46b..286b16bab2 100644 --- a/indra/newview/llviewerchat.cpp +++ b/indra/newview/llviewerchat.cpp @@ -31,6 +31,8 @@ #include "llagent.h" // gAgent #include "lluicolortable.h" #include "llviewercontrol.h" // gSavedSettings +#include "llviewerregion.h" +#include "llworld.h" #include "llinstantmessage.h" //SYSTEM_FROM // LLViewerChat @@ -214,3 +216,43 @@ void LLViewerChat::formatChatMsg(const LLChat& chat, std::string& formated_msg) } +//static +std::string LLViewerChat::getSenderSLURL(const LLChat& chat, const LLSD& args) +{ + switch (chat.mSourceType) + { + case CHAT_SOURCE_AGENT: + return LLSLURL("agent", chat.mFromID, "about").getSLURLString(); + + case CHAT_SOURCE_OBJECT: + return getObjectImSLURL(chat, args); + + default: + llwarns << "Getting SLURL for an unsupported sender type: " << chat.mSourceType << llendl; + } + + return LLStringUtil::null; +} + +//static +std::string LLViewerChat::getObjectImSLURL(const LLChat& chat, const LLSD& args) +{ + std::string url = LLSLURL("objectim", chat.mFromID, "").getSLURLString(); + url += "?name=" + chat.mFromName; + url += "&owner=" + chat.mOwnerID.asString(); + + std::string slurl = args["slurl"].asString(); + if (slurl.empty()) + { + LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent); + if(region) + { + LLSLURL region_slurl(region->getName(), chat.mPosAgent); + slurl = region_slurl.getLocationString(); + } + } + + url += "&slurl=" + LLURI::escape(slurl); + + return url; +} diff --git a/indra/newview/llviewerchat.h b/indra/newview/llviewerchat.h index a9f9a98960..0f15d29f04 100644 --- a/indra/newview/llviewerchat.h +++ b/indra/newview/llviewerchat.h @@ -40,6 +40,10 @@ public: static LLFontGL* getChatFont(); static S32 getChatFontSize(); static void formatChatMsg(const LLChat& chat, std::string& formated_msg); + static std::string getSenderSLURL(const LLChat& chat, const LLSD& args); + +private: + static std::string getObjectImSLURL(const LLChat& chat, const LLSD& args); }; diff --git a/indra/newview/skins/default/xui/en/menu_attachment_self.xml b/indra/newview/skins/default/xui/en/menu_attachment_self.xml index 84e81397be..b8128da358 100644 --- a/indra/newview/skins/default/xui/en/menu_attachment_self.xml +++ b/indra/newview/skins/default/xui/en/menu_attachment_self.xml @@ -68,7 +68,7 @@ name="Stand Up"> function="Self.EnableStandUp" /> </menu_item_call> <menu_item_call - label="Change Outfit" + label="My Appearance" name="Change Outfit"> <menu_item_call.on_click function="CustomizeAvatar" /> diff --git a/indra/newview/skins/default/xui/en/menu_avatar_self.xml b/indra/newview/skins/default/xui/en/menu_avatar_self.xml index 2afa29ec10..d727294cc8 100644 --- a/indra/newview/skins/default/xui/en/menu_avatar_self.xml +++ b/indra/newview/skins/default/xui/en/menu_avatar_self.xml @@ -193,7 +193,7 @@ </menu_item_call> </context_menu> <menu_item_call - label="Change Outfit" + label="My Appearance" layout="topleft" name="Chenge Outfit"> <menu_item_call.on_click diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index ea40a08c95..8c783ae218 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -41,7 +41,7 @@ parameter="agent" /> </menu_item_call> <menu_item_call - label="Change Outfit" + label="My Appearance" name="ChangeOutfit"> <menu_item_call.on_click function="CustomizeAvatar" /> diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index f703acaa66..d9d3fab6d4 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -821,22 +821,6 @@ You need to enter either the Username or both the First and Last name of your av <notification icon="alertmodal.tga" - name="AddClassified" - type="alertmodal"> -Classified ads appear in the 'Classified' section of the Search directory and on [http://secondlife.com/community/classifieds secondlife.com] for one week. -Fill out your ad, then click 'Publish...' to add it to the directory. -You'll be asked for a price to pay when clicking Publish. -Paying more makes your ad appear higher in the list, and also appear higher when people search for keywords. - <tag>confirm</tag> - <usetemplate - ignoretext="How to create a new Classified ad" - name="okcancelignore" - notext="Cancel" - yestext="OK"/> - </notification> - - <notification - icon="alertmodal.tga" name="DeleteClassified" type="alertmodal"> Delete classified '[NAME]'? |