diff --git a/autobuild.xml b/autobuild.xml index 7279e7ebdb..9f3a56a688 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3,6 +3,34 @@ installables + gstreamer10 + + copyright + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + license + LGPL + license_file + LICENSES/gstreamer.txt + name + gstreamer10 + platforms + + linux + + archive + + hash + 01f39ecf80dae64e30402ac384035b3e + url + http://downloads.phoenixviewer.com/gstreamer10-1.6.3.201605191852-linux-201605191852.tar.bz2 + + name + linux + + + version + 0.10.6.294903 + breakpad copyright @@ -792,9 +820,9 @@ archive hash - 96dd770f246917589b776300a2d07f9e + 0bcccd248a5e4084af4026eee439816b url - http://3p.firestormviewer.org/curl-7.54.1.212891029-linux64-212891029.tar.bz2 + http://3p.firestormviewer.org/curl-7.81.0.220511906-linux64_bionic-220511906.tar.bz2 name linux64 @@ -3567,30 +3595,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors name darwin64 - linux - - archive - - hash - 9f9582031af3b78d6153ec296d6dde9f - url - http://3p.firestormviewer.org/vlc_bin-2.2.3-linux-201607071822-r16.tar.bz2 - - name - linux - - linux64 - - archive - - hash - 5eace400c487011a678493fc520be24d - url - http://3p.firestormviewer.org/vlc_bin-2.2.3-linux-x64-201610182130-r16.tar.bz2 - - name - linux64 - windows archive diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index 9d76be92c8..646ff1cfa2 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -112,6 +112,10 @@ if (NOT USE_BUGSPLAT) add_subdirectory(${LIBS_OPEN_PREFIX}llcrashlogger) endif (NOT USE_BUGSPLAT) +if( LINUX ) + add_subdirectory(${VIEWER_PREFIX}linux_crash_logger) +endif() + add_subdirectory(${LIBS_OPEN_PREFIX}llplugin) add_subdirectory(${LIBS_OPEN_PREFIX}llui) add_subdirectory(${LIBS_OPEN_PREFIX}viewer_components) @@ -159,6 +163,10 @@ endif (USE_BUGSPLAT) add_subdirectory(${VIEWER_PREFIX}newview) add_dependencies(viewer firestorm-bin) +set_target_properties( + firestorm-bin PROPERTIES + VS_DEBUGGER_WORKING_DIRECTORY "..\\..\\indra\\newview") + add_subdirectory(${VIEWER_PREFIX}doxygen EXCLUDE_FROM_ALL) if (LL_TESTS) diff --git a/indra/cmake/GStreamer10Plugin.cmake b/indra/cmake/GStreamer10Plugin.cmake new file mode 100644 index 0000000000..ded45da610 --- /dev/null +++ b/indra/cmake/GStreamer10Plugin.cmake @@ -0,0 +1,32 @@ +# -*- cmake -*- +include(Prebuilt) +include(GLIB) + +if (USESYSTEMLIBS) + include(FindPkgConfig) + + pkg_check_modules(GSTREAMER10 REQUIRED gstreamer-1.0) + pkg_check_modules(GSTREAMER10_PLUGINS_BASE REQUIRED gstreamer-plugins-base-1.0) +elseif (LINUX OR WINDOWS) + use_prebuilt_binary(gstreamer10) + use_prebuilt_binary(libxml2) + set(GSTREAMER10_FOUND ON FORCE BOOL) + set(GSTREAMER10_PLUGINS_BASE_FOUND ON FORCE BOOL) + set(GSTREAMER10_INCLUDE_DIRS + ${GLIB_INCLUDE_DIRS} + ${LIBS_PREBUILT_DIR}/include/gstreamer-1.0 + ${LIBS_PREBUILT_DIR}/include/libxml2 + ) + # We don't need to explicitly link against gstreamer itself, because + # LLMediaImplGStreamer probes for the system's copy at runtime. + set(GSTREAMER10_LIBRARIES) +endif (USESYSTEMLIBS) + +if (GSTREAMER10_FOUND AND GSTREAMER10_PLUGINS_BASE_FOUND) + set(GSTREAMER10 ON CACHE BOOL "Build with GStreamer-1.0 streaming media support.") +endif (GSTREAMER10_FOUND AND GSTREAMER10_PLUGINS_BASE_FOUND) + +if (GSTREAMER10) + add_definitions(-DLL_GSTREAMER10_ENABLED=1) +endif (GSTREAMER10) + diff --git a/indra/cmake/bugsplat.cmake b/indra/cmake/bugsplat.cmake index af8610e261..ce61b51b9b 100644 --- a/indra/cmake/bugsplat.cmake +++ b/indra/cmake/bugsplat.cmake @@ -35,8 +35,10 @@ if (USE_BUGSPLAT) set(BUGSPLAT_DB "" CACHE STRING "BugSplat crash database name") if( LINUX ) - set(BUGSPLAT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/breakpad) - add_compile_definitions(__STDC_FORMAT_MACROS) + set(BUGSPLAT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/breakpad) + # Sadly we cannot have the nice things yet and need add_definitions for older cmake + #add_compile_definitions(__STDC_FORMAT_MACROS) + add_definitions(-D__STDC_FORMAT_MACROS) else() set(BUGSPLAT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/bugsplat) endif() diff --git a/indra/linux_crash_logger/CMakeLists.txt b/indra/linux_crash_logger/CMakeLists.txt index aa82ed12cc..ab8ef14fce 100644 --- a/indra/linux_crash_logger/CMakeLists.txt +++ b/indra/linux_crash_logger/CMakeLists.txt @@ -3,18 +3,11 @@ project(linux_crash_logger) include(00-Common) -include(GLH) -include(LLCoreHttp) -include(LLCommon) -include(LLCrashLogger) -include(LLMath) -include(LLMessage) -include(LLFileSystem) -include(LLXML) include(Linking) include(UI) -include(FreeType) -include(Boost) +include(CURL) +include(OpenSSL) +include(ZLIB) include_directories( ${LLCOREHTTP_INCLUDE_DIRS} @@ -36,7 +29,6 @@ include_directories(SYSTEM set(linux_crash_logger_SOURCE_FILES linux_crash_logger.cpp - llcrashloggerlinux.cpp ) set(linux_crash_logger_HEADER_FILES @@ -61,19 +53,13 @@ set(LIBRT_LIBRARY rt) target_link_libraries(linux-crash-logger - ${LLCRASHLOGGER_LIBRARIES} - ${LLFILESYSTEM_LIBRARIES} - ${LLXML_LIBRARIES} - ${LLMESSAGE_LIBRARIES} - ${LLMATH_LIBRARIES} - ${LLCOREHTTP_LIBRARIES} - ${LLCOMMON_LIBRARIES} - ${BOOST_FIBER_LIBRARY} - ${BOOST_CONTEXT_LIBRARY} ${UI_LIBRARIES} - ${DB_LIBRARIES} - ${FREETYPE_LIBRARIES} + ${CURL_LIBRARIES} + ${OPENSSL_LIBRARIES} + ${CRYPTO_LIBRARIES} + ${ZLIB_LIBRARIES} ${LIBRT_LIBRARY} + X11 ) add_custom_target(linux-crash-logger-target ALL diff --git a/indra/linux_crash_logger/linux_crash_logger.cpp b/indra/linux_crash_logger/linux_crash_logger.cpp index 63e5409876..5d55e551a4 100644 --- a/indra/linux_crash_logger/linux_crash_logger.cpp +++ b/indra/linux_crash_logger/linux_crash_logger.cpp @@ -24,35 +24,77 @@ * $/LicenseInfo$ */ -#include "linden_common.h" -#include "llcrashloggerlinux.h" -#include "llsdutil.h" +#include +#include +#include +#include +/* Called via + execl( gCrashLogger.c_str(), gCrashLogger.c_str(), descriptor.path(), gVersion.c_str(), gBugsplatDB.c_str(), nullptr ); +*/ int main(int argc, char **argv) { - LL_INFOS() << "Starting crash reporter." << LL_ENDL; + std::cerr << "linux crash logger called: "; + for( int i = 1; i < argc; ++i ) + std::cerr << argv[i] << " "; - LLCrashLoggerLinux app; - app.parseCommandOptions(argc, argv); + std::cerr << std::endl; - LLSD options = LLApp::instance()->getOptionData( - LLApp::PRIORITY_COMMAND_LINE); - //LLApp::PRIORITY_RUNTIME_OVERRIDE); - - - if (!(options.has("pid") && options.has("dumpdir"))) + if( argc < 4 ) { - LL_WARNS() << "Insufficient parameters to crash report." << LL_ENDL; + std::cerr << argv[0] << "Not enough arguments" << std::endl; + return 1; } - if (! app.init()) + std::string dmpFile{ argv[1] }; + std::string version{ argv[2] }; + std::string strDb{ argv[3] }; + std::string strAsk{ argv[4] }; + + if( strAsk == "ask" ) { - LL_WARNS() << "Unable to initialize application." << LL_ENDL; - return 1; + auto choice = fl_choice( "Firestorm has crashed, submit the minidump?", "No", "Yes", nullptr ); + if( choice == 0 ) + { + std::cerr << "Abort send due to users choice" << std::endl; + return 0; + } } - app.frame(); - app.cleanup(); - LL_INFOS() << "Crash reporter finished normally." << LL_ENDL; - return 0; + std::string url{ "https://" }; + url += strDb; + url += ".bugsplat.com/post/bp/crash/crashpad.php"; + + curl_global_init(CURL_GLOBAL_ALL); + + auto curl = curl_easy_init(); + if( curl) + { + auto form = curl_mime_init(curl); + + auto field = curl_mime_addpart(form); + curl_mime_name(field, "upload_file_minidump"); + curl_mime_filedata(field, dmpFile.c_str() ); + + field = curl_mime_addpart(form); + curl_mime_name(field, "product"); + curl_mime_data(field, "Firestorm-Releasex64", CURL_ZERO_TERMINATED); + + field = curl_mime_addpart(form); + curl_mime_name(field, "version"); + curl_mime_data(field, version.c_str(), CURL_ZERO_TERMINATED); + + curl_easy_setopt(curl, CURLOPT_URL, url.c_str() ); + curl_easy_setopt(curl, CURLOPT_MIMEPOST, form); + + auto res = curl_easy_perform(curl); + + if(res != CURLE_OK) + std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl; + + curl_easy_cleanup(curl); + + curl_mime_free(form); + } + return 0; } diff --git a/indra/linux_crash_logger/llcrashloggerlinux.cpp b/indra/linux_crash_logger/llcrashloggerlinux.cpp deleted file mode 100644 index 0395935d04..0000000000 --- a/indra/linux_crash_logger/llcrashloggerlinux.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/** - * @file llcrashloggerlinux.cpp - * @brief Linux crash logger implementation - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, 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 "llcrashloggerlinux.h" - -#include - -#include "linden_common.h" - -#include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME -#include "llerror.h" -#include "llfile.h" -#include "lltimer.h" -#include "llstring.h" -#include "lldir.h" -#include "llsdserialize.h" - -#if LL_GTK -# include "gtk/gtk.h" -#error "Direct use of GTK is deprecated" -#endif // LL_GTK - -#define MAX_LOADSTRING 100 - -// Fire-901 / Crashreporting: Brand for FS, add URL to privacy policy - -// These need to be localized. -// static const char dialog_text[] = -// "Second Life appears to have crashed or frozen last time it ran.\n" -// "This crash reporter collects information about your computer's hardware, operating system, and some Second Life logs, all of which are used for debugging purposes only.\n" -// "\n" -// "Send crash report?"; -// -// static const char dialog_title[] = -// "Second Life Crash Logger"; - -static const char dialog_text[] = -"Firestorm appears to have crashed or frozen last time it ran.\n" -"This crash reporter collects information about your computer's hardware, operating system which are used for debugging purposes only. SecondLife logs are not collected.\n" -"This report will be send to firestormviewer.org. Review our privacy policy at http://www.firestormviewer.org/privacy-policy for more information.\n" -"\n" -"Send crash report?"; - -static const char dialog_title[] = -"Firestorm Crash Logger"; - -// - -#if 0 - -#if LL_GTK -static void response_callback (GtkDialog *dialog, - gint arg1, - gpointer user_data) -{ - gint *response = (gint*)user_data; - *response = arg1; - gtk_widget_destroy(GTK_WIDGET(dialog)); - gtk_main_quit(); -} -#endif // LL_GTK - -static BOOL do_ask_dialog(void) -{ -#if LL_GTK - gtk_disable_setlocale(); - if (!gtk_init_check(NULL, NULL)) { - LL_INFOS() << "Could not initialize GTK for 'ask to send crash report' dialog; not sending report." << LL_ENDL; - return FALSE; - } - - GtkWidget *win = NULL; - GtkDialogFlags flags = GTK_DIALOG_MODAL; - GtkMessageType messagetype = GTK_MESSAGE_QUESTION; - GtkButtonsType buttons = GTK_BUTTONS_YES_NO; - gint response = GTK_RESPONSE_NONE; - - win = gtk_message_dialog_new(NULL, - flags, messagetype, buttons, - "%s", dialog_text); - gtk_window_set_type_hint(GTK_WINDOW(win), - GDK_WINDOW_TYPE_HINT_DIALOG); - gtk_window_set_title(GTK_WINDOW(win), dialog_title); - g_signal_connect (win, - "response", - G_CALLBACK (response_callback), - &response); - gtk_widget_show_all (win); - gtk_main(); - - return (GTK_RESPONSE_OK == response || - GTK_RESPONSE_YES == response || - GTK_RESPONSE_APPLY == response); -#else - return FALSE; -#endif // LL_GTK -} -#endif - -LLCrashLoggerLinux::LLCrashLoggerLinux(void) -{ -} - -LLCrashLoggerLinux::~LLCrashLoggerLinux(void) -{ -} - -void LLCrashLoggerLinux::gatherPlatformSpecificFiles() -{ -} - -bool LLCrashLoggerLinux::frame() -{ - // Get around the crash logger popping up all the time. - // Right now there seems to be no easy way to test if there's logs from a real crash to send. Which - // would be preferred, as then asking for sending in data makes sense. Right now the dialog will just open always. - - // bool send_logs = true; - // if(CRASH_BEHAVIOR_ASK == getCrashBehavior()) - // { - // send_logs = do_ask_dialog(); - // } - // else if(CRASH_BEHAVIOR_NEVER_SEND == getCrashBehavior()) - // { - // send_logs = false; - // } - - bool send_logs = (CRASH_BEHAVIOR_NEVER_SEND == getCrashBehavior()); - - // - - if(send_logs) - { - sendCrashLogs(); - } - return true; -} - -bool LLCrashLoggerLinux::cleanup() -{ - commonCleanup(); - mKeyMaster.releaseMaster(); - return true; -} - -void LLCrashLoggerLinux::updateApplication(const std::string& message) -{ - LLCrashLogger::updateApplication(message); -} diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp index 8eccae00c7..b94a243fb2 100644 --- a/indra/llcorehttp/_httpoprequest.cpp +++ b/indra/llcorehttp/_httpoprequest.cpp @@ -508,7 +508,12 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service) check_curl_easy_setopt(mCurlHandle, CURLOPT_NOPROGRESS, 1); check_curl_easy_setopt(mCurlHandle, CURLOPT_URL, mReqURL.c_str()); check_curl_easy_setopt(mCurlHandle, CURLOPT_PRIVATE, getHandle()); + +// Newer versions of curl are stricter with checkinng Cotent-Encoding: header +// Aws returns Content-Encoding: binary/octet-stream which is no valid scheme defined by HTTP/1.1 (compress,deflate, gzip) +#if LIBCURL_VERSION_NUM < 0x075100 check_curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, ""); +#endif check_curl_easy_setopt(mCurlHandle, CURLOPT_AUTOREFERER, 1); check_curl_easy_setopt(mCurlHandle, CURLOPT_MAXREDIRS, HTTP_REDIRECTS_DEFAULT); diff --git a/indra/llcorehttp/httpcommon.cpp b/indra/llcorehttp/httpcommon.cpp index 61ba83594e..8012da4370 100644 --- a/indra/llcorehttp/httpcommon.cpp +++ b/indra/llcorehttp/httpcommon.cpp @@ -289,8 +289,12 @@ CURL *getCurlTemplateHandle() check_curl_code(result, CURLOPT_NOSIGNAL); result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_NOPROGRESS, 1); check_curl_code(result, CURLOPT_NOPROGRESS); +// Newer versions of curl are stricter with checkinng Cotent-Encoding: header +// Aws returns Content-Encoding: binary/octet-stream which is no valid scheme defined by HTTP/1.1 (compress,deflate, gzip) +#if LIBCURL_VERSION_NUM < 0x075100 result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_ENCODING, ""); check_curl_code(result, CURLOPT_ENCODING); +#endif result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_AUTOREFERER, 1); check_curl_code(result, CURLOPT_AUTOREFERER); result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_FOLLOWLOCATION, 1); diff --git a/indra/media_plugins/CMakeLists.txt b/indra/media_plugins/CMakeLists.txt index 32e440a829..cde480a46d 100644 --- a/indra/media_plugins/CMakeLists.txt +++ b/indra/media_plugins/CMakeLists.txt @@ -2,10 +2,9 @@ add_subdirectory(base) if (LINUX) -# add_subdirectory(gstreamer010) - add_subdirectory(cef) - add_subdirectory(libvlc) - #add_subdirectory(example) + add_subdirectory(gstreamer10) + add_subdirectory(cef) + #add_subdirectory(libvlc) endif (LINUX) if (DARWIN) diff --git a/indra/media_plugins/gstreamer10/CMakeLists.txt b/indra/media_plugins/gstreamer10/CMakeLists.txt new file mode 100644 index 0000000000..730a2c27fb --- /dev/null +++ b/indra/media_plugins/gstreamer10/CMakeLists.txt @@ -0,0 +1,78 @@ +# -*- cmake -*- + +project(media_plugin_gstreamer10) + +include(00-Common) +include(LLCommon) +include(LLImage) +include(LLPlugin) +include(LLMath) +include(LLRender) +include(LLWindow) +include(Linking) +include(PluginAPI) +include(MediaPluginBase) +include(OpenGL) +include(GLIB) + +include(GStreamer10Plugin) + +include_directories( + ${LLPLUGIN_INCLUDE_DIRS} + ${MEDIA_PLUGIN_BASE_INCLUDE_DIRS} + ${LLCOMMON_INCLUDE_DIRS} + ${LLMATH_INCLUDE_DIRS} + ${LLIMAGE_INCLUDE_DIRS} + ${LLRENDER_INCLUDE_DIRS} + ${LLWINDOW_INCLUDE_DIRS} + ${GSTREAMER10_INCLUDE_DIRS} + ${GSTREAMER10_PLUGINS_BASE_INCLUDE_DIRS} +) +include_directories(SYSTEM + ${LLCOMMON_SYSTEM_INCLUDE_DIRS} + ) + +### media_plugin_gstreamer10 + +if(NOT WORD_SIZE EQUAL 32) + if(NOT WINDOWS) # not windows therefore gcc LINUX and DARWIN + add_definitions(-fPIC) + endif() +endif(NOT WORD_SIZE EQUAL 32) + +set(media_plugin_gstreamer10_SOURCE_FILES + media_plugin_gstreamer10.cpp + llmediaimplgstreamer_syms.cpp + ) + +set(media_plugin_gstreamer10_HEADER_FILES + llmediaimplgstreamer_syms.h + llmediaimplgstreamertriviallogging.h + ) + +add_library(media_plugin_gstreamer10 + SHARED + ${media_plugin_gstreamer10_SOURCE_FILES} +) + +target_link_libraries(media_plugin_gstreamer10 + ${LLPLUGIN_LIBRARIES} + ${MEDIA_PLUGIN_BASE_LIBRARIES} + ${LLCOMMON_LIBRARIES} + ${PLUGIN_API_WINDOWS_LIBRARIES} + ${GSTREAMER10_LIBRARIES} +) + +#add_dependencies(media_plugin_gstreamer10 +# ${LLPLUGIN_LIBRARIES} +# ${MEDIA_PLUGIN_BASE_LIBRARIES} +# ${LLCOMMON_LIBRARIES} +#) + +if (WINDOWS) + set_target_properties( + media_plugin_gstreamer10 + PROPERTIES + LINK_FLAGS "/MANIFEST:NO /SAFESEH:NO /NODEFAULTLIB:LIBCMT" + ) +endif (WINDOWS) diff --git a/indra/media_plugins/gstreamer10/llmediaimplgstreamer.h b/indra/media_plugins/gstreamer10/llmediaimplgstreamer.h new file mode 100644 index 0000000000..6bc272c009 --- /dev/null +++ b/indra/media_plugins/gstreamer10/llmediaimplgstreamer.h @@ -0,0 +1,53 @@ +/** + * @file llmediaimplgstreamer.h + * @author Tofu Linden + * @brief implementation that supports media playback via GStreamer. + * + * @cond + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, 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$ + * @endcond + */ + +// header guard +#ifndef llmediaimplgstreamer_h +#define llmediaimplgstreamer_h + +#if LL_GSTREAMER010_ENABLED + +extern "C" { +#include +#include + +#include "apr_pools.h" +#include "apr_dso.h" +} + + +extern "C" { +gboolean llmediaimplgstreamer_bus_callback (GstBus *bus, + GstMessage *message, + gpointer data); +} + +#endif // LL_GSTREAMER010_ENABLED + +#endif // llmediaimplgstreamer_h diff --git a/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms.cpp b/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms.cpp new file mode 100644 index 0000000000..e5e5c1c9a3 --- /dev/null +++ b/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms.cpp @@ -0,0 +1,197 @@ +/** + * @file llmediaimplgstreamer_syms.cpp + * @brief dynamic GStreamer symbol-grabbing code + * + * @cond + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, 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$ + * @endcond + */ + +#include +#include +#include + +#ifdef LL_WINDOWS +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0502 +#include +#endif + +#include "linden_common.h" + +extern "C" { +#include +#include +} + +#include "apr_pools.h" +#include "apr_dso.h" + +#ifdef LL_WINDOWS + +#ifndef _M_AMD64 +#define GSTREAMER_REG_KEY "Software\\GStreamer1.0\\x86" +#define GSTREAMER_DIR_SUFFIX "1.0\\x86\\bin\\" +#else +#define GSTREAMER_REG_KEY "Software\\GStreamer1.0\\x86_64" +#define GSTREAMER_DIR_SUFFIX "1.0\\x86_64\\bin\\" +#endif + +bool openRegKey( HKEY &aKey ) +{ + // Try native (32 bit view/64 bit view) of registry first. + if( ERROR_SUCCESS == ::RegOpenKeyExA( HKEY_LOCAL_MACHINE, GSTREAMER_REG_KEY, 0, KEY_QUERY_VALUE, &aKey ) ) + return true; + + // If native view fails, use 32 bit view or registry. + if( ERROR_SUCCESS == ::RegOpenKeyExA( HKEY_LOCAL_MACHINE, GSTREAMER_REG_KEY, 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &aKey ) ) + return true; + + return false; +} + +std::string getGStreamerDir() +{ + std::string ret; + HKEY hKey; + + if( openRegKey( hKey ) ) + { + DWORD dwLen(0); + ::RegQueryValueExA( hKey, "InstallDir", nullptr, nullptr, nullptr, &dwLen ); + + if( dwLen > 0 ) + { + std::vector< char > vctBuffer; + vctBuffer.resize( dwLen ); + ::RegQueryValueExA( hKey, "InstallDir", nullptr, nullptr, reinterpret_cast< LPBYTE>(&vctBuffer[ 0 ]), &dwLen ); + ret = &vctBuffer[0]; + + if( ret[ dwLen-1 ] != '\\' ) + ret += "\\"; + ret += GSTREAMER_DIR_SUFFIX; + + SetDllDirectoryA( ret.c_str() ); + } + ::RegCloseKey( hKey ); + } + return ret; +} +#else +std::string getGStreamerDir() { return ""; } +#endif + +#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) RTN (*ll##GSTSYM)(__VA_ARGS__) = NULL; +#include "llmediaimplgstreamer_syms_raw.inc" +#undef LL_GST_SYM + +struct Symloader +{ + bool mRequired; + char const *mName; + apr_dso_handle_sym_t *mPPFunc; +}; + +#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) { REQ, #GSTSYM , (apr_dso_handle_sym_t*)&ll##GSTSYM}, +Symloader sSyms[] = { +#include "llmediaimplgstreamer_syms_raw.inc" +{ false, 0, 0 } }; +#undef LL_GST_SYM + +// a couple of stubs for disgusting reasons +GstDebugCategory* +ll_gst_debug_category_new(gchar *name, guint color, gchar *description) +{ + static GstDebugCategory dummy; + return &dummy; +} +void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname) +{ +} + +static bool sSymsGrabbed = false; +static apr_pool_t *sSymGSTDSOMemoryPool = NULL; + +std::vector< apr_dso_handle_t* > sLoadedLibraries; + +bool grab_gst_syms( std::vector< std::string > const &aDSONames ) +{ + if (sSymsGrabbed) + return true; + + //attempt to load the shared libraries + apr_pool_create(&sSymGSTDSOMemoryPool, NULL); + + for( std::vector< std::string >::const_iterator itr = aDSONames.begin(); itr != aDSONames.end(); ++itr ) + { + apr_dso_handle_t *pDSO(NULL); + std::string strDSO = getGStreamerDir() + *itr; + if( APR_SUCCESS == apr_dso_load( &pDSO, strDSO.c_str(), sSymGSTDSOMemoryPool )) + sLoadedLibraries.push_back( pDSO ); + + for( int i = 0; sSyms[ i ].mName; ++i ) + { + if( !*sSyms[ i ].mPPFunc ) + { + apr_dso_sym( sSyms[ i ].mPPFunc, pDSO, sSyms[ i ].mName ); + } + } + } + + std::stringstream strm; + bool sym_error = false; + for( int i = 0; sSyms[ i ].mName; ++i ) + { + if( sSyms[ i ].mRequired && ! *sSyms[ i ].mPPFunc ) + { + sym_error = true; + strm << sSyms[ i ].mName << std::endl; + } + } + + sSymsGrabbed = !sym_error; + return sSymsGrabbed; +} + + +void ungrab_gst_syms() +{ + // should be safe to call regardless of whether we've + // actually grabbed syms. + + for( std::vector< apr_dso_handle_t* >::iterator itr = sLoadedLibraries.begin(); itr != sLoadedLibraries.end(); ++itr ) + apr_dso_unload( *itr ); + + sLoadedLibraries.clear(); + + if ( sSymGSTDSOMemoryPool ) + { + apr_pool_destroy(sSymGSTDSOMemoryPool); + sSymGSTDSOMemoryPool = NULL; + } + + for( int i = 0; sSyms[ i ].mName; ++i ) + *sSyms[ i ].mPPFunc = NULL; + + sSymsGrabbed = false; +} + diff --git a/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms.h b/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms.h new file mode 100644 index 0000000000..0874644ee6 --- /dev/null +++ b/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms.h @@ -0,0 +1,68 @@ +/** + * @file llmediaimplgstreamer_syms.h + * @brief dynamic GStreamer symbol-grabbing code + * + * @cond + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, 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$ + * @endcond + */ + +#include "linden_common.h" +#include +extern "C" { +#include +} + +bool grab_gst_syms( std::vector< std::string > const&); +void ungrab_gst_syms(); + +#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) extern RTN (*ll##GSTSYM)(__VA_ARGS__); +#include "llmediaimplgstreamer_syms_raw.inc" +#undef LL_GST_SYM + +// regrettable hacks to give us better runtime compatibility with older systems +#define llg_return_if_fail(COND) do{if (!(COND)) return;}while(0) +#define llg_return_val_if_fail(COND,V) do{if (!(COND)) return V;}while(0) + +// regrettable hacks because GStreamer was not designed for runtime loading +#undef GST_TYPE_MESSAGE +#define GST_TYPE_MESSAGE (llgst_message_get_type()) +#undef GST_TYPE_OBJECT +#define GST_TYPE_OBJECT (llgst_object_get_type()) +#undef GST_TYPE_PIPELINE +#define GST_TYPE_PIPELINE (llgst_pipeline_get_type()) +#undef GST_TYPE_ELEMENT +#define GST_TYPE_ELEMENT (llgst_element_get_type()) +#undef GST_TYPE_VIDEO_SINK +#define GST_TYPE_VIDEO_SINK (llgst_video_sink_get_type()) +// more regrettable hacks to stub-out these .h-exposed GStreamer internals +void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname); +#undef _gst_debug_register_funcptr +#define _gst_debug_register_funcptr ll_gst_debug_register_funcptr +GstDebugCategory* ll_gst_debug_category_new(gchar *name, guint color, gchar *description); +#undef _gst_debug_category_new +#define _gst_debug_category_new ll_gst_debug_category_new +#undef __gst_debug_enabled +#define __gst_debug_enabled (0) + +// more hacks +#define LLGST_MESSAGE_TYPE_NAME(M) (llgst_message_type_get_name(GST_MESSAGE_TYPE(M))) diff --git a/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms_raw.inc b/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms_raw.inc new file mode 100644 index 0000000000..da1aa8ec1d --- /dev/null +++ b/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms_raw.inc @@ -0,0 +1,68 @@ +LL_GST_SYM(true, gst_buffer_new, GstBuffer*, void) +LL_GST_SYM(true, gst_structure_set_value, void, GstStructure *, const gchar *, const GValue*) +LL_GST_SYM(true, gst_init_check, gboolean, int *argc, char **argv[], GError ** err) +LL_GST_SYM(true, gst_message_get_type, GType, void) +LL_GST_SYM(true, gst_message_type_get_name, const gchar*, GstMessageType type) +LL_GST_SYM(true, gst_message_parse_error, void, GstMessage *message, GError **gerror, gchar **debug) +LL_GST_SYM(true, gst_message_parse_warning, void, GstMessage *message, GError **gerror, gchar **debug) +LL_GST_SYM(true, gst_message_parse_state_changed, void, GstMessage *message, GstState *oldstate, GstState *newstate, GstState *pending) +LL_GST_SYM(true, gst_element_set_state, GstStateChangeReturn, GstElement *element, GstState state) +LL_GST_SYM(true, gst_object_unref, void, gpointer object) +LL_GST_SYM(true, gst_object_get_type, GType, void) +LL_GST_SYM(true, gst_pipeline_get_type, GType, void) +LL_GST_SYM(true, gst_pipeline_get_bus, GstBus*, GstPipeline *pipeline) +LL_GST_SYM(true, gst_bus_add_watch, guint, GstBus * bus, GstBusFunc func, gpointer user_data) +LL_GST_SYM(true, gst_element_factory_make, GstElement*, const gchar *factoryname, const gchar *name) +LL_GST_SYM(true, gst_element_get_type, GType, void) +LL_GST_SYM(true, gst_static_pad_template_get, GstPadTemplate*, GstStaticPadTemplate *pad_template) +LL_GST_SYM(true, gst_element_class_add_pad_template, void, GstElementClass *klass, GstPadTemplate *temp) +LL_GST_SYM(true, gst_caps_from_string, GstCaps *, const gchar *string) +LL_GST_SYM(true, gst_caps_get_structure, GstStructure *, const GstCaps *caps, guint index) +LL_GST_SYM(true, gst_element_register, gboolean, GstPlugin *plugin, const gchar *name, guint rank, GType type) +LL_GST_SYM(true, gst_structure_get_int, gboolean, const GstStructure *structure, const gchar *fieldname, gint *value) +LL_GST_SYM(true, gst_structure_get_value, G_CONST_RETURN GValue *, const GstStructure *structure, const gchar *fieldname) +LL_GST_SYM(true, gst_value_get_fraction_numerator, gint, const GValue *value) +LL_GST_SYM(true, gst_value_get_fraction_denominator, gint, const GValue *value) +LL_GST_SYM(true, gst_structure_get_name, G_CONST_RETURN gchar *, const GstStructure *structure) +LL_GST_SYM(true, gst_element_seek, bool, GstElement *, gdouble, GstFormat, GstSeekFlags, GstSeekType, gint64, GstSeekType, gint64) + +LL_GST_SYM(false, gst_registry_fork_set_enabled, void, gboolean enabled) +LL_GST_SYM(false, gst_segtrap_set_enabled, void, gboolean enabled) +LL_GST_SYM(false, gst_message_parse_buffering, void, GstMessage *message, gint *percent) +LL_GST_SYM(false, gst_message_parse_info, void, GstMessage *message, GError **gerror, gchar **debug) +LL_GST_SYM(false, gst_element_query_position, gboolean, GstElement *element, GstFormat *format, gint64 *cur) +LL_GST_SYM(false, gst_version, void, guint *major, guint *minor, guint *micro, guint *nano) + +LL_GST_SYM( true, gst_message_parse_tag, void, GstMessage *, GstTagList **) +LL_GST_SYM( true, gst_tag_list_foreach, void, const GstTagList *, GstTagForeachFunc, gpointer) +LL_GST_SYM( true, gst_tag_list_get_tag_size, guint, const GstTagList *, const gchar *) +LL_GST_SYM( true, gst_tag_list_get_value_index, const GValue *, const GstTagList *, const gchar *, guint) + +LL_GST_SYM( true, gst_caps_new_simple, GstCaps*, const char *, const char*, ... ) + +LL_GST_SYM( true, gst_sample_get_caps, GstCaps*, GstSample* ) +LL_GST_SYM( true, gst_sample_get_buffer, GstBuffer*, GstSample* ) +LL_GST_SYM( true, gst_buffer_map, gboolean, GstBuffer*, GstMapInfo*, GstMapFlags ) +LL_GST_SYM( true, gst_buffer_unmap, void, GstBuffer*, GstMapInfo* ) + +LL_GST_SYM( true, gst_app_sink_set_caps, void, GstAppSink*, GstCaps const* ) +LL_GST_SYM( true, gst_app_sink_pull_sample, GstSample*, GstAppSink* ) + +LL_GST_SYM( true, g_free, void, gpointer ) +LL_GST_SYM( true, g_error_free, void, GError* ) + +LL_GST_SYM( true, g_main_context_pending, gboolean, GMainContext* ) +LL_GST_SYM( true, g_main_loop_get_context, GMainContext*, GMainLoop* ) +LL_GST_SYM( true, g_main_context_iteration, gboolean, GMainContext*, gboolean ) +LL_GST_SYM( true, g_main_loop_new, GMainLoop*, GMainContext*, gboolean ) +LL_GST_SYM( true, g_main_loop_quit, void, GMainLoop* ) +LL_GST_SYM( true, gst_mini_object_unref, void, GstMiniObject* ) +LL_GST_SYM( true, g_object_set, void, gpointer, gchar const*, ... ) +LL_GST_SYM( true, g_source_remove, gboolean, guint ) +LL_GST_SYM( true, g_value_get_string, gchar const*, GValue const* ) + + +LL_GST_SYM( true, gst_debug_set_active, void, gboolean ) +LL_GST_SYM( true, gst_debug_add_log_function, void, GstLogFunction, gpointer, GDestroyNotify ) +LL_GST_SYM( true, gst_debug_set_default_threshold, void, GstDebugLevel ) +LL_GST_SYM( true, gst_debug_message_get , gchar const*, GstDebugMessage * ) \ No newline at end of file diff --git a/indra/media_plugins/gstreamer10/media_plugin_gstreamer10.cpp b/indra/media_plugins/gstreamer10/media_plugin_gstreamer10.cpp new file mode 100644 index 0000000000..5c931ea8f0 --- /dev/null +++ b/indra/media_plugins/gstreamer10/media_plugin_gstreamer10.cpp @@ -0,0 +1,980 @@ +/** + * @file media_plugin_gstreamer10.cpp + * @brief GStreamer-1.0 plugin for LLMedia API plugin system + * + * @cond + * $LicenseInfo:firstyear=2016&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2016, Linden Research, Inc. / Nicky Dasmijn + * + * 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$ + * @endcond + */ + +#define FLIP_Y + +#include "linden_common.h" + +#include "llgl.h" + +#include "llplugininstance.h" +#include "llpluginmessage.h" +#include "llpluginmessageclasses.h" +#include "media_plugin_base.h" + +#define G_DISABLE_CAST_CHECKS +extern "C" { +#include +#include + +} + +#include "llmediaimplgstreamer.h" +#include "llmediaimplgstreamer_syms.h" + +static inline void llgst_caps_unref( GstCaps * caps ) +{ + llgst_mini_object_unref( GST_MINI_OBJECT_CAST( caps ) ); +} + +static inline void llgst_sample_unref( GstSample *aSample ) +{ + llgst_mini_object_unref( GST_MINI_OBJECT_CAST( aSample ) ); +} + +////////////////////////////////////////////////////////////////////////////// +// +class MediaPluginGStreamer10 : public MediaPluginBase +{ +public: + MediaPluginGStreamer10(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + ~MediaPluginGStreamer10(); + + /* virtual */ void receiveMessage(const char *message_string); + + static bool startup(); + static bool closedown(); + + gboolean processGSTEvents(GstBus *bus, GstMessage *message); + +private: + std::string getVersion(); + bool navigateTo( const std::string urlIn ); + bool seek( double time_sec ); + bool setVolume( float volume ); + + // misc + bool pause(); + bool stop(); + bool play(double rate); + bool getTimePos(double &sec_out); + + double MIN_LOOP_SEC = 1.0F; + U32 INTERNAL_TEXTURE_SIZE = 1024; + + bool mIsLooping; + + enum ECommand { + COMMAND_NONE, + COMMAND_STOP, + COMMAND_PLAY, + COMMAND_FAST_FORWARD, + COMMAND_FAST_REWIND, + COMMAND_PAUSE, + COMMAND_SEEK, + }; + ECommand mCommand; + +private: + bool unload(); + bool load(); + + bool update(int milliseconds); + void mouseDown( int x, int y ); + void mouseUp( int x, int y ); + void mouseMove( int x, int y ); + + static bool mDoneInit; + + guint mBusWatchID; + + float mVolume; + + int mDepth; + + // padded texture size we need to write into + int mTextureWidth; + int mTextureHeight; + + bool mSeekWanted; + double mSeekDestination; + + // Very GStreamer-specific + GMainLoop *mPump; // event pump for this media + GstElement *mPlaybin; + GstAppSink *mAppSink; +}; + +//static +bool MediaPluginGStreamer10::mDoneInit = false; + +MediaPluginGStreamer10::MediaPluginGStreamer10( LLPluginInstance::sendMessageFunction host_send_func, + void *host_user_data ) + : MediaPluginBase(host_send_func, host_user_data) + , mBusWatchID ( 0 ) + , mSeekWanted(false) + , mSeekDestination(0.0) + , mPump ( NULL ) + , mPlaybin ( NULL ) + , mAppSink ( NULL ) + , mCommand ( COMMAND_NONE ) +{ +} + +gboolean MediaPluginGStreamer10::processGSTEvents(GstBus *bus, GstMessage *message) +{ + if (!message) + return TRUE; // shield against GStreamer bug + + switch (GST_MESSAGE_TYPE (message)) + { + case GST_MESSAGE_BUFFERING: + { + // NEEDS GST 0.10.11+ + if (llgst_message_parse_buffering) + { + gint percent = 0; + llgst_message_parse_buffering(message, &percent); + } + break; + } + case GST_MESSAGE_STATE_CHANGED: + { + GstState old_state; + GstState new_state; + GstState pending_state; + llgst_message_parse_state_changed(message, + &old_state, + &new_state, + &pending_state); + + switch (new_state) + { + case GST_STATE_VOID_PENDING: + break; + case GST_STATE_NULL: + break; + case GST_STATE_READY: + setStatus(STATUS_LOADED); + break; + case GST_STATE_PAUSED: + setStatus(STATUS_PAUSED); + break; + case GST_STATE_PLAYING: + setStatus(STATUS_PLAYING); + break; + } + break; + } + case GST_MESSAGE_ERROR: + { + GError *err = NULL; + gchar *debug = NULL; + + llgst_message_parse_error (message, &err, &debug); + if (err) + llg_error_free (err); + llg_free (debug); + + mCommand = COMMAND_STOP; + + setStatus(STATUS_ERROR); + + break; + } + case GST_MESSAGE_INFO: + { + if (llgst_message_parse_info) + { + GError *err = NULL; + gchar *debug = NULL; + + llgst_message_parse_info (message, &err, &debug); + if (err) + llg_error_free (err); + llg_free (debug); + } + break; + } + case GST_MESSAGE_WARNING: + { + GError *err = NULL; + gchar *debug = NULL; + + llgst_message_parse_warning (message, &err, &debug); + if (err) + llg_error_free (err); + llg_free (debug); + + break; + } + case GST_MESSAGE_EOS: + /* end-of-stream */ + if (mIsLooping) + { + double eos_pos_sec = 0.0F; + bool got_eos_position = getTimePos(eos_pos_sec); + + if (got_eos_position && eos_pos_sec < MIN_LOOP_SEC) + { + // if we know that the movie is really short, don't + // loop it else it can easily become a time-hog + // because of GStreamer spin-up overhead + // inject a COMMAND_PAUSE + mCommand = COMMAND_PAUSE; + } + else + { + stop(); + play(1.0); + } + } + else // not a looping media + { + // inject a COMMAND_STOP + mCommand = COMMAND_STOP; + } + break; + default: + /* unhandled message */ + break; + } + + /* we want to be notified again the next time there is a message + * on the bus, so return true (false means we want to stop watching + * for messages on the bus and our callback should not be called again) + */ + return TRUE; +} + +extern "C" { + gboolean llmediaimplgstreamer_bus_callback (GstBus *bus, + GstMessage *message, + gpointer data) + { + MediaPluginGStreamer10 *impl = (MediaPluginGStreamer10*)data; + return impl->processGSTEvents(bus, message); + } +} // extern "C" + + + +bool MediaPluginGStreamer10::navigateTo ( const std::string urlIn ) +{ + if (!mDoneInit) + return false; // error + + setStatus(STATUS_LOADING); + + mSeekWanted = false; + + if (NULL == mPump || NULL == mPlaybin) + { + setStatus(STATUS_ERROR); + return false; // error + } + + llg_object_set (G_OBJECT (mPlaybin), "uri", urlIn.c_str(), NULL); + + // navigateTo implicitly plays, too. + play(1.0); + + return true; +} + + +class GstSampleUnref +{ + GstSample *mT; +public: + GstSampleUnref( GstSample *aT ) + : mT( aT ) + { llassert_always( mT ); } + + ~GstSampleUnref( ) + { llgst_sample_unref( mT ); } +}; + +bool MediaPluginGStreamer10::update(int milliseconds) +{ + if (!mDoneInit) + return false; // error + + // DEBUGMSG("updating media..."); + + // sanity check + if (NULL == mPump || NULL == mPlaybin) + { + return false; + } + + // see if there's an outstanding seek wanted + if (mSeekWanted && + // bleh, GST has to be happy that the movie is really truly playing + // or it may quietly ignore the seek (with rtsp:// at least). + (GST_STATE(mPlaybin) == GST_STATE_PLAYING)) + { + seek(mSeekDestination); + mSeekWanted = false; + } + + // *TODO: time-limit - but there isn't a lot we can do here, most + // time is spent in gstreamer's own opaque worker-threads. maybe + // we can do something sneaky like only unlock the video object + // for 'milliseconds' and otherwise hold the lock. + while (llg_main_context_pending(llg_main_loop_get_context(mPump))) + { + llg_main_context_iteration(llg_main_loop_get_context(mPump), FALSE); + } + + // check for availability of a new frame + + if( !mAppSink ) + return true; + + if( GST_STATE(mPlaybin) != GST_STATE_PLAYING) // Do not try to pull a sample if not in playing state + return true; + + GstSample *pSample = llgst_app_sink_pull_sample( mAppSink ); + if(!pSample) + return false; // Done playing + + GstSampleUnref oSampleUnref( pSample ); + GstCaps *pCaps = llgst_sample_get_caps ( pSample ); + if (!pCaps) + return false; + + gint width, height; + GstStructure *pStruct = llgst_caps_get_structure ( pCaps, 0); + + int res = llgst_structure_get_int ( pStruct, "width", &width); + res |= llgst_structure_get_int ( pStruct, "height", &height); + + if( !mPixels ) + return true; + + GstBuffer *pBuffer = llgst_sample_get_buffer ( pSample ); + GstMapInfo map; + llgst_buffer_map ( pBuffer, &map, GST_MAP_READ); + + // Our render buffer is always 1kx1k + + U32 rowSkip = INTERNAL_TEXTURE_SIZE / mTextureHeight; + U32 colSkip = INTERNAL_TEXTURE_SIZE / mTextureWidth; + + for (int row = 0; row < mTextureHeight; ++row) + { + U8 const *pTexelIn = map.data + (row*rowSkip * width *3); +#ifndef FLIP_Y + U8 *pTexelOut = mPixels + (row * mTextureWidth * mDepth ); +#else + U8 *pTexelOut = mPixels + ((mTextureHeight-row-1) * mTextureWidth * mDepth ); +#endif + for( int col = 0; col < mTextureWidth; ++col ) + { + pTexelOut[ 0 ] = pTexelIn[0]; + pTexelOut[ 1 ] = pTexelIn[1]; + pTexelOut[ 2 ] = pTexelIn[2]; + pTexelOut += mDepth; + pTexelIn += colSkip*3; + } + } + + llgst_buffer_unmap( pBuffer, &map ); + setDirty(0,0,mTextureWidth,mTextureHeight); + + return true; +} + +void MediaPluginGStreamer10::mouseDown( int x, int y ) +{ + // do nothing +} + +void MediaPluginGStreamer10::mouseUp( int x, int y ) +{ + // do nothing +} + +void MediaPluginGStreamer10::mouseMove( int x, int y ) +{ + // do nothing +} + + +bool MediaPluginGStreamer10::pause() +{ + // todo: error-check this? + if (mDoneInit && mPlaybin) + { + llgst_element_set_state(mPlaybin, GST_STATE_PAUSED); + return true; + } + return false; +} + +bool MediaPluginGStreamer10::stop() +{ + // todo: error-check this? + if (mDoneInit && mPlaybin) + { + llgst_element_set_state(mPlaybin, GST_STATE_READY); + return true; + } + return false; +} + +bool MediaPluginGStreamer10::play(double rate) +{ + // NOTE: we don't actually support non-natural rate. + + // todo: error-check this? + if (mDoneInit && mPlaybin) + { + llgst_element_set_state(mPlaybin, GST_STATE_PLAYING); + return true; + } + return false; +} + +bool MediaPluginGStreamer10::setVolume( float volume ) +{ + // we try to only update volume as conservatively as + // possible, as many gst-plugins-base versions up to at least + // November 2008 have critical race-conditions in setting volume - sigh + if (mVolume == volume) + return true; // nothing to do, everything's fine + + mVolume = volume; + if (mDoneInit && mPlaybin) + { + llg_object_set(mPlaybin, "volume", mVolume, NULL); + return true; + } + + return false; +} + +bool MediaPluginGStreamer10::seek(double time_sec) +{ + bool success = false; + if (mDoneInit && mPlaybin) + { + success = llgst_element_seek(mPlaybin, 1.0F, GST_FORMAT_TIME, + GstSeekFlags(GST_SEEK_FLAG_FLUSH | + GST_SEEK_FLAG_KEY_UNIT), + GST_SEEK_TYPE_SET, gint64(time_sec*GST_SECOND), + GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); + } + return success; +} + +bool MediaPluginGStreamer10::getTimePos(double &sec_out) +{ + bool got_position = false; + if (mDoneInit && mPlaybin) + { + gint64 pos(0); + GstFormat timefmt = GST_FORMAT_TIME; + got_position = + llgst_element_query_position && + llgst_element_query_position(mPlaybin, + &timefmt, + &pos); + got_position = got_position + && (timefmt == GST_FORMAT_TIME); + // GStreamer may have other ideas, but we consider the current position + // undefined if not PLAYING or PAUSED + got_position = got_position && + (GST_STATE(mPlaybin) == GST_STATE_PLAYING || + GST_STATE(mPlaybin) == GST_STATE_PAUSED); + if (got_position && !GST_CLOCK_TIME_IS_VALID(pos)) + { + if (GST_STATE(mPlaybin) == GST_STATE_PLAYING) + { + // if we're playing then we treat an invalid clock time + // as 0, for complicated reasons (insert reason here) + pos = 0; + } + else + { + got_position = false; + } + + } + // If all the preconditions succeeded... we can trust the result. + if (got_position) + { + sec_out = double(pos) / double(GST_SECOND); // gst to sec + } + } + return got_position; +} + +bool MediaPluginGStreamer10::load() +{ + if (!mDoneInit) + return false; // error + + setStatus(STATUS_LOADING); + + mIsLooping = false; + mVolume = 0.1234567f; // minor hack to force an initial volume update + + // Create a pumpable main-loop for this media + mPump = llg_main_loop_new (NULL, FALSE); + if (!mPump) + { + setStatus(STATUS_ERROR); + return false; // error + } + + // instantiate a playbin element to do the hard work + mPlaybin = llgst_element_factory_make ("playbin", ""); + if (!mPlaybin) + { + setStatus(STATUS_ERROR); + return false; // error + } + + // get playbin's bus + GstBus *bus = llgst_pipeline_get_bus (GST_PIPELINE (mPlaybin)); + if (!bus) + { + setStatus(STATUS_ERROR); + return false; // error + } + mBusWatchID = llgst_bus_add_watch (bus, + llmediaimplgstreamer_bus_callback, + this); + llgst_object_unref (bus); + + mAppSink = (GstAppSink*)(llgst_element_factory_make ("appsink", "")); + + GstCaps* pCaps = llgst_caps_new_simple( "video/x-raw", + "format", G_TYPE_STRING, "RGB", + "width", G_TYPE_INT, INTERNAL_TEXTURE_SIZE, + "height", G_TYPE_INT, INTERNAL_TEXTURE_SIZE, + NULL ); + + llgst_app_sink_set_caps( mAppSink, pCaps ); + llgst_caps_unref( pCaps ); + + if (!mAppSink) + { + setStatus(STATUS_ERROR); + return false; + } + + llg_object_set(mPlaybin, "video-sink", mAppSink, NULL); + + return true; +} + +bool MediaPluginGStreamer10::unload () +{ + if (!mDoneInit) + return false; // error + + // stop getting callbacks for this bus + llg_source_remove(mBusWatchID); + mBusWatchID = 0; + + if (mPlaybin) + { + llgst_element_set_state (mPlaybin, GST_STATE_NULL); + llgst_object_unref (GST_OBJECT (mPlaybin)); + mPlaybin = NULL; + } + + if (mPump) + { + llg_main_loop_quit(mPump); + mPump = NULL; + } + + mAppSink = NULL; + + setStatus(STATUS_NONE); + + return true; +} + +void LogFunction(GstDebugCategory *category, GstDebugLevel level, const gchar *file, const gchar *function, gint line, GObject *object, GstDebugMessage *message, gpointer user_data ) +#ifndef LL_LINUX // Docu says we need G_GNUC_NO_INSTRUMENT, but GCC says 'error' + G_GNUC_NO_INSTRUMENT +#endif +{ +#ifdef LL_LINUX + std::cerr << file << ":" << line << "(" << function << "): " << llgst_debug_message_get( message ) << std::endl; +#endif +} + +//static +bool MediaPluginGStreamer10::startup() +{ + // first - check if GStreamer is explicitly disabled + if (NULL != getenv("LL_DISABLE_GSTREAMER")) + return false; + + // only do global GStreamer initialization once. + if (!mDoneInit) + { + ll_init_apr(); + + // Get symbols! + std::vector< std::string > vctDSONames; +#if LL_DARWIN +#elif LL_WINDOWS + vctDSONames.push_back( "libgstreamer-1.0-0.dll" ); + vctDSONames.push_back( "libgstapp-1.0-0.dll" ); + vctDSONames.push_back( "libglib-2.0-0.dll" ); + vctDSONames.push_back( "libgobject-2.0-0.dll" ); +#else // linux or other ELFy unixoid + vctDSONames.push_back( "libgstreamer-1.0.so.0" ); + vctDSONames.push_back( "libgstapp-1.0.so.0" ); + vctDSONames.push_back( "libglib-2.0.so.0" ); + vctDSONames.push_back( "libgobject-2.0.so" ); +#endif + if( !grab_gst_syms( vctDSONames ) ) + { + return false; + } + + if (llgst_segtrap_set_enabled) + { + llgst_segtrap_set_enabled(FALSE); + } +#if LL_LINUX + // Gstreamer tries a fork during init, waitpid-ing on it, + // which conflicts with any installed SIGCHLD handler... + struct sigaction tmpact, oldact; + if (llgst_registry_fork_set_enabled ) { + // if we can disable SIGCHLD-using forking behaviour, + // do it. + llgst_registry_fork_set_enabled(false); + } + else { + // else temporarily install default SIGCHLD handler + // while GStreamer initialises + tmpact.sa_handler = SIG_DFL; + sigemptyset( &tmpact.sa_mask ); + tmpact.sa_flags = SA_SIGINFO; + sigaction(SIGCHLD, &tmpact, &oldact); + } +#endif // LL_LINUX + // Protect against GStreamer resetting the locale, yuck. + static std::string saved_locale; + saved_locale = setlocale(LC_ALL, NULL); + +// _putenv_s( "GST_PLUGIN_PATH", "E:\\gstreamer\\1.0\\x86\\lib\\gstreamer-1.0" ); + + llgst_debug_set_default_threshold( GST_LEVEL_WARNING ); + llgst_debug_add_log_function( LogFunction, NULL, NULL ); + llgst_debug_set_active( false ); + + // finally, try to initialize GStreamer! + GError *err = NULL; + gboolean init_gst_success = llgst_init_check(NULL, NULL, &err); + + // restore old locale + setlocale(LC_ALL, saved_locale.c_str() ); + +#if LL_LINUX + // restore old SIGCHLD handler + if (!llgst_registry_fork_set_enabled) + sigaction(SIGCHLD, &oldact, NULL); +#endif // LL_LINUX + + if (!init_gst_success) // fail + { + if (err) + { + llg_error_free(err); + } + return false; + } + + mDoneInit = true; + } + + return true; +} + +//static +bool MediaPluginGStreamer10::closedown() +{ + if (!mDoneInit) + return false; // error + + ungrab_gst_syms(); + + mDoneInit = false; + + return true; +} + +MediaPluginGStreamer10::~MediaPluginGStreamer10() +{ + closedown(); +} + + +std::string MediaPluginGStreamer10::getVersion() +{ + std::string plugin_version = "GStreamer10 media plugin, GStreamer version "; + if (mDoneInit && + llgst_version) + { + guint major, minor, micro, nano; + llgst_version(&major, &minor, µ, &nano); + plugin_version += llformat("%u.%u.%u.%u (runtime), %u.%u.%u.%u (headers)", (unsigned int)major, (unsigned int)minor, + (unsigned int)micro, (unsigned int)nano, (unsigned int)GST_VERSION_MAJOR, (unsigned int)GST_VERSION_MINOR, + (unsigned int)GST_VERSION_MICRO, (unsigned int)GST_VERSION_NANO); + } + else + { + plugin_version += "(unknown)"; + } + return plugin_version; +} + +void MediaPluginGStreamer10::receiveMessage(const char *message_string) +{ + LLPluginMessage message_in; + + if(message_in.parse(message_string) >= 0) + { + std::string message_class = message_in.getClass(); + std::string message_name = message_in.getName(); + + if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE) + { + if(message_name == "init") + { + LLPluginMessage message("base", "init_response"); + LLSD versions = LLSD::emptyMap(); + versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION; + message.setValueLLSD("versions", versions); + + load(); + + message.setValue("plugin_version", getVersion()); + sendMessage(message); + } + else if(message_name == "idle") + { + // no response is necessary here. + double time = message_in.getValueReal("time"); + + // Convert time to milliseconds for update() + update((int)(time * 1000.0f)); + } + else if(message_name == "cleanup") + { + unload(); + closedown(); + } + else if(message_name == "shm_added") + { + SharedSegmentInfo info; + info.mAddress = message_in.getValuePointer("address"); + info.mSize = (size_t)message_in.getValueS32("size"); + std::string name = message_in.getValue("name"); + + mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); + } + else if(message_name == "shm_remove") + { + std::string name = message_in.getValue("name"); + + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { + if(mPixels == iter->second.mAddress) + { + // This is the currently active pixel buffer. Make sure we stop drawing to it. + mPixels = NULL; + mTextureSegmentName.clear(); + } + mSharedSegments.erase(iter); + } + + // Send the response so it can be cleaned up. + LLPluginMessage message("base", "shm_remove_response"); + message.setValue("name", name); + sendMessage(message); + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) + { + if(message_name == "init") + { + // Plugin gets to decide the texture parameters to use. + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); + // lame to have to decide this now, it depends on the movie. Oh well. + mDepth = 4; + + mTextureWidth = 1; + mTextureHeight = 1; + + message.setValueU32("format", GL_RGBA); + message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8_REV); + + message.setValueS32("depth", mDepth); + message.setValueS32("default_width", INTERNAL_TEXTURE_SIZE ); + message.setValueS32("default_height", INTERNAL_TEXTURE_SIZE ); + message.setValueU32("internalformat", GL_RGBA8); + message.setValueBoolean("coords_opengl", true); // true == use OpenGL-style coordinates, false == (0,0) is upper left. + message.setValueBoolean("allow_downsample", true); // we respond with grace and performance if asked to downscale + sendMessage(message); + } + else if(message_name == "size_change") + { + std::string name = message_in.getValue("name"); + S32 width = message_in.getValueS32("width"); + S32 height = message_in.getValueS32("height"); + S32 texture_width = message_in.getValueS32("texture_width"); + S32 texture_height = message_in.getValueS32("texture_height"); + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); + message.setValue("name", name); + message.setValueS32("width", width); + message.setValueS32("height", height); + message.setValueS32("texture_width", texture_width); + message.setValueS32("texture_height", texture_height); + sendMessage(message); + + if(!name.empty()) + { + // Find the shared memory region with this name + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { + mPixels = (unsigned char*)iter->second.mAddress; + mTextureSegmentName = name; + + mTextureWidth = texture_width; + mTextureHeight = texture_height; + memset( mPixels, 0, mTextureWidth*mTextureHeight*mDepth ); + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_request"); + message.setValue("name", mTextureSegmentName); + message.setValueS32("width", INTERNAL_TEXTURE_SIZE ); + message.setValueS32("height", INTERNAL_TEXTURE_SIZE ); + sendMessage(message); + + } + } + else if(message_name == "load_uri") + { + std::string uri = message_in.getValue("uri"); + navigateTo( uri ); + sendStatus(); + } + else if(message_name == "mouse_event") + { + std::string event = message_in.getValue("event"); + S32 x = message_in.getValueS32("x"); + S32 y = message_in.getValueS32("y"); + + if(event == "down") + { + mouseDown(x, y); + } + else if(event == "up") + { + mouseUp(x, y); + } + else if(event == "move") + { + mouseMove(x, y); + }; + }; + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) + { + if(message_name == "stop") + { + stop(); + } + else if(message_name == "start") + { + double rate = 0.0; + if(message_in.hasValue("rate")) + { + rate = message_in.getValueReal("rate"); + } + // NOTE: we don't actually support rate. + play(rate); + } + else if(message_name == "pause") + { + pause(); + } + else if(message_name == "seek") + { + double time = message_in.getValueReal("time"); + // defer the actual seek in case we haven't + // really truly started yet in which case there + // is nothing to seek upon + mSeekWanted = true; + mSeekDestination = time; + } + else if(message_name == "set_loop") + { + bool loop = message_in.getValueBoolean("loop"); + mIsLooping = loop; + } + else if(message_name == "set_volume") + { + double volume = message_in.getValueReal("volume"); + setVolume(volume); + } + } + } +} + +int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ + if( MediaPluginGStreamer10::startup() ) + { + MediaPluginGStreamer10 *self = new MediaPluginGStreamer10(host_send_func, host_user_data); + *plugin_send_func = MediaPluginGStreamer10::staticReceiveMessage; + *plugin_user_data = (void*)self; + + return 0; // okay + } + else + { + return -1; // failed to init + } +} diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 762a5fa55f..37f79d7862 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1864,6 +1864,8 @@ if (WINDOWS) COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}" ) + set_source_files_properties( llappviewer.cpp llviewermenu.cpp PROPERTIES COMPILE_FLAGS /bigobj ) + list(APPEND viewer_HEADER_FILES llappviewerwin32.h llwindebug.h @@ -2565,26 +2567,30 @@ if (LINUX) set(product Firestorm-${ARCH}-${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}) # These are the generated targets that are copied to package/ -if (NOT ENABLE_MEDIA_PLUGINS) - set(COPY_INPUT_DEPENDENCIES - ${VIEWER_BINARY_NAME} - SLPlugin - media_plugin_cef - #media_plugin_gstreamer010 - media_plugin_libvlc - llcommon - ) -else (NOT ENABLE_MEDIA_PLUGINS) - set(COPY_INPUT_DEPENDENCIES - ${VIEWER_BINARY_NAME} - #linux-crash-logger - SLPlugin - media_plugin_cef - #media_plugin_gstreamer010 - llcommon - ) -endif (NOT ENABLE_MEDIA_PLUGINS) + if (NOT ENABLE_MEDIA_PLUGINS) + set(COPY_INPUT_DEPENDENCIES + ${VIEWER_BINARY_NAME} + SLPlugin + media_plugin_cef + media_plugin_gstreamer10 + #media_plugin_libvlc + llcommon + linux-crash-logger + ) + else (NOT ENABLE_MEDIA_PLUGINS) + set(COPY_INPUT_DEPENDENCIES + ${VIEWER_BINARY_NAME} + #linux-crash-logger + SLPlugin + media_plugin_cef + media_plugin_gstreamer10 + llcommon + linux-crash-logger + ) + endif (NOT ENABLE_MEDIA_PLUGINS) + add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_gstreamer10 media_plugin_cef linux-crash-logger) + add_custom_command( OUTPUT ${product}.tar.bz2 COMMAND ${PYTHON_EXECUTABLE} @@ -2610,7 +2616,6 @@ endif (NOT ENABLE_MEDIA_PLUGINS) ${COPY_INPUT_DEPENDENCIES} ) - add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.copy_touched COMMAND ${PYTHON_EXECUTABLE} @@ -2861,8 +2866,10 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE endif (LINUX) endif (USE_BUGSPLAT) - # for both Bugsplat and Breakpad - add_dependencies(llpackage generate_symbols) + if (NOT LINUX) #Linux generates symbols via viewer_manifest.py/fs_viewer_manifest.py + # for both Bugsplat and Breakpad + add_dependencies(llpackage generate_symbols) + endif() endif () if (LL_TESTS) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index f4114fca49..ca856c1aed 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -25946,6 +25946,17 @@ Change of this parameter will affect the layout of buttons in notification toast Type Boolean Value + 0 + + FSAutoTuneLock + + Comment + When enabled the viewer will dynamically change settings until auto tune is explicitly turned off. + Persist + 1 + Type + Boolean + Value 1 FSAllowSelfImpostor @@ -26025,6 +26036,17 @@ Change of this parameter will affect the layout of buttons in notification toast Value 0 + FSUserTargetReflections + + Comment + Set by auto tune floater on build + Persist + 0 + Type + S32 + Value + 4 + FSReportRegionRestartToChat Comment diff --git a/indra/newview/fs_viewer_manifest.py b/indra/newview/fs_viewer_manifest.py index 28467eb274..04d75e6c1d 100644 --- a/indra/newview/fs_viewer_manifest.py +++ b/indra/newview/fs_viewer_manifest.py @@ -198,17 +198,17 @@ class FSViewerManifest: from shutil import rmtree import tarfile - #if isdir( "symbols" ): - # rmtree( "symbols" ) + if isdir( "symbols" ): + rmtree( "symbols" ) - #files = glob( "%s/bin/*" % self.args['dest'] ) - #for f in files: - # self.fs_generate_breakpad_symbols_for_file( f ) - - #files = glob( "%s/lib/*.so" % self.args['dest'] ) - #for f in files: - # self.fs_generate_breakpad_symbols_for_file( f ) + files = glob( "%s/bin/*" % self.args['dest'] ) + for f in files: + self.fs_generate_breakpad_symbols_for_file( f ) + files = glob( "%s/lib/*.so" % self.args['dest'] ) + for f in files: + if f.find( "libcef.so" ) == -1: + self.fs_generate_breakpad_symbols_for_file( f ) if isdir( "symbols" ): for a in self.args: diff --git a/indra/newview/fsfloaterperformance.cpp b/indra/newview/fsfloaterperformance.cpp index 43401fe0b4..7e11d1dadc 100644 --- a/indra/newview/fsfloaterperformance.cpp +++ b/indra/newview/fsfloaterperformance.cpp @@ -51,8 +51,12 @@ #include "pipeline.h" #include "llviewercontrol.h" #include "fsavatarrenderpersistence.h" +#include "llpresetsmanager.h" #include "fsperfstats.h" // performance stats support #include "fslslbridge.h" +#include + +extern F32 gSavedDrawDistance; const F32 REFRESH_INTERVAL = 1.0f; const S32 BAR_LEFT_PAD = 2; @@ -119,8 +123,11 @@ BOOL FSFloaterPerformance::postBuild() auto tgt_panel = findChild("target_subpanel"); if (tgt_panel) { - tgt_panel->getChild("target_btn")->setCommitCallback(boost::bind(&FSFloaterPerformance::showSelectedPanel, this, mAutoTunePanel)); - tgt_panel->getChild("FSTuningFPSStrategy")->setCurrentByIndex(gSavedSettings.getU32("FSTuningFPSStrategy")); + tgt_panel->getChild("target_btn")->setCommitCallback(boost::bind(&FSFloaterPerformance::showSelectedPanel, this, mAutoTunePanel)); + tgt_panel->getChild("FSTuningFPSStrategy")->setCurrentByIndex(gSavedSettings.getU32("FSTuningFPSStrategy")); + tgt_panel->getChild("PrefSaveButton")->setCommitCallback(boost::bind(&FSFloaterPerformance::savePreset, this)); + tgt_panel->getChild("PrefLoadButton")->setCommitCallback(boost::bind(&FSFloaterPerformance::loadPreset, this)); + tgt_panel->getChild("Defaults")->setCommitCallback(boost::bind(&FSFloaterPerformance::setHardwareDefaults, this)); } initBackBtn(mNearbyPanel); @@ -146,6 +153,7 @@ BOOL FSFloaterPerformance::postBuild() mNearbyPanel->getChild("hide_avatars")->set(!LLPipeline::hasRenderTypeControl(LLPipeline::RENDER_TYPE_AVATAR)); mNearbyList = mNearbyPanel->getChild("nearby_list"); mNearbyList->setRightMouseDownCallback(boost::bind(&FSFloaterPerformance::onAvatarListRightClick, this, _1, _2, _3)); + updateComplexityText(); mComplexityChangedSignal = gSavedSettings.getControl("RenderAvatarMaxComplexity")->getCommitSignal()->connect(boost::bind(&FSFloaterPerformance::updateComplexityText, this)); @@ -155,10 +163,53 @@ BOOL FSFloaterPerformance::postBuild() mNearbyPanel->getChild("FSRenderAvatarMaxART")->setCommitCallback(boost::bind(&FSFloaterPerformance::updateMaxRenderTime, this)); LLAvatarComplexityControls::setIndirectMaxArc(); + // store the current setting as the users desired reflection detail and DD + gSavedSettings.setS32("FSUserTargetReflections", LLPipeline::RenderReflectionDetail); + if(!FSPerfStats::tunables.userAutoTuneEnabled) + { + if (gSavedDrawDistance) + { + gSavedSettings.setF32("FSAutoTuneRenderFarClipTarget", gSavedDrawDistance); + } + else + { + gSavedSettings.setF32("FSAutoTuneRenderFarClipTarget", LLPipeline::RenderFarClip); + } + } return TRUE; } +void FSFloaterPerformance::resetMaxArtSlider() +{ + FSPerfStats::renderAvatarMaxART_ns = 0; + FSPerfStats::tunables.updateSettingsFromRenderCostLimit(); + FSPerfStats::tunables.applyUpdates(); + updateMaxRenderTime(); +} + +void FSFloaterPerformance::savePreset() +{ + LLFloaterReg::showInstance("save_pref_preset", "graphic" ); +} + +void FSFloaterPerformance::loadPreset() +{ + LLFloaterReg::showInstance("load_pref_preset", "graphic"); + resetMaxArtSlider(); +} + +void FSFloaterPerformance::setHardwareDefaults() +{ + LLFeatureManager::getInstance()->applyRecommendedSettings(); + // reset indirects before refresh because we may have changed what they control + LLAvatarComplexityControls::setIndirectControls(); + gSavedSettings.setString("PresetGraphicActive", ""); + LLPresetsManager::getInstance()->triggerChangeSignal(); + resetMaxArtSlider(); +} + + void FSFloaterPerformance::showSelectedPanel(LLPanel* selected_panel) { hidePanels(); @@ -284,7 +335,7 @@ void FSFloaterPerformance::draw() textbox->setColor(LLUIColorTable::instance().getColor("DrYellow")); unreliable = true; } - else if (FSPerfStats::autoTune) + else if (FSPerfStats::tunables.userAutoTuneEnabled) { textbox->setVisible(true); textbox->setText(getString("tuning_fps", args)); @@ -295,7 +346,12 @@ void FSFloaterPerformance::draw() textbox->setVisible(false); } - if (FSPerfStats::autoTune && !unreliable ) + auto button = getChild("AutoTuneFPS"); + if((bool)button->getToggleState() != FSPerfStats::tunables.userAutoTuneEnabled) + { + button->toggleState(); + } + if (FSPerfStats::tunables.userAutoTuneEnabled && !unreliable ) { // the tuning itself is managed from another thread but we can report progress here diff --git a/indra/newview/fsfloaterperformance.h b/indra/newview/fsfloaterperformance.h index 034c772ae2..f60de2da84 100644 --- a/indra/newview/fsfloaterperformance.h +++ b/indra/newview/fsfloaterperformance.h @@ -55,6 +55,10 @@ public: void onCustomAction (const LLSD& userdata, const LLUUID& av_id); bool isActionChecked(const LLSD& userdata, const LLUUID& av_id); void onExtendedAction(const LLSD& userdata, const LLUUID& av_id); + void resetMaxArtSlider(); + void savePreset(); + void loadPreset(); + void setHardwareDefaults(); private: void initBackBtn(LLPanel* panel); diff --git a/indra/newview/fsperfstats.cpp b/indra/newview/fsperfstats.cpp index aeb8880927..1238bd786d 100644 --- a/indra/newview/fsperfstats.cpp +++ b/indra/newview/fsperfstats.cpp @@ -32,6 +32,7 @@ #include "llagentcamera.h" #include "llvoavatar.h" #include "llworld.h" +#include extern LLControlGroup gSavedSettings; @@ -47,11 +48,10 @@ namespace FSPerfStats #endif std::atomic tunedAvatars{0}; - U32 targetFPS; // desired FPS - U64 renderAvatarMaxART_ns{(U64)(ART_UNLIMITED_NANOS)}; // highest render time we'll allow without culling features + std::atomic renderAvatarMaxART_ns{(U64)(ART_UNLIMITED_NANOS)}; // highest render time we'll allow without culling features + bool belowTargetFPS{false}; U32 lastGlobalPrefChange{0}; std::mutex bufferToggleLock{}; - bool autoTune{false}; Tunables tunables; @@ -65,9 +65,69 @@ namespace FSPerfStats void Tunables::applyUpdates() { assert_main_thread(); - if( tuningFlag & NonImposters ){ gSavedSettings.setU32("IndirectMaxNonImpostors", nonImposters); }; + // these following variables are proxies for pipeline statics we do not need a two way update (no llviewercontrol handler) + if( tuningFlag & NonImpostors ){ gSavedSettings.setU32("IndirectMaxNonImpostors", nonImpostors); }; if( tuningFlag & ReflectionDetail ){ gSavedSettings.setS32("RenderReflectionDetail", reflectionDetail); }; if( tuningFlag & FarClip ){ gSavedSettings.setF32("RenderFarClip", farClip); }; + if( tuningFlag & UserMinDrawDistance ){ gSavedSettings.setF32("FSAutoTuneRenderFarClipMin", userMinDrawDistance); }; + if( tuningFlag & UserTargetDrawDistance ){ gSavedSettings.setF32("FSAutoTuneRenderFarClipTarget", userTargetDrawDistance); }; + if( tuningFlag & UserImpostorDistance ){ gSavedSettings.setF32("FSAutoTuneImpostorFarAwayDistance", userImpostorDistance); }; + if( tuningFlag & UserImpostorDistanceTuningEnabled ){ gSavedSettings.setBOOL("FSAutoTuneImpostorByDistEnabled", userImpostorDistanceTuningEnabled); }; + if( tuningFlag & UserFPSTuningStrategy ){ gSavedSettings.setU32("FSTuningFPSStrategy", userFPSTuningStrategy); }; + if( tuningFlag & UserAutoTuneEnabled ){ gSavedSettings.setBOOL("FSAutoTuneFPS", userAutoTuneEnabled); }; + if( tuningFlag & UserAutoTuneLock ){ gSavedSettings.setBOOL("FSAutoTuneLock", userAutoTuneLock); }; + if( tuningFlag & UserTargetFPS ){ gSavedSettings.setU32("FSTargetFPS", userTargetFPS); }; + if( tuningFlag & UserTargetReflections ){ gSavedSettings.setS32("FSUserTargetReflections", userTargetReflections); }; + // Note: The Max ART slider is logarithmic and thus we have an intermediate proxy value + if( tuningFlag & UserARTCutoff ){ gSavedSettings.setF32("FSRenderAvatarMaxART", userARTCutoffSliderValue); }; + resetChanges(); + } + + void Tunables::updateRenderCostLimitFromSettings() + { + assert_main_thread(); + const auto newval = gSavedSettings.getF32("FSRenderAvatarMaxART"); + if(newval < log10(FSPerfStats::ART_UNLIMITED_NANOS/1000)) + { + FSPerfStats::renderAvatarMaxART_ns = pow(10,newval)*1000; + } + else + { + FSPerfStats::renderAvatarMaxART_ns = 0; + }; + } + + // static + void Tunables::updateSettingsFromRenderCostLimit() + { + if( userARTCutoffSliderValue != log10( ( (F32)FSPerfStats::renderAvatarMaxART_ns )/1000 ) ) + { + if( FSPerfStats::renderAvatarMaxART_ns != 0 ) + { + updateUserARTCutoffSlider(log10( ( (F32)FSPerfStats::renderAvatarMaxART_ns )/1000 ) ); + } + else + { + updateUserARTCutoffSlider(log10( (F32)FSPerfStats::ART_UNLIMITED_NANOS/1000 ) ); + } + } + } + + void Tunables::initialiseFromSettings() + { + assert_main_thread(); + // the following variables are two way and have "push" in llviewercontrol + FSPerfStats::tunables.userMinDrawDistance = gSavedSettings.getF32("FSAutoTuneRenderFarClipMin"); + FSPerfStats::tunables.userTargetDrawDistance = gSavedSettings.getF32("FSAutoTuneRenderFarClipTarget"); + FSPerfStats::tunables.userImpostorDistance = gSavedSettings.getF32("FSAutoTuneImpostorFarAwayDistance"); + FSPerfStats::tunables.userImpostorDistanceTuningEnabled = gSavedSettings.getBOOL("FSAutoTuneImpostorByDistEnabled"); + FSPerfStats::tunables.userFPSTuningStrategy = gSavedSettings.getU32("FSTuningFPSStrategy"); + FSPerfStats::tunables.userTargetFPS = gSavedSettings.getU32("FSTargetFPS"); + FSPerfStats::tunables.userTargetReflections = gSavedSettings.getU32("FSUserTargetReflections"); + FSPerfStats::tunables.userAutoTuneEnabled = gSavedSettings.getBOOL("FSAutoTuneFPS"); + FSPerfStats::tunables.userAutoTuneLock = gSavedSettings.getBOOL("FSAutoTuneLock"); + // Note: The Max ART slider is logarithmic and thus we have an intermediate proxy value + updateRenderCostLimitFromSettings(); resetChanges(); } @@ -75,12 +135,7 @@ namespace FSPerfStats { // create a queue // create a thread to consume from the queue - - FSPerfStats::targetFPS = gSavedSettings.getU32("FSTargetFPS"); - FSPerfStats::autoTune = gSavedSettings.getBOOL("FSAutoTuneFPS"); - - updateRenderCostLimitFromSettings(); - + tunables.initialiseFromSettings(); t.detach(); } @@ -91,8 +146,7 @@ namespace FSPerfStats using ST = StatType_t; bool unreliable{false}; - static LLCachedControl smoothingPeriods(gSavedSettings, "FSPerfFloaterSmoothingPeriods"); - + FSPerfStats::StatsRecorder::getSceneStat(FSPerfStats::StatType_t::RENDER_FRAME); auto& sceneStats = statsDoubleBuffer[writeBuffer][static_cast(ObjType_t::OT_GENERAL)][LLUUID::null]; auto& lastStats = statsDoubleBuffer[writeBuffer ^ 1][static_cast(ObjType_t::OT_GENERAL)][LLUUID::null]; @@ -129,7 +183,7 @@ namespace FSPerfStats { auto avg = lastStats[static_cast(statEntry)]; auto val = sceneStats[static_cast(statEntry)]; - sceneStats[static_cast(statEntry)] = avg + (val/smoothingPeriods) - (avg/smoothingPeriods); + sceneStats[static_cast(statEntry)] = avg + (val / SMOOTHING_PERIODS) - (avg / SMOOTHING_PERIODS); // LL_INFOS("scenestats") << "Scenestat: " << static_cast(statEntry) << " before=" << avg << " new=" << val << " newavg=" << statsDoubleBuffer[writeBuffer][static_cast(ObjType_t::OT_GENERAL)][LLUUID::null][static_cast(statEntry)] << LL_ENDL; } @@ -137,9 +191,9 @@ namespace FSPerfStats for(auto& stat_entry : statsMap) { auto val = stat_entry.second[static_cast(ST::RENDER_COMBINED)]; - if(val>smoothingPeriods){ + if(val > SMOOTHING_PERIODS){ auto avg = statsDoubleBuffer[writeBuffer ^ 1][static_cast(ObjType_t::OT_ATTACHMENT)][stat_entry.first][static_cast(ST::RENDER_COMBINED)]; - stat_entry.second[static_cast(ST::RENDER_COMBINED)] = avg + (val/smoothingPeriods) - (avg/smoothingPeriods); + stat_entry.second[static_cast(ST::RENDER_COMBINED)] = avg + (val / SMOOTHING_PERIODS) - (avg / SMOOTHING_PERIODS); } } @@ -150,10 +204,10 @@ namespace FSPerfStats for(auto& stat : avatarStatsToAvg) { auto val = stat_entry.second[static_cast(stat)]; - if(val>smoothingPeriods) + if(val > SMOOTHING_PERIODS) { auto avg = statsDoubleBuffer[writeBuffer ^ 1][static_cast(ObjType_t::OT_AVATAR)][stat_entry.first][static_cast(stat)]; - stat_entry.second[static_cast(stat)] = avg + (val/smoothingPeriods) - (avg/smoothingPeriods); + stat_entry.second[static_cast(stat)] = avg + (val / SMOOTHING_PERIODS) - (avg / SMOOTHING_PERIODS); } } } @@ -185,7 +239,7 @@ namespace FSPerfStats } // and now adjust the proxy vars so that the main thread can adjust the visuals. - if(autoTune) + if(tunables.userAutoTuneEnabled) { updateAvatarParams(); } @@ -238,37 +292,6 @@ namespace FSPerfStats } } - // static - void StatsRecorder::updateSettingsFromRenderCostLimit() - { - static LLCachedControl maxRenderCost_us(gSavedSettings, "FSRenderAvatarMaxART"); - if( (F32)maxRenderCost_us != log10( ( (F32)FSPerfStats::renderAvatarMaxART_ns )/1000 ) ) - { - if( FSPerfStats::renderAvatarMaxART_ns != 0 ) - { - gSavedSettings.setF32( "FSRenderAvatarMaxART", log10( ( (F32)FSPerfStats::renderAvatarMaxART_ns )/1000 ) ); - } - else - { - gSavedSettings.setF32( "FSRenderAvatarMaxART",log10( FSPerfStats::ART_UNLIMITED_NANOS/1000 ) ); - } - } - } - - // static - void StatsRecorder::updateRenderCostLimitFromSettings() - { - const auto newval = gSavedSettings.getF32("FSRenderAvatarMaxART"); - if(newval < log10(FSPerfStats::ART_UNLIMITED_NANOS/1000)) - { - FSPerfStats::renderAvatarMaxART_ns = pow(10,newval)*1000; - } - else - { - FSPerfStats::renderAvatarMaxART_ns = 0; - }; - } - //static int StatsRecorder::countNearbyAvatars(S32 distance) { @@ -283,23 +306,16 @@ namespace FSPerfStats // static void StatsRecorder::updateAvatarParams() { - static LLCachedControl drawDistance(gSavedSettings, "RenderFarClip"); - static LLCachedControl userMinDrawDistance(gSavedSettings, "FSAutoTuneRenderFarClipMin"); - static LLCachedControl userTargetDrawDistance(gSavedSettings, "FSAutoTuneRenderFarClipTarget"); - static LLCachedControl impostorDistance(gSavedSettings, "FSAutoTuneImpostorFarAwayDistance"); - static LLCachedControl impostorDistanceTuning(gSavedSettings, "FSAutoTuneImpostorByDistEnabled"); - static LLCachedControl maxNonImpostors (gSavedSettings, "IndirectMaxNonImpostors"); - static LLCachedControl fpsTuningStrategy (gSavedSettings, "FSTuningFPSStrategy"); - if(impostorDistanceTuning) + if(tunables.userImpostorDistanceTuningEnabled) { // if we have less than the user's "max Non-Impostors" avatars within the desired range then adjust the limit. // also adjusts back up again for nearby crowds. - auto count = countNearbyAvatars(std::min(drawDistance, impostorDistance)); - if( count != maxNonImpostors ) + auto count = countNearbyAvatars(std::min(LLPipeline::RenderFarClip, tunables.userImpostorDistance)); + if( count != tunables.nonImpostors ) { tunables.updateNonImposters( (count < LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER)?count : LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER ); - LL_DEBUGS("AutoTune") << "There are " << count << "avatars within " << std::min(drawDistance, impostorDistance) << "m of the camera" << LL_ENDL; + LL_DEBUGS("AutoTune") << "There are " << count << "avatars within " << std::min(LLPipeline::RenderFarClip, tunables.userImpostorDistance) << "m of the camera" << LL_ENDL; } } @@ -326,44 +342,51 @@ namespace FSPerfStats } // The frametime budget we have based on the target FPS selected - auto target_frame_time_raw = (U64)llround((F64)LLTrace::BlockTimer::countsPerSecond()/(targetFPS==0?1:targetFPS)); + auto target_frame_time_raw = (U64)llround((F64)LLTrace::BlockTimer::countsPerSecond()/(tunables.userTargetFPS==0?1:tunables.userTargetFPS)); // LL_INFOS() << "Effective FPS(raw):" << tot_frame_time_raw << " Target:" << target_frame_time_raw << LL_ENDL; - + auto inferredFPS{1000/(U32)std::max(raw_to_ms(tot_frame_time_raw),1.0)}; + U32 settingsChangeFrequency{inferredFPS > 25?inferredFPS:25}; if( tot_limit_time_raw != 0) { // This could be problematic. tot_frame_time_raw -= tot_limit_time_raw; } - // 1) Is the target frame tim lower than current? + // 1) Is the target frame time lower than current? if( target_frame_time_raw <= tot_frame_time_raw ) { + if(belowTargetFPS == false) + { + // this is the first frame under. hold fire to add a little hysteresis + belowTargetFPS = true; + FSPerfStats::lastGlobalPrefChange = gFrameCount; + } // if so we've got work to do // how much of the frame was spent on non avatar related work? U32 non_avatar_time_raw = tot_frame_time_raw - tot_avatar_time_raw; - // If the target frame time < non avatar frame time thne adjusting avatars is only goin gto get us so far. + // If the target frame time < scene time (estimated as non_avatar time) U64 target_avatar_time_raw; if(target_frame_time_raw < non_avatar_time_raw) { // we cannnot do this by avatar adjustment alone. - if((gFrameCount - FSPerfStats::lastGlobalPrefChange) > 10) // give changes a short time to take effect. + if((gFrameCount - FSPerfStats::lastGlobalPrefChange) > settingsChangeFrequency) // give changes a short time to take effect. { - if(fpsTuningStrategy == 1) + if(tunables.userFPSTuningStrategy == TUNE_SCENE_AND_AVATARS) { // 1 - hack the water to opaque. all non opaque have a significant hit, this is a big boost for (arguably) a minor visual hit. - // the other reflection options make comparatively little change and iof this overshoots we'll be stepping back up later + // the other reflection options make comparatively little change and if this overshoots we'll be stepping back up later if(LLPipeline::RenderReflectionDetail != -2) { FSPerfStats::tunables.updateReflectionDetail(-2); FSPerfStats::lastGlobalPrefChange = gFrameCount; return; } - else // deliberately "else" here so we only do these in steps + else // deliberately "else" here so we only do one of these in any given frame { // step down the DD by 10m per update - auto new_dd = (drawDistance-10>userMinDrawDistance)?(drawDistance - 10) : userMinDrawDistance; - if(new_dd != drawDistance) + auto new_dd = (LLPipeline::RenderFarClip - DD_STEP > tunables.userMinDrawDistance)?(LLPipeline::RenderFarClip - DD_STEP) : tunables.userMinDrawDistance; + if(new_dd != LLPipeline::RenderFarClip) { FSPerfStats::tunables.updateFarClip( new_dd ); FSPerfStats::lastGlobalPrefChange = gFrameCount; @@ -371,26 +394,28 @@ namespace FSPerfStats } } } + // if we reach here, we've no more changes to make to tune scenery so we'll resort to agressive Avatar tuning + // Note: moved from outside "if changefrequency elapsed" to stop fallthrough and allow scenery changes time to take effect. + target_avatar_time_raw = 0; + } + else + { + // we made a settings change recently so let's give it time. + return; } - target_avatar_time_raw = 0; } else { - // desired avatar budget. + // set desired avatar budget. target_avatar_time_raw = target_frame_time_raw - non_avatar_time_raw; } if( target_avatar_time_raw < tot_avatar_time_raw ) { // we need to spend less time drawing avatars to meet our budget - // Note: working in usecs now cos reasons. - auto new_render_limit_ns {renderAvatarMaxART_ns}; + auto new_render_limit_ns {FSPerfStats::raw_to_ns(av_render_max_raw)}; // max render this frame may be higher than the last (cos new entrants and jitter) so make sure we are heading in the right direction - if(FSPerfStats::raw_to_ns(av_render_max_raw) < renderAvatarMaxART_ns) - { - new_render_limit_ns = FSPerfStats::raw_to_ns(av_render_max_raw); - } - else + if( new_render_limit_ns > renderAvatarMaxART_ns ) { new_render_limit_ns = renderAvatarMaxART_ns; } @@ -400,30 +425,55 @@ namespace FSPerfStats new_render_limit_ns = std::max((U64)new_render_limit_ns, (U64)FSPerfStats::ART_MINIMUM_NANOS); // assign the new value - renderAvatarMaxART_ns = new_render_limit_ns; + if(renderAvatarMaxART_ns != new_render_limit_ns) + { + renderAvatarMaxART_ns = new_render_limit_ns; + tunables.updateSettingsFromRenderCostLimit(); + } // LL_DEBUGS() << "AUTO_TUNE: avatar_budget adjusted to:" << new_render_limit_ns << LL_ENDL; } // LL_DEBUGS() << "AUTO_TUNE: Target frame time:"<< FSPerfStats::raw_to_us(target_frame_time_raw) << "usecs (non_avatar is " << FSPerfStats::raw_to_us(non_avatar_time_raw) << "usecs) Max cost limited=" << renderAvatarMaxART_ns << LL_ENDL; } else if( FSPerfStats::raw_to_ns(target_frame_time_raw) > (FSPerfStats::raw_to_ns(tot_frame_time_raw) + renderAvatarMaxART_ns) ) { - if( FSPerfStats::tunedAvatars >= 0 ) + if(belowTargetFPS == true) { - // if we have more time to spare let's shift up little in the hope we'll restore an avatar. - renderAvatarMaxART_ns += FSPerfStats::ART_MIN_ADJUST_UP_NANOS; + // we reached target, force a pause + lastGlobalPrefChange = gFrameCount; + belowTargetFPS = false; } - if( drawDistance < userTargetDrawDistance ) + + // once we're over the FPS target we slow down further + if((gFrameCount - lastGlobalPrefChange) > settingsChangeFrequency*3) { - FSPerfStats::tunables.updateFarClip( drawDistance + 10. ); - } - if( (target_frame_time_raw * 1.5) > tot_frame_time_raw && - FSPerfStats::tunedAvatars == 0 && - drawDistance >= userTargetDrawDistance) - { - // if everything else is "max" and we have 50% headroom let's knock the water quality up a notch at a time. - FSPerfStats::tunables.updateReflectionDetail( gSavedSettings.getS32("RenderReflectionDetail") + 1 ); + if(!tunables.userAutoTuneLock) + { + // we've reached the target and stayed long enough to consider stable. + // turn off if we are not locked. + tunables.updateUserAutoTuneEnabled(false); + } + if( FSPerfStats::tunedAvatars > 0 ) + { + // if we have more time to spare let's shift up little in the hope we'll restore an avatar. + renderAvatarMaxART_ns += FSPerfStats::ART_MIN_ADJUST_UP_NANOS; + tunables.updateSettingsFromRenderCostLimit(); + return; + } + if(tunables.userFPSTuningStrategy == TUNE_SCENE_AND_AVATARS) + { + if( LLPipeline::RenderFarClip < tunables.userTargetDrawDistance ) + { + FSPerfStats::tunables.updateFarClip( std::min(LLPipeline::RenderFarClip + DD_STEP, tunables.userTargetDrawDistance) ); + FSPerfStats::lastGlobalPrefChange = gFrameCount; + return; + } + if( (tot_frame_time_raw * 1.5) < target_frame_time_raw ) + { + // if everything else is "max" and we have >50% headroom let's knock the water quality up a notch at a time. + FSPerfStats::tunables.updateReflectionDetail( std::min(LLPipeline::RenderReflectionDetail + 1, tunables.userTargetReflections) ); + } + } } } - updateSettingsFromRenderCostLimit(); } } \ No newline at end of file diff --git a/indra/newview/fsperfstats.h b/indra/newview/fsperfstats.h index d6ff6fffb1..ced3785342 100644 --- a/indra/newview/fsperfstats.h +++ b/indra/newview/fsperfstats.h @@ -64,19 +64,23 @@ namespace FSPerfStats extern std::atomic inUseAttachmentUnRigged; #endif // Note if changing these, they should correspond with the log range of the correpsonding sliders - constexpr U64 ART_UNLIMITED_NANOS{50000000}; - constexpr U64 ART_MINIMUM_NANOS{100000}; - constexpr U64 ART_MIN_ADJUST_UP_NANOS{10000}; - constexpr U64 ART_MIN_ADJUST_DOWN_NANOS{10000}; + static constexpr U64 ART_UNLIMITED_NANOS{50000000}; + static constexpr U64 ART_MINIMUM_NANOS{100000}; + static constexpr U64 ART_MIN_ADJUST_UP_NANOS{10000}; + static constexpr U64 ART_MIN_ADJUST_DOWN_NANOS{10000}; - constexpr F32 PREFERRED_DD{180}; + static constexpr F32 PREFERRED_DD{180}; + static constexpr U32 SMOOTHING_PERIODS{50}; + static constexpr U32 DD_STEP{10}; + + static constexpr U32 TUNE_AVATARS_ONLY{0}; + static constexpr U32 TUNE_SCENE_AND_AVATARS{1}; extern std::atomic tunedAvatars; - extern U32 targetFPS; // desired FPS - extern U64 renderAvatarMaxART_ns; + extern std::atomic renderAvatarMaxART_ns; + extern bool belowTargetFPS; extern U32 lastGlobalPrefChange; extern std::mutex bufferToggleLock; - extern bool autoTune; enum class ObjType_t{ OT_GENERAL=0, // Also Unknown. Used for n/a type stats such as scenery @@ -118,21 +122,56 @@ namespace FSPerfStats struct Tunables { static constexpr U32 Nothing{0}; - static constexpr U32 NonImposters{1}; + static constexpr U32 NonImpostors{1}; static constexpr U32 ReflectionDetail{2}; static constexpr U32 FarClip{4}; + static constexpr U32 UserMinDrawDistance{8}; + static constexpr U32 UserTargetDrawDistance{16}; + static constexpr U32 UserImpostorDistance{32}; + static constexpr U32 UserImpostorDistanceTuningEnabled{64}; + static constexpr U32 UserFPSTuningStrategy{128}; + static constexpr U32 UserAutoTuneEnabled{256}; + static constexpr U32 UserTargetFPS{512}; + static constexpr U32 UserARTCutoff{1024}; + static constexpr U32 UserTargetReflections{2048}; + static constexpr U32 UserAutoTuneLock{4096}; - U32 tuningFlag{0}; - U32 nonImposters; - S32 reflectionDetail; - F32 farClip; + U32 tuningFlag{0}; // bit mask for changed settings - void updateFarClip(F32 nv){farClip=nv; tuningFlag |= FarClip;}; - void updateNonImposters(U32 nv){nonImposters=nv; tuningFlag |= NonImposters;}; + // proxy variables, used to pas the new value to be set via the mainthread + U32 nonImpostors{0}; + S32 reflectionDetail{0}; + F32 farClip{0.0}; + F32 userMinDrawDistance{0.0}; + F32 userTargetDrawDistance{0.0}; + F32 userImpostorDistance{0.0}; + bool userImpostorDistanceTuningEnabled{false}; + U32 userFPSTuningStrategy{0}; + bool userAutoTuneEnabled{false}; + bool userAutoTuneLock{true}; + U32 userTargetFPS{0}; + F32 userARTCutoffSliderValue{0}; + S32 userTargetReflections{0}; + + void updateNonImposters(U32 nv){nonImpostors=nv; tuningFlag |= NonImpostors;}; void updateReflectionDetail(S32 nv){reflectionDetail=nv; tuningFlag |= ReflectionDetail;}; + void updateFarClip(F32 nv){farClip=nv; tuningFlag |= FarClip;}; + void updateUserMinDrawDistance(F32 nv){userMinDrawDistance=nv; tuningFlag |= UserMinDrawDistance;}; + void updateUserTargetDrawDistance(F32 nv){userTargetDrawDistance=nv; tuningFlag |= UserTargetDrawDistance;}; + void updateImposterDistance(F32 nv){userImpostorDistance=nv; tuningFlag |= UserImpostorDistance;}; + void updateImposterDistanceTuningEnabled(bool nv){userImpostorDistanceTuningEnabled=nv; tuningFlag |= UserImpostorDistanceTuningEnabled;}; + void updateUserFPSTuningStrategy(U32 nv){userFPSTuningStrategy=nv; tuningFlag |= UserFPSTuningStrategy;}; + void updateTargetFps(U32 nv){userTargetFPS=nv; tuningFlag |= UserTargetFPS;}; + void updateUserARTCutoffSlider(F32 nv){userARTCutoffSliderValue=nv; tuningFlag |= UserARTCutoff;}; + void updateUserAutoTuneEnabled(bool nv){userAutoTuneEnabled=nv; tuningFlag |= UserAutoTuneEnabled;}; + void updateUserAutoTuneLock(bool nv){userAutoTuneLock=nv; tuningFlag |= UserAutoTuneLock;}; + void updateUserTargetReflections(S32 nv){userTargetReflections=nv; tuningFlag |= UserTargetReflections;}; - void applyUpdates(); void resetChanges(){tuningFlag=Nothing;}; + void initialiseFromSettings(); + void updateRenderCostLimitFromSettings(); + void updateSettingsFromRenderCostLimit(); + void applyUpdates(); }; extern Tunables tunables; @@ -177,8 +216,6 @@ namespace FSPerfStats { return max[getReadBufferIndex()][static_cast(otype)][static_cast(type)]; } - static void updateSettingsFromRenderCostLimit(); - static void updateRenderCostLimitFromSettings(); static void updateAvatarParams(); private: StatsRecorder(); diff --git a/indra/newview/installers/linux/appimage.sh b/indra/newview/installers/linux/appimage.sh index 85dfda6284..b06a096fa1 100755 --- a/indra/newview/installers/linux/appimage.sh +++ b/indra/newview/installers/linux/appimage.sh @@ -3,6 +3,8 @@ SCRIPT_PATH=`readlink -f $0` SCRIPT_PATH=`dirname $SCRIPT_PATH` +echo "Trying to build AppImage in directory $1 into file $3" + # All hope is lost if there is no lsb_release command command -v lsb_release >/dev/null 2>/dev/null || exit 0 @@ -45,3 +47,8 @@ chmod a+x appimagetool-x86_64.AppImage ./appimagetool-x86_64.AppImage --appimage-extract rm appimagetool-x86_64.AppImage ARCH=x86_64 squashfs-root/AppRun packaged + +if [ -f $2 ] +then + mv $2 $3 +fi diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 82d7341569..2fad445380 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -146,10 +146,10 @@ #include "stringize.h" #include "llcoros.h" #include "llexception.h" -//#if !LL_LINUX #include "cef/dullahan_version.h" +#if !LL_LINUX #include "vlc/libvlc_version.h" -//#endif // LL_LINUX +#endif // LL_LINUX // Third party library includes #include @@ -1643,7 +1643,7 @@ bool LLAppViewer::doFrame() // Perfstats collection Frame boundary { // and now adjust the visuals from previous frame. - if(FSPerfStats::autoTune && FSPerfStats::tunables.tuningFlag != FSPerfStats::Tunables::Nothing) + if(FSPerfStats::tunables.userAutoTuneEnabled && FSPerfStats::tunables.tuningFlag != FSPerfStats::Tunables::Nothing) { FSPerfStats::tunables.applyUpdates(); } @@ -3969,7 +3969,7 @@ LLSD LLAppViewer::getViewerInfo() const // info["LIBCEF_VERSION"] = "Undefined"; //#endif -//#if !LL_LINUX +#if !LL_LINUX std::ostringstream vlc_ver_codec; vlc_ver_codec << LIBVLC_VERSION_MAJOR; vlc_ver_codec << "."; @@ -3977,9 +3977,9 @@ LLSD LLAppViewer::getViewerInfo() const vlc_ver_codec << "."; vlc_ver_codec << LIBVLC_VERSION_REVISION; info["LIBVLC_VERSION"] = vlc_ver_codec.str(); -//#else -// info["LIBVLC_VERSION"] = "Undefined"; -//#endif +#else + info["LIBVLC_VERSION"] = "Using gstreamer 1.0"; +#endif S32 packets_in = LLViewerStats::instance().getRecording().getSum(LLStatViewer::PACKETS_IN); if (packets_in > 0) diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index 16a181d002..99716e9ede 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -49,8 +49,11 @@ #include "breakpad/client/linux/handler/exception_handler.h" #include "breakpad/common/linux/http_upload.h" #include "lldir.h" +#include "../llcrashlogger/llcrashlogger.h" #endif +#include "fsversionvalues.h" + #define VIEWERAPI_SERVICE "com.secondlife.ViewerAppAPIService" #define VIEWERAPI_PATH "/com/secondlife/ViewerAppAPI" #define VIEWERAPI_INTERFACE "com.secondlife.ViewerAppAPI" @@ -138,11 +141,56 @@ LLAppViewerLinux::~LLAppViewerLinux() } #if LL_SEND_CRASH_REPORTS +std::string gCrashLogger; +std::string gVersion; +std::string gBugsplatDB; +std::string gCrashBehavior; + static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded) { - printf("Dump path: %s\n", descriptor.path() ); + if( fork() == 0 ) + execl( gCrashLogger.c_str(), gCrashLogger.c_str(), descriptor.path(), gVersion.c_str(), gBugsplatDB.c_str(), gCrashBehavior.c_str(), nullptr ); return succeeded; } + +void setupBreadpad() +{ + std::string build_data_fname(gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "build_data.json")); + gCrashLogger = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "linux-crash-logger.bin"); + + llifstream inf(build_data_fname.c_str()); + if(!inf.is_open()) + { + LL_WARNS("BUGSPLAT") << "Can't initialize BugSplat, can't read '" << build_data_fname << "'" << LL_ENDL; + return; + } + + Json::Reader reader; + Json::Value build_data; + if(!reader.parse(inf, build_data, false)) + { + LL_WARNS("BUGSPLAT") << "Can't initialize BugSplat, can't parse '" << build_data_fname << "': " + << reader.getFormatedErrorMessages() << LL_ENDL; + return; + } + + Json::Value BugSplat_DB = build_data["BugSplat DB"]; + if(!BugSplat_DB) + { + LL_WARNS("BUGSPLAT") << "Can't initialize BugSplat, no 'BugSplat DB' entry in '" << build_data_fname + << "'" << LL_ENDL; + return; + } + gVersion = STRINGIZE( + LL_VIEWER_VERSION_MAJOR << '.' << LL_VIEWER_VERSION_MINOR << '.' << LL_VIEWER_VERSION_PATCH + << '.' << LL_VIEWER_VERSION_BUILD); + gBugsplatDB = BugSplat_DB.asString(); + + LL_INFOS("BUGSPLAT") << "Initializing with crash logger: " << gCrashLogger << " database: " << gBugsplatDB << " version: " << gVersion << LL_ENDL; + + google_breakpad::MinidumpDescriptor *descriptor = new google_breakpad::MinidumpDescriptor(gDirUtilp->getExpandedFilename(LL_PATH_DUMP, "")); + google_breakpad::ExceptionHandler *eh = new google_breakpad::ExceptionHandler(*descriptor, NULL, dumpCallback, NULL, true, -1); +} #endif bool LLAppViewerLinux::init() @@ -155,11 +203,17 @@ bool LLAppViewerLinux::init() bool success = LLAppViewer::init(); #if LL_SEND_CRASH_REPORTS - if (success) - { - google_breakpad::MinidumpDescriptor *descriptor = new google_breakpad::MinidumpDescriptor(gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"")); - google_breakpad::ExceptionHandler *eh = new google_breakpad::ExceptionHandler(*descriptor, NULL, dumpCallback, NULL, true, -1); - } + S32 nCrashSubmitBehavior = gCrashSettings.getS32("CrashSubmitBehavior"); + + // For the first version we just consider always send and create a nice dialog for CRASH_BEHAVIOR_ASK later. + if (success && nCrashSubmitBehavior != CRASH_BEHAVIOR_NEVER_SEND ) + { + if( nCrashSubmitBehavior == CRASH_BEHAVIOR_ASK ) + gCrashBehavior = "ask"; + else + gCrashBehavior = "send"; + setupBreadpad(); + } #endif return success; diff --git a/indra/newview/llpresetsmanager.cpp b/indra/newview/llpresetsmanager.cpp index b25b79c5a2..459f9ea275 100644 --- a/indra/newview/llpresetsmanager.cpp +++ b/indra/newview/llpresetsmanager.cpp @@ -711,7 +711,7 @@ void LLPresetsManager::handleGraphicPresetControlChanged(LLControlVariablePtr co if (!mIsLoadingPreset && (!mIsDrawDistanceSteppingActive || control->getName() != "RenderFarClip") && - (!FSPerfStats::autoTune) ) + (!FSPerfStats::tunables.userAutoTuneEnabled) ) { LL_DEBUGS() << "Trigger graphic preset control changed signal" << LL_ENDL; diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 3b1f3179d3..3ef82e5e26 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -1094,14 +1094,20 @@ void handleDiskCacheSizeChanged(const LLSD& newValue) void handleTargetFPSChanged(const LLSD& newValue) { const auto targetFPS = gSavedSettings.getU32("FSTargetFPS"); - FSPerfStats::targetFPS = targetFPS; + FSPerfStats::tunables.userTargetFPS = targetFPS; +} +// perf floater stuffs +void handleAutoTuneLockChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getBOOL("FSAutoTuneLock"); + FSPerfStats::tunables.userAutoTuneLock = newval; } // perrf floater stuffs void handleAutoTuneFPSChanged(const LLSD& newValue) { const auto newval = gSavedSettings.getBOOL("FSAutoTuneFPS"); - FSPerfStats::autoTune = newval; + FSPerfStats::tunables.userAutoTuneEnabled = newval; if(newval && FSPerfStats::renderAvatarMaxART_ns == 0) // If we've enabled autotune we override "unlimited" to max { gSavedSettings.setF32("FSRenderAvatarMaxART",log10(FSPerfStats::ART_UNLIMITED_NANOS-1000));//triggers callback to update static var @@ -1110,7 +1116,19 @@ void handleAutoTuneFPSChanged(const LLSD& newValue) void handleRenderAvatarMaxARTChanged(const LLSD& newValue) { - FSPerfStats::StatsRecorder::updateRenderCostLimitFromSettings(); + FSPerfStats::tunables.updateRenderCostLimitFromSettings(); +} + +void handleUserTargetDrawDistanceChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getF32("FSAutoTuneRenderFarClipTarget"); + FSPerfStats::tunables.userTargetDrawDistance = newval; +} + +void handleUserTargetReflectionsChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getF32("FSUserTargetReflections"); + FSPerfStats::tunables.userTargetReflections = newval; } void handlePerformanceStatsEnabledChanged(const LLSD& newValue) @@ -1118,6 +1136,22 @@ void handlePerformanceStatsEnabledChanged(const LLSD& newValue) const auto newval = gSavedSettings.getBOOL("FSPerfStatsCaptureEnabled"); FSPerfStats::StatsRecorder::setEnabled(newval); } +void handleUserImpostorByDistEnabledChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getBOOL("FSAutoTuneImpostorByDistEnabled"); + FSPerfStats::tunables.userImpostorDistanceTuningEnabled = newval; +} +void handleUserImpostorDistanceChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getF32("FSAutoTuneImpostorFarAwayDistance"); + FSPerfStats::tunables.userImpostorDistance = newval; +} +void handleFPSTuningStrategyChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getU32("FSTuningFPSStrategy"); + FSPerfStats::tunables.userFPSTuningStrategy = newval; +} + // //////////////////////////////////////////////////////////////////////////// @@ -1378,8 +1412,14 @@ void settings_setup_listeners() // perf floater controls gSavedSettings.getControl("FSTargetFPS")->getSignal()->connect(boost::bind(&handleTargetFPSChanged, _2)); gSavedSettings.getControl("FSAutoTuneFPS")->getSignal()->connect(boost::bind(&handleAutoTuneFPSChanged, _2)); + gSavedSettings.getControl("FSAutoTuneLock")->getSignal()->connect(boost::bind(&handleAutoTuneLockChanged, _2)); gSavedSettings.getControl("FSRenderAvatarMaxART")->getSignal()->connect(boost::bind(&handleRenderAvatarMaxARTChanged, _2)); gSavedSettings.getControl("FSPerfStatsCaptureEnabled")->getSignal()->connect(boost::bind(&handlePerformanceStatsEnabledChanged, _2)); + gSavedSettings.getControl("FSUserTargetReflections")->getSignal()->connect(boost::bind(&handleUserTargetReflectionsChanged, _2)); + gSavedSettings.getControl("FSAutoTuneRenderFarClipTarget")->getSignal()->connect(boost::bind(&handleUserTargetDrawDistanceChanged, _2)); + gSavedSettings.getControl("FSAutoTuneImpostorFarAwayDistance")->getSignal()->connect(boost::bind(&handleUserImpostorDistanceChanged, _2)); + gSavedSettings.getControl("FSAutoTuneImpostorByDistEnabled")->getSignal()->connect(boost::bind(&handleUserImpostorByDistEnabledChanged, _2)); + gSavedSettings.getControl("FSTuningFPSStrategy")->getSignal()->connect(boost::bind(&handleFPSTuningStrategyChanged, _2)); // } diff --git a/indra/newview/llxmlrpclistener.cpp b/indra/newview/llxmlrpclistener.cpp index 4401f61059..a041edb855 100644 --- a/indra/newview/llxmlrpclistener.cpp +++ b/indra/newview/llxmlrpclistener.cpp @@ -344,7 +344,10 @@ public: switch (curlcode) { case CURLE_SSL_PEER_CERTIFICATE: +// CURLE_SSL_CACERT has been deprecated, the LIBCURL-VERSION_NUM check is probably no checking for the lowest curl vesion this did happen +#if LIBCURL_VERSION_NUM < 0x075100 case CURLE_SSL_CACERT: +#endif data["certificate"] = mTransaction->getErrorCertData(); break; diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index 4d7ec57ace..5916b43539 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -517,7 +517,10 @@ void LLXMLRPCTransaction::Impl::setHttpStatus(const LLCore::HttpStatus &status) message = LLTrans::getString("ssl_peer_certificate"); break; +// CURLE_SSL_CACERT has been deprecated, the LIBCURL-VERSION_NUM check is probably no checking for the lowest curl vesion this did happen +#if LIBCURL_VERSION_NUM < 0x075100 case CURLE_SSL_CACERT: +#endif case CURLE_SSL_CONNECT_ERROR: message = LLTrans::getString("ssl_connect_error"); break; diff --git a/indra/newview/skins/default/xui/da/strings.xml b/indra/newview/skins/default/xui/da/strings.xml index f7453fccfc..05df2c3dca 100644 --- a/indra/newview/skins/default/xui/da/strings.xml +++ b/indra/newview/skins/default/xui/da/strings.xml @@ -425,11 +425,6 @@ Prøv venligst om lidt igen. Noter om version - Henter... diff --git a/indra/newview/skins/default/xui/de/floater_performance.xml b/indra/newview/skins/default/xui/de/floater_performance.xml index 4985f92000..e646f55982 100644 --- a/indra/newview/skins/default/xui/de/floater_performance.xml +++ b/indra/newview/skins/default/xui/de/floater_performance.xml @@ -18,6 +18,12 @@ Im Hintergrund + + 5-10 Sekunden warten auf Effekt der Anpassungen. + + + Statistik pausiert, wenn FPS begrenzt oder im Hintergrund. + Gesamt: [TOT_AV] ([TOT_AV_TIME]μs) @@ -30,25 +36,32 @@ Bilder pro Sekunde - 5-10 Sekunden warten auf Effekt der Anpassungen. + Statistik pausiert, wenn FPS begrenzt oder im Hintergrund. Frame-Aufschlüsselung erfolgt hier. - - Auto-Anpassung Ziel-FPS + + Auto-Anpassung: - + + Ziel-FPS: + + + + + + + + + + + + + Tuning Strategy + + + + + + + - - Auto-Tune Frame Rate - - - - - Automatically adjust settings to maintain FPS - - - - - - - - - - - - + + width="180"> Graphics settings - width="395"> Choose settings for distance, water, lighting and more. - name="icon_arrow3" follows="right|top" top="19" - right="-20"/> - - + right="-20" /> + + + follows="left|top" + font="SansSerifLarge" + text_color="White" + height="20" + layout="topleft" + left="10" + name="avatars_nearby_lbl" + top="7" + width="205"> Avatars nearby + follows="left|top" + font="SansSerif" + text_color="White" + height="20" + layout="topleft" + left="10" + name="avatars_nearby_desc" + top_pad="0" + width="345"> Manage which nearby avatars are fully displayed. - + Time spent drawing avatars + follows="top|right" + font="SansSerifHuge" + text_color="White" + height="20" + layout="topleft" + left_pad="10" + top="14" + name="av_frame_stats" + width="62"> 00% + height="16" + width="16" + image_name="Arrow_Right_Off" + mouse_opaque="true" + name="icon_arrow2" + follows="right|top" + top="19" + right="-20" /> + bg_alpha_color="PanelGray" + background_visible="true" + background_opaque="false" + border="true" + bevel_style="none" + follows="left|top|right" + height="50" + width="560" + name="complexity_subpanel" + layout="topleft" + top_pad="10"> + follows="left|top" + font="SansSerifLarge" + text_color="White" + height="20" + layout="topleft" + left="10" + name="complexity_lbl" + top="7" + width="180"> Your avatar complexity + follows="left|top" + font="SansSerif" + text_color="White" + height="20" + layout="topleft" + left="10" + name="complexity_info" + top_pad="0" + width="455"> Be a good citizen. Manage the impact of your avatar + height="16" + width="16" + image_name="Arrow_Right_Off" + mouse_opaque="true" + name="icon_arrow4" + follows="right|top" + top="19" + right="-20" /> + bg_alpha_color="PanelGray" + background_visible="true" + background_opaque="false" + border="true" + bevel_style="none" + follows="left|top|right" + height="50" + width="560" + name="huds_subpanel" + layout="topleft" + top_pad="10"> + follows="left|top" + font="SansSerifLarge" + text_color="White" + height="20" + layout="topleft" + left="10" + name="huds_lbl" + top="7" + width="135"> Your active HUDs + follows="left|top" + font="SansSerif" + text_color="White" + height="20" + layout="topleft" + left="10" + name="huds_desc" + top_pad="0" + width="345"> Removing unnecessary HUDs may improve speed. + follows="top|right" + font="SansSerifSmall" + text_color="White" + height="28" + layout="topleft" + left_pad="10" + name="huds_frme_pct_lbl" + top="8" + width="75"> Time spent drawing HUDs - + 00% + height="16" + width="16" + image_name="Arrow_Right_Off" + mouse_opaque="true" + name="icon_arrow4" + follows="right|top" + top="19" + right="-20" /> + filename="panel_performance_nearby.xml" + follows="all" + layout="topleft" + left="0" + name="panel_performance_nearby" + visible="false" + top="115" /> + filename="panel_performance_complexity.xml" + follows="all" + layout="topleft" + left="0" + name="panel_performance_complexity" + visible="false" + top="115" /> + filename="panel_performance_preferences.xml" + follows="all" + layout="topleft" + left="0" + name="panel_performance_preferences" + visible="false" + top="115" /> + filename="panel_performance_huds.xml" + follows="all" + layout="topleft" + left="0" + name="panel_performance_huds" + visible="false" + top="115" /> + filename="panel_performance_autotune.xml" + follows="all" + layout="topleft" + left="0" + name="panel_performance_autotune" + visible="false" + top="115" /> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 6fafa948fa..000ad3fb8f 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2885,6 +2885,17 @@ function="Floater.Toggle" parameter="scene_load_stats" /> + + + + + diff --git a/indra/newview/skins/default/xui/en/mime_types_linux.xml b/indra/newview/skins/default/xui/en/mime_types_linux.xml index a130d2b0e9..22a0024874 100644 --- a/indra/newview/skins/default/xui/en/mime_types_linux.xml +++ b/indra/newview/skins/default/xui/en/mime_types_linux.xml @@ -130,7 +130,7 @@ movie - media_plugin_libvlc + media_plugin_gstreamer @@ -163,7 +163,7 @@ audio - media_plugin_libvlc + media_plugin_gstreamer @@ -174,7 +174,7 @@ movie - media_plugin_libvlc + media_plugin_gstreamer @@ -196,7 +196,7 @@ movie - media_plugin_libvlc + media_plugin_gstreamer @@ -218,7 +218,7 @@ audio - media_plugin_libvlc + media_plugin_gstreamer @@ -295,7 +295,7 @@ audio - media_plugin_libvlc + media_plugin_gstreamer @@ -306,7 +306,7 @@ audio - media_plugin_libvlc + media_plugin_gstreamer @@ -317,7 +317,7 @@ audio - media_plugin_libvlc + media_plugin_gstreamer @@ -328,7 +328,7 @@ audio - media_plugin_libvlc + media_plugin_gstreamer @@ -438,7 +438,7 @@ movie - media_plugin_libvlc + media_plugin_gstreamer @@ -449,7 +449,7 @@ movie - media_plugin_libvlc + media_plugin_gstreamer @@ -460,7 +460,7 @@ movie - media_plugin_libvlc + media_plugin_gstreamer @@ -471,7 +471,7 @@ movie - media_plugin_libvlc + media_plugin_gstreamer @@ -482,7 +482,7 @@ movie - media_plugin_libvlc + media_plugin_gstreamer @@ -493,7 +493,7 @@ movie - media_plugin_libvlc + media_plugin_gstreamer diff --git a/indra/newview/skins/default/xui/en/panel_performance_autotune.xml b/indra/newview/skins/default/xui/en/panel_performance_autotune.xml index d29406ef2d..d27231123a 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_autotune.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_autotune.xml @@ -68,7 +68,7 @@ Distant Avatars -Avatars that are further away still have a high impact. +width="450" +wrap="true"> +Distant avatars can be automatically optimized regardless of their render cost. Set the distance from camera beyond which an avatar will be optimized. +Note: This setting will force MaxNonImpostors to 1 if nobody is nearby. -When adjusting scene parameters, autotune will optimize draw distance to between the minimum and the preferred. +When adjusting scene parameters, autotune will choose values between the minimum and the preferred draw distances. width="580"> You can also right-click on an avatar in-world to control display. - + + Note: Your own avatar includes viewer overheads. Use the attachment tab to see how you affect others. + label_text.text_color="White" layout="topleft" name="display_friends" - top_pad="3" + top_pad="2" left="18" width="256"> + Release Notes - https://wiki.firestormviewer.org/firestorm_change_log_ + https://wiki.firestormviewer.org/changelog:firestorm_change_log_ Loading... diff --git a/indra/newview/skins/default/xui/es/strings.xml b/indra/newview/skins/default/xui/es/strings.xml index 3e9bfe63c6..8d5192bc6d 100644 --- a/indra/newview/skins/default/xui/es/strings.xml +++ b/indra/newview/skins/default/xui/es/strings.xml @@ -663,11 +663,6 @@ pueden adjuntarse a las notas. Notas de la versión - Cargando... diff --git a/indra/newview/skins/default/xui/fr/floater_performance.xml b/indra/newview/skins/default/xui/fr/floater_performance.xml new file mode 100644 index 0000000000..d3bfbac156 --- /dev/null +++ b/indra/newview/skins/default/xui/fr/floater_performance.xml @@ -0,0 +1,92 @@ + + + + Images: [TOT_FRAME_TIME]ms - Scène:[SCENERY_FRAME_PCT]% Avatars:[AV_FRAME_PCT]% UI:[UI_FRAME_PCT]% Huds:[HUDS_FRAME_PCT]% Swap:[SWAP_FRAME_PCT]% Tâches:[IDLE_FRAME_PCT]% + + + FPS limité à: [FPSCAP] fps + + + Objectif: [FPSTARGET] fps + + + En arrière-plan + + + Total: [TOT_AV] ([TOT_AV_TIME]μs) + + + Total: [TOT_ATT] ([TOT_ATT_TIME]μs) + + + + + images par seconde + + + Attendez 5 à 10 secondes pour voir les changements. + + + [----------------- Vous verrez ici l'analyse du cadre. -----------------] + + + + + Réglage auto de l'affichage + + + + Réglage auto pour maint. le nombre de FPS. + + + + + + + + + + + + Paramètres graphiques + + + Sélectionnez les paramètres de distance, d'eau, d'éclairage, etc.. + + + + + Avatars à proximité + + + Définir quels avatars sont entièrement affichés. + + +Temps +Dessin +Avatars + + + + + Complexité de l'avatar + + + Soyez un bon citoyen. Gérez l'impact de votre avatar. + + + + + Vos HUD actifs + + + La suppress. des HUD inutiles peut améliorer la fluidité. + + +Temps +Dessin +HUDs + + + + diff --git a/indra/newview/skins/default/xui/fr/menu_viewer.xml b/indra/newview/skins/default/xui/fr/menu_viewer.xml index 7224832e08..7a8d5e7012 100644 --- a/indra/newview/skins/default/xui/fr/menu_viewer.xml +++ b/indra/newview/skins/default/xui/fr/menu_viewer.xml @@ -127,6 +127,7 @@ + diff --git a/indra/newview/skins/default/xui/fr/panel_fs_nui_login.xml b/indra/newview/skins/default/xui/fr/panel_fs_nui_login.xml index 2ff9ddff32..fb0ad900ce 100644 --- a/indra/newview/skins/default/xui/fr/panel_fs_nui_login.xml +++ b/indra/newview/skins/default/xui/fr/panel_fs_nui_login.xml @@ -3,9 +3,9 @@ http://secondlife.com/account/request.php?lang=fr - + Une grille connue ou l'URI d'une grille - + diff --git a/indra/newview/skins/default/xui/fr/panel_performance_autotune.xml b/indra/newview/skins/default/xui/fr/panel_performance_autotune.xml new file mode 100644 index 0000000000..9e5a95efcb --- /dev/null +++ b/indra/newview/skins/default/xui/fr/panel_performance_autotune.xml @@ -0,0 +1,34 @@ + + + + Retour + + + Options de réglage automatique + + + Avatars éloignés + + + + +Les avatars qui sont plus éloignés ont toujours un impact élevé. +Définissez la dist. de la caméra au-delà de laquelle un avatar sera optimisé. + + + Réglage de la distance de visibilité + + + + + Lors du réglage des paramètres de la scène, l'autotune optimisera la distance de visibilité entre le minimum et le maximum. + + + Divers + + + + + Ces options contrôlent des paramètres plus fins. Utilisez la page d'aide en ligne pour obtenir plus d'informations sur leur fonctionnement. + + diff --git a/indra/newview/skins/default/xui/fr/panel_performance_complexity.xml b/indra/newview/skins/default/xui/fr/panel_performance_complexity.xml new file mode 100644 index 0000000000..bf3dbcc625 --- /dev/null +++ b/indra/newview/skins/default/xui/fr/panel_performance_complexity.xml @@ -0,0 +1,23 @@ + + + + Retour + + + Complexité des attachements + + + Les attachements complexifient l'avatar et le rendu est plus lent. + + + Cet écran vous permet de visualiser les attachements de votre avatar. + + + Vous pouvez facilement supprimer vos attachements en cliquant sur le "X". + + + + + + + diff --git a/indra/newview/skins/default/xui/fr/panel_performance_huds.xml b/indra/newview/skins/default/xui/fr/panel_performance_huds.xml new file mode 100644 index 0000000000..995f7739f4 --- /dev/null +++ b/indra/newview/skins/default/xui/fr/panel_performance_huds.xml @@ -0,0 +1,22 @@ + + + + Retour + + + Vos HUDs actifs + + + Détacher les HUDs inutilisés économise de la mémoire et peut rendre le visualiseur plus rapide. + + + Les HUD sont souvent très scriptés et contribuent également au lag côté serveur. + + + L'utilisation du bouton de réduction d'un HUD ne le détache pas. Utilisez le X pour le retirer. + + + + + + diff --git a/indra/newview/skins/default/xui/fr/panel_performance_nearby.xml b/indra/newview/skins/default/xui/fr/panel_performance_nearby.xml new file mode 100644 index 0000000000..9a4cffe7b7 --- /dev/null +++ b/indra/newview/skins/default/xui/fr/panel_performance_nearby.xml @@ -0,0 +1,38 @@ + + + + Retour + + + Avatars à proximité + + + Masquer les avatars les plus complexes pour gagner en fluidité. + + + + + illimité + + + + + + + + + + Vous pouvez également faire un clic droit sur un avatar pour contr. l'affichage. + + diff --git a/indra/newview/skins/default/xui/pl/panel_fs_login.xml b/indra/newview/skins/default/xui/pl/panel_fs_login.xml index f4934d7a96..ad4302a343 100644 --- a/indra/newview/skins/default/xui/pl/panel_fs_login.xml +++ b/indra/newview/skins/default/xui/pl/panel_fs_login.xml @@ -1,8 +1,8 @@ - + Istniejący świat lub URI świata - + diff --git a/indra/newview/skins/default/xui/pl/panel_fs_nui_login.xml b/indra/newview/skins/default/xui/pl/panel_fs_nui_login.xml index 5e1fd854d1..ba215d8ec0 100644 --- a/indra/newview/skins/default/xui/pl/panel_fs_nui_login.xml +++ b/indra/newview/skins/default/xui/pl/panel_fs_nui_login.xml @@ -1,8 +1,8 @@ - + Istniejący świat lub URI świata - + diff --git a/indra/newview/skins/default/xui/pl/panel_performance_autotune.xml b/indra/newview/skins/default/xui/pl/panel_performance_autotune.xml index 895c82cc4c..28896900d6 100644 --- a/indra/newview/skins/default/xui/pl/panel_performance_autotune.xml +++ b/indra/newview/skins/default/xui/pl/panel_performance_autotune.xml @@ -12,8 +12,9 @@ -Awatary, które są dalej, nadal wpływają na renderowanie. +Awatary w oddali mogą być optymalizowane niezależnie od kosztu renderowania. Określ odległość po której awatar zostanie zoptymalizowany. +To ustawienie wymusi MaxNonImpostors do 1, jeśli nikogo nie będzie w pobliżu. Limity dostrajania pola widzenia @@ -21,7 +22,7 @@ Określ odległość po której awatar zostanie zoptymalizowany. - Podczas przetwarzania sceny autostrojenie zoptymalizuje pole widzenia między minimalnym a preferowanym. + Podczas przetwarzania sceny autostrojenie wybierze wartości między minimalnymi a preferowanymi dla pola widzenia. Różne diff --git a/indra/newview/skins/default/xui/pl/panel_performance_nearby.xml b/indra/newview/skins/default/xui/pl/panel_performance_nearby.xml index 32e7959a74..9dbb97bd21 100644 --- a/indra/newview/skins/default/xui/pl/panel_performance_nearby.xml +++ b/indra/newview/skins/default/xui/pl/panel_performance_nearby.xml @@ -24,8 +24,11 @@ Możesz kliknąć PPM na awatarze w świecie, aby sterować wyświetlaniem. - diff --git a/indra/newview/skins/default/xui/ru/notifications.xml b/indra/newview/skins/default/xui/ru/notifications.xml index 7401f4b086..2bccaea303 100644 --- a/indra/newview/skins/default/xui/ru/notifications.xml +++ b/indra/newview/skins/default/xui/ru/notifications.xml @@ -5290,4 +5290,11 @@ https://wiki.firestormviewer.org/fs_voice Предмет с названием "[NAME]" является ригованым мешем, но прикреплен на экран в "[HUD_POINT]". Это значит, что для вас он будет отображаться правильно, но все остальные вообще не смогут его увидеть. Возможно, вы захотите снять его и снова прикрепить к обычной точке крепления на теле. + + + URL-адрес заставки входа в систему переопределен в целях тестирования. + +Сбросить URL по умолчанию? + + diff --git a/indra/newview/skins/default/xui/ru/panel_performance_autotune.xml b/indra/newview/skins/default/xui/ru/panel_performance_autotune.xml index da4c10292c..3d51d3ba51 100644 --- a/indra/newview/skins/default/xui/ru/panel_performance_autotune.xml +++ b/indra/newview/skins/default/xui/ru/panel_performance_autotune.xml @@ -6,14 +6,15 @@ -Аватары которые далеко, по-прежнему имеют большое влияние. -Установи дальность, дальше которой аватар будет оптимизирован. +Далекие аватары будут оптимизированы независимо от рендеринга. Установи дальность, с которой аватар будет оптимизирован. +Примечание. Этот параметр установит MaxNonImpostors значение 1, +если поблизости никого нет. Пределы настройки расстояния -При настройке параметров сцены, автонастройка оптимизирует расстояние прорисовки между минимальным и предпочтительным. +При настройке параметров сцены, автонастройка будет выбирать значения между минимальным и предпочтительным расстоянием прорисовки. Разные настройки diff --git a/indra/newview/skins/default/xui/ru/panel_performance_nearby.xml b/indra/newview/skins/default/xui/ru/panel_performance_nearby.xml index af94ecb184..d82785b813 100644 --- a/indra/newview/skins/default/xui/ru/panel_performance_nearby.xml +++ b/indra/newview/skins/default/xui/ru/panel_performance_nearby.xml @@ -1,4 +1,4 @@ - + Назад Аватары рядом @@ -17,8 +17,11 @@ Вы можете щелкнуть ПКМ на аватар в мире, чтобы управлять отображением. -