From 73616b81f39bd49362f0e55b893203f544c1369f Mon Sep 17 00:00:00 2001 From: Matt Hardcastle Date: Thu, 20 Jun 2019 15:36:28 -0700 Subject: [PATCH 01/21] Fail on empty LAUNCHER_HMAC_SECRET Priot to this change there was code that attempted to verify that LAUNCHER_HMAC_SECRET was set to something. This code was broke though and didn't catch the case correctly. This change fixes the check. --- launchers/darwin/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launchers/darwin/CMakeLists.txt b/launchers/darwin/CMakeLists.txt index 4da675fcc9..9592ef69f3 100644 --- a/launchers/darwin/CMakeLists.txt +++ b/launchers/darwin/CMakeLists.txt @@ -67,7 +67,7 @@ add_executable(${PROJECT_NAME} MACOSX_BUNDLE ${src_files}) set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME ${APP_NAME} MACOSX_BUNDLE_BUNDLE_NAME ${APP_NAME}) set_from_env(LAUNCHER_HMAC_SECRET LAUNCHER_HMAC_SECRET "") -if (LAUNCHER_HMAC_SECRET STREQUAL "") +if ("${LAUNCHER_HMAC_SECRET}" STREQUAL "") message(FATAL_ERROR "LAUNCHER_HMAC_SECRET is not set") endif() From 3a5aa4194e7fe5a745a1ff17a1f6cb3ebed497db Mon Sep 17 00:00:00 2001 From: Matt Hardcastle Date: Sat, 22 Jun 2019 11:23:17 -0700 Subject: [PATCH 02/21] Pin the macOS HQ Launcher target version to 10.9 This change pins HQ Launcher's target SDK to 10.9, which is the same as the target SDK for Interface. Without this pinned value the target version defaults to whatever the OS version is on the machine that happened to build HQ Launcher. --- launchers/darwin/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/launchers/darwin/CMakeLists.txt b/launchers/darwin/CMakeLists.txt index 9592ef69f3..76d209d89d 100644 --- a/launchers/darwin/CMakeLists.txt +++ b/launchers/darwin/CMakeLists.txt @@ -1,4 +1,5 @@ cmake_minimum_required(VERSION 3.0) +set(ENV{MACOSX_DEPLOYMENT_TARGET} 10.9) project(HQLauncher) set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/") set(src_files From 4d28c5fe412ae1f3df98ccf1edf1f6660211b0a5 Mon Sep 17 00:00:00 2001 From: Matt Hardcastle Date: Sat, 22 Jun 2019 11:32:36 -0700 Subject: [PATCH 03/21] Use version from Interface in macOS HQ Launcher Prior to this change the macOS HQ Launcher used the version from the settings files. Pull this information in the settings file could result in a situation where the setting file was updated, but interface wasn't. When the launcher ran a second time it would check the settings file and think Interface was updated even though it wasn't. This change resolves the issue by asking interface for its version directly. In the event that Interface doesn't response with a version number HQ Launcher knows how to interoperate HQ Launcher will fall back to using the settings file. Known Issues --- 1) Interface reports different version number formats depending on how its built. A stable interface for getting the build version from interface should be added. --- launchers/darwin/CMakeLists.txt | 2 + launchers/darwin/src/Interface.h | 8 ++ launchers/darwin/src/Interface.m | 100 ++++++++++++++++++++++ launchers/darwin/src/LatestBuildRequest.m | 25 ++++-- 4 files changed, 128 insertions(+), 7 deletions(-) create mode 100644 launchers/darwin/src/Interface.h create mode 100644 launchers/darwin/src/Interface.m diff --git a/launchers/darwin/CMakeLists.txt b/launchers/darwin/CMakeLists.txt index 76d209d89d..a3fc0dc7c1 100644 --- a/launchers/darwin/CMakeLists.txt +++ b/launchers/darwin/CMakeLists.txt @@ -27,6 +27,8 @@ set(src_files src/LatestBuildRequest.m src/OrganizationRequest.m src/OrganizationRequest.h + src/Interface.h + src/Interface.m src/ErrorViewController.h src/ErrorViewController.m src/Settings.h diff --git a/launchers/darwin/src/Interface.h b/launchers/darwin/src/Interface.h new file mode 100644 index 0000000000..c142aeecf5 --- /dev/null +++ b/launchers/darwin/src/Interface.h @@ -0,0 +1,8 @@ +#import + +@interface Interface : NSObject + +-(id _Nonnull) initWith:(NSString * _Nonnull) aPathToInterface; +-(NSInteger) getVersion:(out NSError * _Nullable * _Nonnull) anError; + +@end diff --git a/launchers/darwin/src/Interface.m b/launchers/darwin/src/Interface.m new file mode 100644 index 0000000000..b007e7faa5 --- /dev/null +++ b/launchers/darwin/src/Interface.m @@ -0,0 +1,100 @@ +#import "Interface.h" + +@implementation Interface +{ + NSString *pathTo; +} + +-(id) initWith:(NSString*)aPathToInterface +{ + [self init]; + self->pathTo = [NSString stringWithFormat:@"%@/Contents/MacOS/interface", aPathToInterface]; + return self; +} + +-(NSInteger) getVersion:(out NSError * _Nullable *) outError +{ + NSTask * interface = [[NSTask alloc] init]; + NSPipe * standardOut = [NSPipe pipe]; + + interface.launchPath = self->pathTo; + interface.arguments = @[ @"--version" ]; + interface.standardOutput = standardOut; + + NSLog(@"calling interface at %@", self->pathTo); + + if (@available(macOS 10.13, *)) { + NSError *error = nil; + if (![interface launchAndReturnError:&error]) { + *outError = [NSError errorWithDomain:@"interface" + code:-1 + userInfo:@{NSUnderlyingErrorKey: error}]; + return 0; + } + } else { + NSError *error = nil; + [interface launch]; + [interface waitUntilExit]; + if (0 != [interface terminationStatus]) { + *outError = [NSError errorWithDomain:@"interface" + code:-1 + userInfo:@{NSUnderlyingErrorKey: error}]; + return 0; + } + } + + NSFileHandle * fh = [standardOut fileHandleForReading]; + NSData * data = [fh readDataToEndOfFile]; + NSString * output = [NSString stringWithUTF8String:[data bytes]]; + if (output == nil) { + NSDictionary * userInfo = @{ + NSLocalizedDescriptionKey: NSLocalizedString(@"Couldn't start interface", nil) + }; + *outError = [NSError errorWithDomain:@"interface" + code:-1 + userInfo:userInfo]; + return 0; + } + + // Interface returns the build version as a string like this: + // "Interface 33333-DEADBEEF". This code grabs the substring + // between "Interface " and the hyphon ("-") + NSRange start = [output rangeOfString:@"Interface "]; + if (start.length == 0) { + NSDictionary * userInfo = @{ + NSLocalizedDescriptionKey: NSLocalizedString(@"Couldn't read interface's version", nil) + }; + *outError = [NSError errorWithDomain:@"interface" + code:-2 + userInfo:userInfo]; + return 0; + } + NSRange end = [output rangeOfString:@"-"]; + if (end.length == 0) { + NSDictionary * userInfo = @{ + NSLocalizedDescriptionKey: NSLocalizedString(@"Couldn't read interface's version", nil) + }; + *outError = [NSError errorWithDomain:@"interface" + code:-2 + userInfo:userInfo]; + return 0; + } + NSRange subRange = {start.length, end.location - start.length}; + NSString * versionStr; + @try { + versionStr = [output substringWithRange:subRange]; + } + @catch (NSException *) { + NSDictionary * userInfo = @{ + NSLocalizedDescriptionKey: NSLocalizedString(@"Couldn't read interface's version", nil) + }; + *outError = [NSError errorWithDomain:@"interface" + code:-2 + userInfo:userInfo]; + return 0; + } + + return versionStr.integerValue; +} + +@end diff --git a/launchers/darwin/src/LatestBuildRequest.m b/launchers/darwin/src/LatestBuildRequest.m index 5119efa8f6..21f63425ab 100644 --- a/launchers/darwin/src/LatestBuildRequest.m +++ b/launchers/darwin/src/LatestBuildRequest.m @@ -1,9 +1,22 @@ #import "LatestBuildRequest.h" #import "Launcher.h" #import "Settings.h" +#import "Interface.h" @implementation LatestBuildRequest +- (NSInteger) getCurrentVersion { + NSString* interfaceAppPath = [[Launcher.sharedLauncher getAppPath] stringByAppendingString:@"interface.app"]; + NSError * error = nil; + Interface * interface = [[Interface alloc] initWith:interfaceAppPath]; + NSInteger currentVersion = [interface getVersion:&error]; + if (currentVersion == 0 && error != nil) { + NSLog(@"can't get version from interface, falling back to settings: %@", error); + currentVersion = [Settings.sharedSettings latestBuildVersion]; + } + return currentVersion; +} + - (void) requestLatestBuildInfo { NSMutableURLRequest *request = [NSMutableURLRequest new]; [request setURL:[NSURL URLWithString:@"https://thunder.highfidelity.com/builds/api/tags/latest?format=json"]]; @@ -45,8 +58,7 @@ BOOL appDirectoryExist = [fileManager fileExistsAtPath:[[sharedLauncher getAppPath] stringByAppendingString:@"interface.app"]]; dispatch_async(dispatch_get_main_queue(), ^{ - Settings* settings = [Settings sharedSettings]; - NSInteger currentVersion = [settings latestBuildVersion]; + NSInteger currentVersion = [self getCurrentVersion]; NSLog(@"Latest Build Request -> does build directory exist: %@", appDirectoryExist ? @"TRUE" : @"FALSE"); NSLog(@"Latest Build Request -> current version: %ld", currentVersion); NSLog(@"Latest Build Request -> latest version: %ld", buildNumber.integerValue); @@ -105,11 +117,10 @@ NSDictionary* macInstallerObject = [installers objectForKey:@"mac"]; NSString* macInstallerUrl = [macInstallerObject valueForKey:@"zip_url"]; - BOOL appDirectoryExist = [fileManager fileExistsAtPath:[[sharedLauncher getAppPath] stringByAppendingString:@"interface.app"]]; - - Settings* settings = [Settings sharedSettings]; - NSInteger currentVersion = [settings latestBuildVersion]; - BOOL latestVersionAvailable = (currentVersion != buildNumber.integerValue); + NSString* interfaceAppPath = [[sharedLauncher getAppPath] stringByAppendingString:@"interface.app"]; + BOOL appDirectoryExist = [fileManager fileExistsAtPath:interfaceAppPath]; + + BOOL latestVersionAvailable = ([self getCurrentVersion] != buildNumber.integerValue); [[Settings sharedSettings] buildVersion:buildNumber.integerValue]; BOOL shouldDownloadInterface = (latestVersionAvailable || !appDirectoryExist); From 4f6e2c85f9c14ae89b303b1b0ee0800f4845e77c Mon Sep 17 00:00:00 2001 From: Matt Hardcastle Date: Sat, 22 Jun 2019 12:28:57 -0700 Subject: [PATCH 04/21] Never cache the tags API in macOS's HQ Launcher Prior to this change we used the default session while downloading the latest tags API response from Thunder. This left open the possibility that NSURLSession could cache the response, even though the server asked it not to; NSURLSession can be pretty aggressive about its caching. This change ensure no caching of the API is occurring my using an ephemeral session when calling the tags API. --- launchers/darwin/src/LatestBuildRequest.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/launchers/darwin/src/LatestBuildRequest.m b/launchers/darwin/src/LatestBuildRequest.m index 21f63425ab..7e836548af 100644 --- a/launchers/darwin/src/LatestBuildRequest.m +++ b/launchers/darwin/src/LatestBuildRequest.m @@ -23,8 +23,8 @@ [request setHTTPMethod:@"GET"]; [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; - - NSURLSession* session = [NSURLSession sharedSession]; + // We're using an ephermeral session here to ensure the tags api response is never cached. + NSURLSession * session = [NSURLSession sessionWithConfiguration:NSURLSessionConfiguration.ephemeralSessionConfiguration]; NSURLSessionDataTask* dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { From 9e309b095da40440ac5b5c6a052b1bdc9a5b8e68 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Sun, 23 Jun 2019 08:00:13 -0700 Subject: [PATCH 05/21] Fix bug that was packing zero offsets that were never used --- libraries/render-utils/src/Model.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 64a46f3c1e..eccc7287b2 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1738,6 +1738,9 @@ void Blender::run() { int numMeshes = 0; // number of meshes in this model. for (auto meshIter = _hfmModel->meshes.cbegin(); meshIter != _hfmModel->meshes.cend(); ++meshIter) { numMeshes++; + if (meshIter->blendshapes.isEmpty()) { + continue; + } int numVertsInMesh = meshIter->vertices.size(); numBlendshapeOffsets += numVertsInMesh; } From 87c680382f5c11bb8556e901fcff383fdd2b1285 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Sun, 23 Jun 2019 08:42:38 -0700 Subject: [PATCH 06/21] Strip-mining optimization to improve cache utilization. For each mesh: init, accumulate, and pack using a recycled offset buffer. --- libraries/render-utils/src/Model.cpp | 32 +++++++++++++++++----------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index eccc7287b2..6e969fe51f 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1735,6 +1735,7 @@ Blender::Blender(ModelPointer model, HFMModel::ConstPointer hfmModel, int blendN void Blender::run() { DETAILED_PROFILE_RANGE_EX(simulation_animation, __FUNCTION__, 0xFFFF0000, 0, { { "url", _model->getURL().toString() } }); int numBlendshapeOffsets = 0; // number of offsets required for all meshes. + int maxBlendshapeOffsets = 0; // number of offsets in the largest mesh. int numMeshes = 0; // number of meshes in this model. for (auto meshIter = _hfmModel->meshes.cbegin(); meshIter != _hfmModel->meshes.cend(); ++meshIter) { numMeshes++; @@ -1743,16 +1744,19 @@ void Blender::run() { } int numVertsInMesh = meshIter->vertices.size(); numBlendshapeOffsets += numVertsInMesh; + maxBlendshapeOffsets = std::max(maxBlendshapeOffsets, numVertsInMesh); } - // all elements are default constructed to zero offsets. - QVector packedBlendshapeOffsets(numBlendshapeOffsets); - QVector unpackedBlendshapeOffsets(numBlendshapeOffsets); - - // allocate the required size + // allocate the required sizes QVector blendedMeshSizes; blendedMeshSizes.reserve(numMeshes); + QVector packedBlendshapeOffsets; + packedBlendshapeOffsets.reserve(numBlendshapeOffsets); + + QVector unpackedBlendshapeOffsets; + unpackedBlendshapeOffsets.reserve(maxBlendshapeOffsets); // reuse for all meshes + int offset = 0; for (auto meshIter = _hfmModel->meshes.cbegin(); meshIter != _hfmModel->meshes.cend(); ++meshIter) { if (meshIter->blendshapes.isEmpty()) { @@ -1762,6 +1766,9 @@ void Blender::run() { int numVertsInMesh = meshIter->vertices.size(); blendedMeshSizes.push_back(numVertsInMesh); + // initialize offsets to zero + memset(unpackedBlendshapeOffsets.data(), 0, numVertsInMesh * sizeof(BlendshapeOffsetUnpacked)); + // for each blendshape in this mesh, accumulate the offsets into unpackedBlendshapeOffsets. const float NORMAL_COEFFICIENT_SCALE = 0.01f; for (int i = 0, n = qMin(_blendshapeCoefficients.size(), meshIter->blendshapes.size()); i < n; i++) { @@ -1776,7 +1783,7 @@ void Blender::run() { for (int j = 0; j < blendshape.indices.size(); ++j) { int index = blendshape.indices.at(j); - auto& currentBlendshapeOffset = unpackedBlendshapeOffsets[offset + index]; + auto& currentBlendshapeOffset = unpackedBlendshapeOffsets[index]; currentBlendshapeOffset.positionOffset += blendshape.vertices.at(j) * vertexCoefficient; currentBlendshapeOffset.normalOffset += blendshape.normals.at(j) * normalCoefficient; if (j < blendshape.tangents.size()) { @@ -1784,20 +1791,19 @@ void Blender::run() { } } } - offset += numVertsInMesh; - } - // convert unpackedBlendshapeOffsets into packedBlendshapeOffsets for the gpu. - // FIXME it feels like we could be more effectively using SIMD here - { + // convert unpackedBlendshapeOffsets into packedBlendshapeOffsets for the gpu. auto unpacked = unpackedBlendshapeOffsets.data(); - auto packed = packedBlendshapeOffsets.data(); - for (int i = 0; i < unpackedBlendshapeOffsets.size(); ++i) { + auto packed = packedBlendshapeOffsets.data() + offset; + for (int i = 0; i < numVertsInMesh; ++i) { packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10((*packed).packedPosNorTan, (*unpacked)); ++unpacked; ++packed; } + + offset += numVertsInMesh; } + Q_ASSERT(offset == numBlendshapeOffsets); // post the result to the ModelBlender, which will dispatch to the model if still alive QMetaObject::invokeMethod(DependencyManager::get().data(), "setBlendedVertices", From cceff21cd0ea1d583e39c6dea5f333df909bed10 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Sun, 23 Jun 2019 08:57:56 -0700 Subject: [PATCH 07/21] Pull packBlendshapeOffsets() into separate function --- libraries/render-utils/src/Model.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 6e969fe51f..6a06047bef 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1691,10 +1691,7 @@ public: } }; - -using packBlendshapeOffsetTo = void(glm::uvec4& packed, const BlendshapeOffsetUnpacked& unpacked); - -void packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10(glm::uvec4& packed, const BlendshapeOffsetUnpacked& unpacked) { +static void packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10(glm::uvec4& packed, const BlendshapeOffsetUnpacked& unpacked) { float len = glm::compMax(glm::abs(unpacked.positionOffset)); glm::vec3 normalizedPos(unpacked.positionOffset); if (len > 0.0f) { @@ -1711,6 +1708,14 @@ void packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10(glm::uvec4& pac ); } +static void packBlendshapeOffsets(BlendshapeOffsetUnpacked* unpacked, BlendshapeOffsetPacked* packed, int size) { + for (int i = 0; i < size; ++i) { + packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10((*packed).packedPosNorTan, (*unpacked)); + ++unpacked; + ++packed; + } +} + class Blender : public QRunnable { public: @@ -1795,11 +1800,7 @@ void Blender::run() { // convert unpackedBlendshapeOffsets into packedBlendshapeOffsets for the gpu. auto unpacked = unpackedBlendshapeOffsets.data(); auto packed = packedBlendshapeOffsets.data() + offset; - for (int i = 0; i < numVertsInMesh; ++i) { - packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10((*packed).packedPosNorTan, (*unpacked)); - ++unpacked; - ++packed; - } + packBlendshapeOffsets(unpacked, packed, numVertsInMesh); offset += numVertsInMesh; } From 8653118b6cb09810b7d1688ddb62975d52b96f05 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Sun, 23 Jun 2019 10:32:57 -0700 Subject: [PATCH 08/21] Full SIMD implementation of packBlendshapeOffsets() using AVX2. 6x speedup over the existing (partial SIMD) version. 60x speedup over the original (pure GLM) version. --- libraries/render-utils/src/Model.cpp | 10 +- .../src/avx2/BlendshapePacking_avx2.cpp | 285 ++++++++++++++++++ 2 files changed, 294 insertions(+), 1 deletion(-) create mode 100644 libraries/render-utils/src/avx2/BlendshapePacking_avx2.cpp diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 6a06047bef..67f64395b2 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1708,7 +1708,7 @@ static void packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10(glm::uve ); } -static void packBlendshapeOffsets(BlendshapeOffsetUnpacked* unpacked, BlendshapeOffsetPacked* packed, int size) { +static void packBlendshapeOffsets_ref(BlendshapeOffsetUnpacked* unpacked, BlendshapeOffsetPacked* packed, int size) { for (int i = 0; i < size; ++i) { packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10((*packed).packedPosNorTan, (*unpacked)); ++unpacked; @@ -1716,6 +1716,14 @@ static void packBlendshapeOffsets(BlendshapeOffsetUnpacked* unpacked, Blendshape } } +void packBlendshapeOffsets_AVX2(float (*unpacked)[9], uint32_t (*packed)[4], int size); + +static void packBlendshapeOffsets(BlendshapeOffsetUnpacked* unpacked, BlendshapeOffsetPacked* packed, int size) { + static_assert(sizeof(BlendshapeOffsetUnpacked) == 9 * sizeof(float), "struct BlendshapeOffsetUnpacked size doesn't match."); + static_assert(sizeof(BlendshapeOffsetPacked) == 4 * sizeof(uint32_t), "struct BlendshapeOffsetPacked size doesn't match."); + packBlendshapeOffsets_AVX2((float(*)[9])unpacked, (uint32_t(*)[4])packed, size); +} + class Blender : public QRunnable { public: diff --git a/libraries/render-utils/src/avx2/BlendshapePacking_avx2.cpp b/libraries/render-utils/src/avx2/BlendshapePacking_avx2.cpp new file mode 100644 index 0000000000..5524c355dc --- /dev/null +++ b/libraries/render-utils/src/avx2/BlendshapePacking_avx2.cpp @@ -0,0 +1,285 @@ +// +// BlendshapePacking_avx2.cpp +// +// Created by Ken Cooke on 6/22/19. +// Copyright 2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifdef __AVX2__ + +#include +#include + +void packBlendshapeOffsets_AVX2(float (*unpacked)[9], uint32_t (*packed)[4], int size) { + + int i = 0; + for (; i < size - 7; i += 8) { // blocks of 8 + + // + // deinterleave (8x9 to 9x8 matrix transpose) + // + __m256 s0 = _mm256_insertf128_ps(_mm256_castps128_ps256(_mm_load_ps(&unpacked[i+0][0])), _mm_load_ps(&unpacked[i+4][0]), 1); + __m256 s1 = _mm256_insertf128_ps(_mm256_castps128_ps256(_mm_load_ps(&unpacked[i+1][0])), _mm_load_ps(&unpacked[i+5][0]), 1); + __m256 s2 = _mm256_insertf128_ps(_mm256_castps128_ps256(_mm_load_ps(&unpacked[i+2][0])), _mm_load_ps(&unpacked[i+6][0]), 1); + __m256 s3 = _mm256_insertf128_ps(_mm256_castps128_ps256(_mm_load_ps(&unpacked[i+3][0])), _mm_load_ps(&unpacked[i+7][0]), 1); + __m256 s4 = _mm256_insertf128_ps(_mm256_castps128_ps256(_mm_load_ps(&unpacked[i+0][4])), _mm_load_ps(&unpacked[i+4][4]), 1); + __m256 s5 = _mm256_insertf128_ps(_mm256_castps128_ps256(_mm_load_ps(&unpacked[i+1][4])), _mm_load_ps(&unpacked[i+5][4]), 1); + __m256 s6 = _mm256_insertf128_ps(_mm256_castps128_ps256(_mm_load_ps(&unpacked[i+2][4])), _mm_load_ps(&unpacked[i+6][4]), 1); + __m256 s7 = _mm256_insertf128_ps(_mm256_castps128_ps256(_mm_load_ps(&unpacked[i+3][4])), _mm_load_ps(&unpacked[i+7][4]), 1); + + __m256 t0 = _mm256_unpacklo_ps(s0, s1); + __m256 t1 = _mm256_unpackhi_ps(s0, s1); + __m256 t2 = _mm256_unpacklo_ps(s2, s3); + __m256 t3 = _mm256_unpackhi_ps(s2, s3); + __m256 t4 = _mm256_unpacklo_ps(s4, s5); + __m256 t5 = _mm256_unpackhi_ps(s4, s5); + __m256 t6 = _mm256_unpacklo_ps(s6, s7); + __m256 t7 = _mm256_unpackhi_ps(s6, s7); + + __m256 px = _mm256_shuffle_ps(t0, t2, _MM_SHUFFLE(1,0,1,0)); + __m256 py = _mm256_shuffle_ps(t0, t2, _MM_SHUFFLE(3,2,3,2)); + __m256 pz = _mm256_shuffle_ps(t1, t3, _MM_SHUFFLE(1,0,1,0)); + __m256 nx = _mm256_shuffle_ps(t1, t3, _MM_SHUFFLE(3,2,3,2)); + __m256 ny = _mm256_shuffle_ps(t4, t6, _MM_SHUFFLE(1,0,1,0)); + __m256 nz = _mm256_shuffle_ps(t4, t6, _MM_SHUFFLE(3,2,3,2)); + __m256 tx = _mm256_shuffle_ps(t5, t7, _MM_SHUFFLE(1,0,1,0)); + __m256 ty = _mm256_shuffle_ps(t5, t7, _MM_SHUFFLE(3,2,3,2)); + + __m256 tz = _mm256_i32gather_ps(unpacked[i+0], _mm256_setr_epi32(8,17,26,35,44,53,62,71), sizeof(float)); + + // abs(pos) + __m256 apx = _mm256_andnot_ps(_mm256_set1_ps(-0.0f), px); + __m256 apy = _mm256_andnot_ps(_mm256_set1_ps(-0.0f), py); + __m256 apz = _mm256_andnot_ps(_mm256_set1_ps(-0.0f), pz); + + // len = compMax(abs(pos)) + __m256 len = _mm256_max_ps(_mm256_max_ps(apx, apy), apz); + + // detect zeros + __m256 mask = _mm256_cmp_ps(len, _mm256_setzero_ps(), _CMP_EQ_OQ); + + // rcp = 1.0f / len + __m256 rcp = _mm256_div_ps(_mm256_set1_ps(1.0f), len); + + // replace +inf with 1.0f + rcp = _mm256_blendv_ps(rcp, _mm256_set1_ps(1.0f), mask); + len = _mm256_blendv_ps(len, _mm256_set1_ps(1.0f), mask); + + // pos *= 1.0f / len + px = _mm256_mul_ps(px, rcp); + py = _mm256_mul_ps(py, rcp); + pz = _mm256_mul_ps(pz, rcp); + + // clamp(vec, -1.0f, 1.0f) + px = _mm256_min_ps(_mm256_max_ps(px, _mm256_set1_ps(-1.0f)), _mm256_set1_ps(1.0f)); + py = _mm256_min_ps(_mm256_max_ps(py, _mm256_set1_ps(-1.0f)), _mm256_set1_ps(1.0f)); + pz = _mm256_min_ps(_mm256_max_ps(pz, _mm256_set1_ps(-1.0f)), _mm256_set1_ps(1.0f)); + nx = _mm256_min_ps(_mm256_max_ps(nx, _mm256_set1_ps(-1.0f)), _mm256_set1_ps(1.0f)); + ny = _mm256_min_ps(_mm256_max_ps(ny, _mm256_set1_ps(-1.0f)), _mm256_set1_ps(1.0f)); + nz = _mm256_min_ps(_mm256_max_ps(nz, _mm256_set1_ps(-1.0f)), _mm256_set1_ps(1.0f)); + tx = _mm256_min_ps(_mm256_max_ps(tx, _mm256_set1_ps(-1.0f)), _mm256_set1_ps(1.0f)); + ty = _mm256_min_ps(_mm256_max_ps(ty, _mm256_set1_ps(-1.0f)), _mm256_set1_ps(1.0f)); + tz = _mm256_min_ps(_mm256_max_ps(tz, _mm256_set1_ps(-1.0f)), _mm256_set1_ps(1.0f)); + + // vec *= 511.0f + px = _mm256_mul_ps(px, _mm256_set1_ps(511.0f)); + py = _mm256_mul_ps(py, _mm256_set1_ps(511.0f)); + pz = _mm256_mul_ps(pz, _mm256_set1_ps(511.0f)); + nx = _mm256_mul_ps(nx, _mm256_set1_ps(511.0f)); + ny = _mm256_mul_ps(ny, _mm256_set1_ps(511.0f)); + nz = _mm256_mul_ps(nz, _mm256_set1_ps(511.0f)); + tx = _mm256_mul_ps(tx, _mm256_set1_ps(511.0f)); + ty = _mm256_mul_ps(ty, _mm256_set1_ps(511.0f)); + tz = _mm256_mul_ps(tz, _mm256_set1_ps(511.0f)); + + // veci = lrint(vec) & 03ff + __m256i pxi = _mm256_and_si256(_mm256_cvtps_epi32(px), _mm256_set1_epi32(0x3ff)); + __m256i pyi = _mm256_and_si256(_mm256_cvtps_epi32(py), _mm256_set1_epi32(0x3ff)); + __m256i pzi = _mm256_and_si256(_mm256_cvtps_epi32(pz), _mm256_set1_epi32(0x3ff)); + __m256i nxi = _mm256_and_si256(_mm256_cvtps_epi32(nx), _mm256_set1_epi32(0x3ff)); + __m256i nyi = _mm256_and_si256(_mm256_cvtps_epi32(ny), _mm256_set1_epi32(0x3ff)); + __m256i nzi = _mm256_and_si256(_mm256_cvtps_epi32(nz), _mm256_set1_epi32(0x3ff)); + __m256i txi = _mm256_and_si256(_mm256_cvtps_epi32(tx), _mm256_set1_epi32(0x3ff)); + __m256i tyi = _mm256_and_si256(_mm256_cvtps_epi32(ty), _mm256_set1_epi32(0x3ff)); + __m256i tzi = _mm256_and_si256(_mm256_cvtps_epi32(tz), _mm256_set1_epi32(0x3ff)); + + // pack = (xi << 0) | (yi << 10) | (zi << 20); + __m256i li = _mm256_castps_si256(len); // length + __m256i pi = _mm256_or_si256(_mm256_or_si256(pxi, _mm256_slli_epi32(pyi, 10)), _mm256_slli_epi32(pzi, 20)); // position + __m256i ni = _mm256_or_si256(_mm256_or_si256(nxi, _mm256_slli_epi32(nyi, 10)), _mm256_slli_epi32(nzi, 20)); // normal + __m256i ti = _mm256_or_si256(_mm256_or_si256(txi, _mm256_slli_epi32(tyi, 10)), _mm256_slli_epi32(tzi, 20)); // tangent + + // + // interleave (4x4 matrix transpose) + // + __m256i u0 = _mm256_unpacklo_epi32(li, pi); + __m256i u1 = _mm256_unpackhi_epi32(li, pi); + __m256i u2 = _mm256_unpacklo_epi32(ni, ti); + __m256i u3 = _mm256_unpackhi_epi32(ni, ti); + + __m256i v0 = _mm256_unpacklo_epi64(u0, u2); + __m256i v1 = _mm256_unpackhi_epi64(u0, u2); + __m256i v2 = _mm256_unpacklo_epi64(u1, u3); + __m256i v3 = _mm256_unpackhi_epi64(u1, u3); + + __m256i w0 = _mm256_permute2f128_si256(v0, v1, 0x20); + __m256i w1 = _mm256_permute2f128_si256(v2, v3, 0x20); + __m256i w2 = _mm256_permute2f128_si256(v0, v1, 0x31); + __m256i w3 = _mm256_permute2f128_si256(v2, v3, 0x31); + + // store pack x 8 + _mm256_storeu_si256((__m256i*)packed[i+0], w0); + _mm256_storeu_si256((__m256i*)packed[i+2], w1); + _mm256_storeu_si256((__m256i*)packed[i+4], w2); + _mm256_storeu_si256((__m256i*)packed[i+6], w3); + } + + if (i < size) { // remainder + int rem = size - i; + + // + // deinterleave (8x9 to 9x8 matrix transpose) + // + __m256 s0 = _mm256_setzero_ps(); + __m256 s1 = _mm256_setzero_ps(); + __m256 s2 = _mm256_setzero_ps(); + __m256 s3 = _mm256_setzero_ps(); + __m256 s4 = _mm256_setzero_ps(); + __m256 s5 = _mm256_setzero_ps(); + __m256 s6 = _mm256_setzero_ps(); + __m256 s7 = _mm256_setzero_ps(); + + switch (rem) { + case 7: s6 = _mm256_loadu_ps(unpacked[i+6]); + case 6: s5 = _mm256_loadu_ps(unpacked[i+5]); + case 5: s4 = _mm256_loadu_ps(unpacked[i+4]); + case 4: s3 = _mm256_loadu_ps(unpacked[i+3]); + case 3: s2 = _mm256_loadu_ps(unpacked[i+2]); + case 2: s1 = _mm256_loadu_ps(unpacked[i+1]); + case 1: s0 = _mm256_loadu_ps(unpacked[i+0]); + } + + __m256 t0 = _mm256_unpacklo_ps(s0, s1); + __m256 t1 = _mm256_unpackhi_ps(s0, s1); + __m256 t2 = _mm256_unpacklo_ps(s2, s3); + __m256 t3 = _mm256_unpackhi_ps(s2, s3); + __m256 t4 = _mm256_unpacklo_ps(s4, s5); + __m256 t5 = _mm256_unpackhi_ps(s4, s5); + __m256 t6 = _mm256_unpacklo_ps(s6, s7); + __m256 t7 = _mm256_unpackhi_ps(s6, s7); + + s0 = _mm256_shuffle_ps(t0, t2, _MM_SHUFFLE(1,0,1,0)); + s1 = _mm256_shuffle_ps(t0, t2, _MM_SHUFFLE(3,2,3,2)); + s2 = _mm256_shuffle_ps(t1, t3, _MM_SHUFFLE(1,0,1,0)); + s3 = _mm256_shuffle_ps(t1, t3, _MM_SHUFFLE(3,2,3,2)); + s4 = _mm256_shuffle_ps(t4, t6, _MM_SHUFFLE(1,0,1,0)); + s5 = _mm256_shuffle_ps(t4, t6, _MM_SHUFFLE(3,2,3,2)); + s6 = _mm256_shuffle_ps(t5, t7, _MM_SHUFFLE(1,0,1,0)); + s7 = _mm256_shuffle_ps(t5, t7, _MM_SHUFFLE(3,2,3,2)); + + __m256 px = _mm256_permute2f128_ps(s0, s4, 0x20); + __m256 py = _mm256_permute2f128_ps(s1, s5, 0x20); + __m256 pz = _mm256_permute2f128_ps(s2, s6, 0x20); + __m256 nx = _mm256_permute2f128_ps(s3, s7, 0x20); + __m256 ny = _mm256_permute2f128_ps(s0, s4, 0x31); + __m256 nz = _mm256_permute2f128_ps(s1, s5, 0x31); + __m256 tx = _mm256_permute2f128_ps(s2, s6, 0x31); + __m256 ty = _mm256_permute2f128_ps(s3, s7, 0x31); + + __m256i loadmask = _mm256_cvtepi8_epi32(_mm_cvtsi64_si128(0xffffffffffffffffULL >> (64 - 8 * rem))); + __m256 tz = _mm256_mask_i32gather_ps(_mm256_setzero_ps(), unpacked[i+0], _mm256_setr_epi32(8,17,26,35,44,53,62,71), + _mm256_castsi256_ps(loadmask), sizeof(float)); + // abs(pos) + __m256 apx = _mm256_andnot_ps(_mm256_set1_ps(-0.0f), px); + __m256 apy = _mm256_andnot_ps(_mm256_set1_ps(-0.0f), py); + __m256 apz = _mm256_andnot_ps(_mm256_set1_ps(-0.0f), pz); + + // len = compMax(abs(pos)) + __m256 len = _mm256_max_ps(_mm256_max_ps(apx, apy), apz); + + // detect zeros + __m256 mask = _mm256_cmp_ps(len, _mm256_setzero_ps(), _CMP_EQ_OQ); + + // rcp = 1.0f / len + __m256 rcp = _mm256_div_ps(_mm256_set1_ps(1.0f), len); + + // replace +inf with 1.0f + rcp = _mm256_blendv_ps(rcp, _mm256_set1_ps(1.0f), mask); + len = _mm256_blendv_ps(len, _mm256_set1_ps(1.0f), mask); + + // pos *= 1.0f / len + px = _mm256_mul_ps(px, rcp); + py = _mm256_mul_ps(py, rcp); + pz = _mm256_mul_ps(pz, rcp); + + // clamp(vec, -1.0f, 1.0f) + px = _mm256_min_ps(_mm256_max_ps(px, _mm256_set1_ps(-1.0f)), _mm256_set1_ps(1.0f)); + py = _mm256_min_ps(_mm256_max_ps(py, _mm256_set1_ps(-1.0f)), _mm256_set1_ps(1.0f)); + pz = _mm256_min_ps(_mm256_max_ps(pz, _mm256_set1_ps(-1.0f)), _mm256_set1_ps(1.0f)); + nx = _mm256_min_ps(_mm256_max_ps(nx, _mm256_set1_ps(-1.0f)), _mm256_set1_ps(1.0f)); + ny = _mm256_min_ps(_mm256_max_ps(ny, _mm256_set1_ps(-1.0f)), _mm256_set1_ps(1.0f)); + nz = _mm256_min_ps(_mm256_max_ps(nz, _mm256_set1_ps(-1.0f)), _mm256_set1_ps(1.0f)); + tx = _mm256_min_ps(_mm256_max_ps(tx, _mm256_set1_ps(-1.0f)), _mm256_set1_ps(1.0f)); + ty = _mm256_min_ps(_mm256_max_ps(ty, _mm256_set1_ps(-1.0f)), _mm256_set1_ps(1.0f)); + tz = _mm256_min_ps(_mm256_max_ps(tz, _mm256_set1_ps(-1.0f)), _mm256_set1_ps(1.0f)); + + // vec *= 511.0f + px = _mm256_mul_ps(px, _mm256_set1_ps(511.0f)); + py = _mm256_mul_ps(py, _mm256_set1_ps(511.0f)); + pz = _mm256_mul_ps(pz, _mm256_set1_ps(511.0f)); + nx = _mm256_mul_ps(nx, _mm256_set1_ps(511.0f)); + ny = _mm256_mul_ps(ny, _mm256_set1_ps(511.0f)); + nz = _mm256_mul_ps(nz, _mm256_set1_ps(511.0f)); + tx = _mm256_mul_ps(tx, _mm256_set1_ps(511.0f)); + ty = _mm256_mul_ps(ty, _mm256_set1_ps(511.0f)); + tz = _mm256_mul_ps(tz, _mm256_set1_ps(511.0f)); + + // veci = lrint(vec) & 03ff + __m256i pxi = _mm256_and_si256(_mm256_cvtps_epi32(px), _mm256_set1_epi32(0x3ff)); + __m256i pyi = _mm256_and_si256(_mm256_cvtps_epi32(py), _mm256_set1_epi32(0x3ff)); + __m256i pzi = _mm256_and_si256(_mm256_cvtps_epi32(pz), _mm256_set1_epi32(0x3ff)); + __m256i nxi = _mm256_and_si256(_mm256_cvtps_epi32(nx), _mm256_set1_epi32(0x3ff)); + __m256i nyi = _mm256_and_si256(_mm256_cvtps_epi32(ny), _mm256_set1_epi32(0x3ff)); + __m256i nzi = _mm256_and_si256(_mm256_cvtps_epi32(nz), _mm256_set1_epi32(0x3ff)); + __m256i txi = _mm256_and_si256(_mm256_cvtps_epi32(tx), _mm256_set1_epi32(0x3ff)); + __m256i tyi = _mm256_and_si256(_mm256_cvtps_epi32(ty), _mm256_set1_epi32(0x3ff)); + __m256i tzi = _mm256_and_si256(_mm256_cvtps_epi32(tz), _mm256_set1_epi32(0x3ff)); + + // pack = (xi << 0) | (yi << 10) | (zi << 20); + __m256i li = _mm256_castps_si256(len); // length + __m256i pi = _mm256_or_si256(_mm256_or_si256(pxi, _mm256_slli_epi32(pyi, 10)), _mm256_slli_epi32(pzi, 20)); // position + __m256i ni = _mm256_or_si256(_mm256_or_si256(nxi, _mm256_slli_epi32(nyi, 10)), _mm256_slli_epi32(nzi, 20)); // normal + __m256i ti = _mm256_or_si256(_mm256_or_si256(txi, _mm256_slli_epi32(tyi, 10)), _mm256_slli_epi32(tzi, 20)); // tangent + + // + // interleave (4x4 matrix transpose) + // + __m256i u0 = _mm256_unpacklo_epi32(li, pi); + __m256i u1 = _mm256_unpackhi_epi32(li, pi); + __m256i u2 = _mm256_unpacklo_epi32(ni, ti); + __m256i u3 = _mm256_unpackhi_epi32(ni, ti); + + __m256i v0 = _mm256_unpacklo_epi64(u0, u2); + __m256i v1 = _mm256_unpackhi_epi64(u0, u2); + __m256i v2 = _mm256_unpacklo_epi64(u1, u3); + __m256i v3 = _mm256_unpackhi_epi64(u1, u3); + + // store pack x 8 + switch (rem) { + case 7: _mm_storeu_si128((__m128i*)packed[i+6], _mm256_extractf128_si256(v2, 1)); + case 6: _mm_storeu_si128((__m128i*)packed[i+5], _mm256_extractf128_si256(v1, 1)); + case 5: _mm_storeu_si128((__m128i*)packed[i+4], _mm256_extractf128_si256(v0, 1)); + case 4: _mm_storeu_si128((__m128i*)packed[i+3], _mm256_castsi256_si128(v3)); + case 3: _mm_storeu_si128((__m128i*)packed[i+2], _mm256_castsi256_si128(v2)); + case 2: _mm_storeu_si128((__m128i*)packed[i+1], _mm256_castsi256_si128(v1)); + case 1: _mm_storeu_si128((__m128i*)packed[i+0], _mm256_castsi256_si128(v0)); + } + } + + _mm256_zeroupper(); +} + +#endif From 87e0f5b2bba804f892741217a893e345f6283b53 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Sun, 23 Jun 2019 10:40:15 -0700 Subject: [PATCH 09/21] Runtime dispatch for AVX2 --- libraries/render-utils/src/Model.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 67f64395b2..164090709a 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1716,14 +1716,29 @@ static void packBlendshapeOffsets_ref(BlendshapeOffsetUnpacked* unpacked, Blends } } +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) +// +// Runtime CPU dispatch +// +#include "CPUDetect.h" + void packBlendshapeOffsets_AVX2(float (*unpacked)[9], uint32_t (*packed)[4], int size); static void packBlendshapeOffsets(BlendshapeOffsetUnpacked* unpacked, BlendshapeOffsetPacked* packed, int size) { - static_assert(sizeof(BlendshapeOffsetUnpacked) == 9 * sizeof(float), "struct BlendshapeOffsetUnpacked size doesn't match."); - static_assert(sizeof(BlendshapeOffsetPacked) == 4 * sizeof(uint32_t), "struct BlendshapeOffsetPacked size doesn't match."); - packBlendshapeOffsets_AVX2((float(*)[9])unpacked, (uint32_t(*)[4])packed, size); + static bool _cpuSupportsAVX2 = cpuSupportsAVX2(); + if (_cpuSupportsAVX2) { + static_assert(sizeof(BlendshapeOffsetUnpacked) == 9 * sizeof(float), "struct BlendshapeOffsetUnpacked size doesn't match."); + static_assert(sizeof(BlendshapeOffsetPacked) == 4 * sizeof(uint32_t), "struct BlendshapeOffsetPacked size doesn't match."); + packBlendshapeOffsets_AVX2((float(*)[9])unpacked, (uint32_t(*)[4])packed, size); + } else { + packBlendshapeOffsets_ref(unpacked, packed, size); + } } +#else // portable reference code +static auto& packBlendshapeOffsets = packBlendshapeOffsets_ref; +#endif + class Blender : public QRunnable { public: From 75aea88f200b0b3cf716aba5aa1871739701097d Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Mon, 24 Jun 2019 11:51:03 -0700 Subject: [PATCH 10/21] CR feedback --- libraries/render-utils/src/Model.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 164090709a..11c1e42fd4 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1720,7 +1720,7 @@ static void packBlendshapeOffsets_ref(BlendshapeOffsetUnpacked* unpacked, Blends // // Runtime CPU dispatch // -#include "CPUDetect.h" +#include void packBlendshapeOffsets_AVX2(float (*unpacked)[9], uint32_t (*packed)[4], int size); From e39ccff873465dd98e0e05e2323ab71f8db77234 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Mon, 24 Jun 2019 11:57:37 -0700 Subject: [PATCH 11/21] BUGZ-812 - Log system info on domain connect or connect refusal --- domain-server/src/DomainGatekeeper.cpp | 3 +- domain-server/src/NodeConnectionData.cpp | 6 +++- libraries/networking/CMakeLists.txt | 2 +- libraries/networking/src/NodeList.cpp | 30 +++++++++++-------- .../networking/src/ThreadedAssignment.cpp | 11 +++++++ libraries/networking/src/ThreadedAssignment.h | 2 +- .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 3 +- 8 files changed, 40 insertions(+), 19 deletions(-) diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index 6d339852d5..6aaa348f6c 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -136,7 +136,8 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointergetSenderSockAddr() << "with hardware address" << nodeConnection.hardwareAddress - << "and machine fingerprint" << nodeConnection.machineFingerprint; + << "and machine fingerprint" << nodeConnection.machineFingerprint + << "sysinfo" << nodeConnection.SystemInfo; } } diff --git a/domain-server/src/NodeConnectionData.cpp b/domain-server/src/NodeConnectionData.cpp index 9703db39c8..e3406aa797 100644 --- a/domain-server/src/NodeConnectionData.cpp +++ b/domain-server/src/NodeConnectionData.cpp @@ -37,7 +37,11 @@ NodeConnectionData NodeConnectionData::fromDataStream(QDataStream& dataStream, c dataStream >> newHeader.machineFingerprint; // and the operating system type - dataStream >> newHeader.SystemInfo; + QByteArray compressedSystemInfo; + dataStream >> compressedSystemInfo; + if(!compressedSystemInfo.isEmpty()) { + newHeader.SystemInfo = qUncompress(compressedSystemInfo); + } dataStream >> newHeader.connectReason; diff --git a/libraries/networking/CMakeLists.txt b/libraries/networking/CMakeLists.txt index c3592c5da2..9f63f2cb00 100644 --- a/libraries/networking/CMakeLists.txt +++ b/libraries/networking/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME networking) setup_hifi_library(Network) -link_hifi_libraries(shared) +link_hifi_libraries(shared platform) target_openssl() target_tbb() diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 96b713c583..0dad7705f8 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include "AccountManager.h" #include "AddressManager.h" @@ -42,6 +44,7 @@ using namespace std::chrono; const int KEEPALIVE_PING_INTERVAL_MS = 1000; +const int MAX_SYSTEM_INFO_SIZE = 1000; NodeList::NodeList(char newOwnerType, int socketListenPort, int dtlsListenPort) : LimitedNodeList(socketListenPort, dtlsListenPort), @@ -418,19 +421,20 @@ void NodeList::sendDomainServerCheckIn() { auto accountManager = DependencyManager::get(); packetStream << FingerprintUtils::getMachineFingerprint(); - QString systemInfo; -#if defined Q_OS_WIN - systemInfo = "OS:Windows"; -#elif defined Q_OS_OSX - systemInfo = "OS:OSX"; -#elif defined Q_OS_LINUX - systemInfo = "OS:Linux"; -#elif defined Q_OS_ANDROID - systemInfo = "OS:Android"; -#else - systemInfo = "OS:Unknown"; -#endif - packetStream << systemInfo; + auto desc = platform::getAll(); + + QByteArray systemInfo(desc.dump().c_str()); + QByteArray compressedSystemInfo = qCompress(systemInfo); + + if(compressedSystemInfo.size() > MAX_SYSTEM_INFO_SIZE) { + // Highly unlikely, as not even unreasonable machines will + // overflow the max size, but prevent MTU overflow anyway. + // We could do something sophisticated like clearing specific + // values if they're too big, but we'll save that for later. + compressedSystemInfo.clear(); + } + + packetStream << compressedSystemInfo; packetStream << _connectReason; diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index 2b415073f2..b8a8f65080 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -20,6 +20,7 @@ #include #include +#include #include "NetworkLogging.h" ThreadedAssignment::ThreadedAssignment(ReceivedMessage& message) : @@ -38,6 +39,16 @@ ThreadedAssignment::ThreadedAssignment(ReceivedMessage& message) : // if the NL tells us we got a DS response, clear our member variable of queued check-ins auto nodeList = DependencyManager::get(); connect(nodeList.data(), &NodeList::receivedDomainServerList, this, &ThreadedAssignment::clearQueuedCheckIns); + + platform::create(); + if (!platform::enumeratePlatform()) { + qCDebug(networking) << "Failed to enumerate platform."; + } +} + +ThreadedAssignment::~ThreadedAssignment() { + stop(); + platform::destroy(); } void ThreadedAssignment::setFinished(bool isFinished) { diff --git a/libraries/networking/src/ThreadedAssignment.h b/libraries/networking/src/ThreadedAssignment.h index e76533b2a1..12096cf23f 100644 --- a/libraries/networking/src/ThreadedAssignment.h +++ b/libraries/networking/src/ThreadedAssignment.h @@ -22,7 +22,7 @@ class ThreadedAssignment : public Assignment { Q_OBJECT public: ThreadedAssignment(ReceivedMessage& message); - ~ThreadedAssignment() { stop(); } + ~ThreadedAssignment(); virtual void aboutToFinish() { }; void addPacketStatsAndSendStatsPacket(QJsonObject statsObject); diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index e434867c9a..ed68fe89dc 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -72,7 +72,7 @@ PacketVersion versionForPacketType(PacketType packetType) { return static_cast(DomainConnectionDeniedVersion::IncludesExtraInfo); case PacketType::DomainConnectRequest: - return static_cast(DomainConnectRequestVersion::HasSystemInfo); + return static_cast(DomainConnectRequestVersion::HasCompressedSystemInfo); case PacketType::DomainServerAddedNode: return static_cast(DomainServerAddedNodeVersion::PermissionsGrid); diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index a244399c5a..6230b8b11e 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -347,7 +347,8 @@ enum class DomainConnectRequestVersion : PacketVersion { AlwaysHasMachineFingerprint, HasTimestamp, HasReason, - HasSystemInfo + HasSystemInfo, + HasCompressedSystemInfo }; enum class DomainConnectionDeniedVersion : PacketVersion { From 3e2e020731b8be785ea6d0ddbc1917b5b940cb8d Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 24 Jun 2019 12:48:13 -0700 Subject: [PATCH 12/21] BUGZ-746: About tab: Better CPU/GPU info reporting; New copied info (including OS version) --- .../simplifiedUI/settingsApp/about/About.qml | 49 +++++++++++++++++-- .../simplifiedControls/Button.qml | 30 ++++++++++++ 2 files changed, 74 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/hifi/simplifiedUI/settingsApp/about/About.qml b/interface/resources/qml/hifi/simplifiedUI/settingsApp/about/About.qml index 76ab762a6b..3e3758e7a8 100644 --- a/interface/resources/qml/hifi/simplifiedUI/settingsApp/about/About.qml +++ b/interface/resources/qml/hifi/simplifiedUI/settingsApp/about/About.qml @@ -122,12 +122,22 @@ Flickable { } HifiStylesUit.GraphikRegular { - text: "CPU: " + PlatformInfo.getCPUBrand() + text: "CPU:" Layout.maximumWidth: parent.width height: paintedHeight size: 16 color: simplifiedUI.colors.text.white wrapMode: Text.Wrap + + Component.onCompleted: { + var cpu = JSON.parse(PlatformInfo.getCPU(0)); + var cpuModel = cpu.model; + if (cpuModel.length === 0) { + cpuModel = "Unknown"; + } + + text = "CPU: " + cpuModel; + } } HifiStylesUit.GraphikRegular { @@ -158,12 +168,22 @@ Flickable { } HifiStylesUit.GraphikRegular { - text: "GPU: " + PlatformInfo.getGraphicsCardType() + text: "GPU: " Layout.maximumWidth: parent.width height: paintedHeight size: 16 color: simplifiedUI.colors.text.white wrapMode: Text.Wrap + + Component.onCompleted: { + var gpu = JSON.parse(PlatformInfo.getGPU(0)); + var gpuModel = gpu.model; + if (gpuModel.length === 0) { + gpuModel = "Unknown"; + } + + text = "GPU: " + gpuModel; + } } HifiStylesUit.GraphikRegular { @@ -180,9 +200,11 @@ Flickable { width: 200 height: 32 text: "Copy to Clipboard" + temporaryText: "Copied!" onClicked: { Window.copyToClipboard(root.buildPlatformInfoTextToCopy()); + showTemporaryText(); } } } @@ -206,12 +228,29 @@ Flickable { textToCopy += "Computer Vendor/Model: " + computerVendor + "/" + computerModel + "\n"; textToCopy += "Profiled Platform Tier: " + PlatformInfo.getTierProfiled() + "\n"; textToCopy += "OS Type: " + PlatformInfo.getOperatingSystemType() + "\n"; - textToCopy += "CPU: " + PlatformInfo.getCPUBrand() + "\n"; + + var cpu = JSON.parse(PlatformInfo.getCPU(0)); + var cpuModel = cpu.model; + if (cpuModel.length === 0) { + cpuModel = "Unknown"; + } + + textToCopy += "CPU: " + cpuModel + "\n"; textToCopy += "# CPUs: " + PlatformInfo.getNumCPUs() + "\n"; textToCopy += "# CPU Cores: " + PlatformInfo.getNumLogicalCores() + "\n"; textToCopy += "RAM: " + PlatformInfo.getTotalSystemMemoryMB() + " MB\n"; - textToCopy += "GPU: " + PlatformInfo.getGraphicsCardType() + "\n"; - textToCopy += "VR Hand Controllers: " + (PlatformInfo.hasRiftControllers() ? "Rift" : (PlatformInfo.hasViveControllers() ? "Vive" : "None")); + + var gpu = JSON.parse(PlatformInfo.getGPU(0)); + var gpuModel = gpu.model; + if (gpuModel.length === 0) { + gpuModel = "Unknown"; + } + + textToCopy += "GPU: " + gpuModel + "\n"; + textToCopy += "VR Hand Controllers: " + (PlatformInfo.hasRiftControllers() ? "Rift" : (PlatformInfo.hasViveControllers() ? "Vive" : "None")) + "\n"; + + textToCopy += "\n**All Platform Info**\n"; + textToCopy += JSON.stringify(JSON.parse(PlatformInfo.getPlatform()), null, 4); return textToCopy; } diff --git a/interface/resources/qml/hifi/simplifiedUI/simplifiedControls/Button.qml b/interface/resources/qml/hifi/simplifiedUI/simplifiedControls/Button.qml index 313daab704..1d594a0d6d 100644 --- a/interface/resources/qml/hifi/simplifiedUI/simplifiedControls/Button.qml +++ b/interface/resources/qml/hifi/simplifiedUI/simplifiedControls/Button.qml @@ -16,6 +16,9 @@ import TabletScriptingInterface 1.0 Original.Button { id: root + // The two properties below are used when calling showTemporaryText() + property string originalText: "" + property string temporaryText: "" SimplifiedConstants.SimplifiedConstants { id: simplifiedUI @@ -103,4 +106,31 @@ Original.Button { horizontalAlignment: Text.AlignHCenter text: root.text } + + Timer { + id: showTemporaryTextTimer + interval: 1500 + repeat: false + running: false + + onTriggered: { + buttonText.text = root.originalText; + root.originalText = ""; + } + } + + function showTemporaryText() { + if (root.temporaryText === "") { + return; + } + + if (showTemporaryTextTimer.running) { + showTemporaryTextTimer.restart(); + return; + } + + root.originalText = buttonText.text; + buttonText.text = root.temporaryText; + showTemporaryTextTimer.start(); + } } From 541d45012a0677f65757e1e84add0654ba3b2872 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Mon, 24 Jun 2019 12:54:58 -0700 Subject: [PATCH 13/21] Move BlendshapePacking_avx2.cpp to shared --- .../{render-utils => shared}/src/avx2/BlendshapePacking_avx2.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename libraries/{render-utils => shared}/src/avx2/BlendshapePacking_avx2.cpp (100%) diff --git a/libraries/render-utils/src/avx2/BlendshapePacking_avx2.cpp b/libraries/shared/src/avx2/BlendshapePacking_avx2.cpp similarity index 100% rename from libraries/render-utils/src/avx2/BlendshapePacking_avx2.cpp rename to libraries/shared/src/avx2/BlendshapePacking_avx2.cpp From 2322df5a5930f436fcf43389a906f97f638f71b0 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Mon, 24 Jun 2019 12:57:42 -0700 Subject: [PATCH 14/21] Add unit-test to validate AVX2 --- tests/shared/src/BlendshapePackingTests.cpp | 148 ++++++++++++++++++++ tests/shared/src/BlendshapePackingTests.h | 23 +++ 2 files changed, 171 insertions(+) create mode 100644 tests/shared/src/BlendshapePackingTests.cpp create mode 100644 tests/shared/src/BlendshapePackingTests.h diff --git a/tests/shared/src/BlendshapePackingTests.cpp b/tests/shared/src/BlendshapePackingTests.cpp new file mode 100644 index 0000000000..a751a5ca02 --- /dev/null +++ b/tests/shared/src/BlendshapePackingTests.cpp @@ -0,0 +1,148 @@ +// +// BlendshapePackingTests.cpp +// tests/shared/src +// +// Created by Ken Cooke on 6/24/19. +// Copyright 2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "BlendshapePackingTests.h" + +#include + +#include + +#include +#include + +struct BlendshapeOffsetUnpacked { + glm::vec3 positionOffset; + glm::vec3 normalOffset; + glm::vec3 tangentOffset; +}; + +struct BlendshapeOffsetPacked { + glm::uvec4 packedPosNorTan; +}; + +QTEST_MAIN(BlendshapePackingTests) + +static void packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10(glm::uvec4& packed, const BlendshapeOffsetUnpacked& unpacked) { + float len = glm::compMax(glm::abs(unpacked.positionOffset)); + glm::vec3 normalizedPos(unpacked.positionOffset); + if (len > 0.0f) { + normalizedPos /= len; + } else { + len = 1.0f; + } + + packed = glm::uvec4( + glm::floatBitsToUint(len), + glm_packSnorm3x10_1x2(glm::vec4(normalizedPos, 0.0f)), + glm_packSnorm3x10_1x2(glm::vec4(unpacked.normalOffset, 0.0f)), + glm_packSnorm3x10_1x2(glm::vec4(unpacked.tangentOffset, 0.0f)) + ); +} + +static void packBlendshapeOffsets_ref(BlendshapeOffsetUnpacked* unpacked, BlendshapeOffsetPacked* packed, int size) { + for (int i = 0; i < size; ++i) { + packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10((*packed).packedPosNorTan, (*unpacked)); + ++unpacked; + ++packed; + } +} + +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) +// +// Runtime CPU dispatch +// +#include + +void packBlendshapeOffsets_AVX2(float (*unpacked)[9], uint32_t (*packed)[4], int size); + +static void packBlendshapeOffsets(BlendshapeOffsetUnpacked* unpacked, BlendshapeOffsetPacked* packed, int size) { + static bool _cpuSupportsAVX2 = cpuSupportsAVX2(); + if (_cpuSupportsAVX2) { + static_assert(sizeof(BlendshapeOffsetUnpacked) == 9 * sizeof(float), "struct BlendshapeOffsetUnpacked size doesn't match."); + static_assert(sizeof(BlendshapeOffsetPacked) == 4 * sizeof(uint32_t), "struct BlendshapeOffsetPacked size doesn't match."); + packBlendshapeOffsets_AVX2((float(*)[9])unpacked, (uint32_t(*)[4])packed, size); + } else { + packBlendshapeOffsets_ref(unpacked, packed, size); + } +} + +#else // portable reference code +static auto& packBlendshapeOffsets = packBlendshapeOffsets_ref; +#endif + +void comparePacked(BlendshapeOffsetPacked& ref, BlendshapeOffsetPacked& tst) { + union i10i10i10i2 { + struct { + int x : 10; + int y : 10; + int z : 10; + int w : 2; + } data; + uint32_t pack; + } Ref[4], Tst[4]; + + for (int i = 0; i < 4; i++) { + Ref[i].pack = ref.packedPosNorTan[i]; + Tst[i].pack = tst.packedPosNorTan[i]; + } + + // allow 1 ULP due to rounding differences + QCOMPARE_WITH_ABS_ERROR(Tst[0].pack, Ref[0].pack, 1); + + QCOMPARE_WITH_ABS_ERROR(Tst[1].data.x, Ref[1].data.x, 1); + QCOMPARE_WITH_ABS_ERROR(Tst[1].data.y, Ref[1].data.y, 1); + QCOMPARE_WITH_ABS_ERROR(Tst[1].data.z, Ref[1].data.z, 1); + + QCOMPARE_WITH_ABS_ERROR(Tst[2].data.x, Ref[2].data.x, 1); + QCOMPARE_WITH_ABS_ERROR(Tst[2].data.y, Ref[2].data.y, 1); + QCOMPARE_WITH_ABS_ERROR(Tst[2].data.z, Ref[2].data.z, 1); + + QCOMPARE_WITH_ABS_ERROR(Tst[3].data.x, Ref[3].data.x, 1); + QCOMPARE_WITH_ABS_ERROR(Tst[3].data.y, Ref[3].data.y, 1); + QCOMPARE_WITH_ABS_ERROR(Tst[3].data.z, Ref[3].data.z, 1); +} + +void BlendshapePackingTests::testAVX2() { + + for (int numBlendshapeOffsets = 0; numBlendshapeOffsets < 4096; ++numBlendshapeOffsets) { + + std::vector unpackedBlendshapeOffsets(numBlendshapeOffsets); + std::vector packedBlendshapeOffsets1(numBlendshapeOffsets); + std::vector packedBlendshapeOffsets2(numBlendshapeOffsets); + + // init test data + if (numBlendshapeOffsets > 0) { + unpackedBlendshapeOffsets[0] = { + glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f), + }; + } + for (int i = 1; i < numBlendshapeOffsets; ++i) { + unpackedBlendshapeOffsets[i] = { + glm::linearRand(glm::vec3(-2.0f, -2.0f, -2.0f), glm::vec3(2.0f, 2.0f, 2.0f)), + glm::linearRand(glm::vec3(-2.0f, -2.0f, -2.0f), glm::vec3(2.0f, 2.0f, 2.0f)), + glm::linearRand(glm::vec3(-2.0f, -2.0f, -2.0f), glm::vec3(2.0f, 2.0f, 2.0f)), + }; + } + + // ref version + packBlendshapeOffsets_ref(unpackedBlendshapeOffsets.data(), packedBlendshapeOffsets1.data(), numBlendshapeOffsets); + + // AVX2 version, if supported by CPU + packBlendshapeOffsets(unpackedBlendshapeOffsets.data(), packedBlendshapeOffsets2.data(), numBlendshapeOffsets); + + // verify + for (int i = 0; i < numBlendshapeOffsets; ++i) { + auto ref = packedBlendshapeOffsets1.at(i); + auto tst = packedBlendshapeOffsets2.at(i); + comparePacked(ref, tst); + } + } +} diff --git a/tests/shared/src/BlendshapePackingTests.h b/tests/shared/src/BlendshapePackingTests.h new file mode 100644 index 0000000000..d6d0ef8b10 --- /dev/null +++ b/tests/shared/src/BlendshapePackingTests.h @@ -0,0 +1,23 @@ +// +// BlendshapePackingTests.h +// tests/shared/src +// +// Created by Ken Cooke on 6/24/19. +// Copyright 2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_BlendshapePackingTests_h +#define hifi_BlendshapePackingTests_h + +#include + +class BlendshapePackingTests : public QObject { + Q_OBJECT +private slots: + void testAVX2(); +}; + +#endif // hifi_BlendshapePackingTests_h From aefa43bd116599a458b6cac467af42b9e7924cd7 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 24 Jun 2019 13:02:28 -0700 Subject: [PATCH 15/21] Prevent duplicates from accumulating in EntityTree::_needsParentFixup --- libraries/entities/src/EntityTree.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index dbc347631d..dca3ac595a 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -2121,9 +2121,10 @@ void EntityTree::fixupNeedsParentFixups() { _needsParentFixup.clear(); } + std::unordered_set seenEntityIds; QMutableVectorIterator iter(entitiesToFixup); while (iter.hasNext()) { - EntityItemWeakPointer entityWP = iter.next(); + const auto& entityWP = iter.next(); EntityItemPointer entity = entityWP.lock(); if (!entity) { // entity was deleted before we found its parent @@ -2131,6 +2132,17 @@ void EntityTree::fixupNeedsParentFixups() { continue; } + const auto id = entity->getID(); + // BUGZ-771 some entities seem to never be removed by the below logic and further seem to accumulate dupes within the _needsParentFixup list + // This block ensures that duplicates are removed from entitiesToFixup before it's re-appended to _needsParentFixup + if (0 != seenEntityIds.count(id)) { + // Entity was duplicated inside entitiesToFixup + iter.remove(); + continue; + } + + seenEntityIds.insert(id); + entity->requiresRecalcBoxes(); bool queryAACubeSuccess { false }; bool maxAACubeSuccess { false }; From 3c0c1413db22c19dc6bb77b733d69df46ca76f74 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Mon, 24 Jun 2019 14:12:25 -0700 Subject: [PATCH 16/21] fix apple build --- libraries/platform/CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libraries/platform/CMakeLists.txt b/libraries/platform/CMakeLists.txt index 70f3157e1e..55203d45a4 100644 --- a/libraries/platform/CMakeLists.txt +++ b/libraries/platform/CMakeLists.txt @@ -5,3 +5,11 @@ link_hifi_libraries(shared) GroupSources("src") target_json() + +if (APPLE) + # link in required OS X frameworks and include the right GL headers + find_library(OpenGL OpenGL) + find_library(AppKit AppKit) + + target_link_libraries(${TARGET_NAME} ${OpenGL} ${AppKit}) +endif () From 9ae67c15b233f873b50ff3e1235054283803bbc3 Mon Sep 17 00:00:00 2001 From: Matt Hardcastle Date: Mon, 24 Jun 2019 14:27:07 -0700 Subject: [PATCH 17/21] Use old API to launch tasks on all versions of macOS --- launchers/darwin/src/Interface.m | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/launchers/darwin/src/Interface.m b/launchers/darwin/src/Interface.m index b007e7faa5..d02b66b581 100644 --- a/launchers/darwin/src/Interface.m +++ b/launchers/darwin/src/Interface.m @@ -23,24 +23,14 @@ NSLog(@"calling interface at %@", self->pathTo); - if (@available(macOS 10.13, *)) { - NSError *error = nil; - if (![interface launchAndReturnError:&error]) { - *outError = [NSError errorWithDomain:@"interface" - code:-1 - userInfo:@{NSUnderlyingErrorKey: error}]; - return 0; - } - } else { - NSError *error = nil; - [interface launch]; - [interface waitUntilExit]; - if (0 != [interface terminationStatus]) { - *outError = [NSError errorWithDomain:@"interface" - code:-1 - userInfo:@{NSUnderlyingErrorKey: error}]; - return 0; - } + NSError *error = nil; + [interface launch]; + [interface waitUntilExit]; + if (0 != [interface terminationStatus]) { + *outError = [NSError errorWithDomain:@"interface" + code:-1 + userInfo:@{NSUnderlyingErrorKey: error}]; + return 0; } NSFileHandle * fh = [standardOut fileHandleForReading]; From c605c2917f1c7a60ec447980bd82094269b6d301 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 24 Jun 2019 11:04:01 -0700 Subject: [PATCH 18/21] trying to fix entity tree renderer performance --- .../src/EntityTreeRenderer.cpp | 52 ++++++++----------- .../src/EntityTreeRenderer.h | 2 +- libraries/shared/src/PrioritySortUtil.h | 2 +- 3 files changed, 24 insertions(+), 32 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 5ac6e4f642..5cb7b89de5 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -207,7 +207,7 @@ void EntityTreeRenderer::stopDomainAndNonOwnedEntities() { if (entityItem && !entityItem->getScript().isEmpty()) { if (!(entityItem->isLocalEntity() || (entityItem->isAvatarEntity() && entityItem->getOwningAvatarID() == getTree()->getMyAvatarSessionUUID()))) { - if (entityItem->contains(_avatarPosition)) { + if (_currentEntitiesInside.contains(entityID)) { _entitiesScriptEngine->callEntityScriptMethod(entityID, "leaveEntity"); } _entitiesScriptEngine->unloadEntityScript(entityID, true); @@ -222,6 +222,7 @@ void EntityTreeRenderer::clearDomainAndNonOwnedEntities() { auto sessionUUID = getTree()->getMyAvatarSessionUUID(); std::unordered_map savedEntities; + std::unordered_set savedRenderables; // remove all entities from the scene auto scene = _viewState->getMain3DScene(); if (scene) { @@ -232,11 +233,12 @@ void EntityTreeRenderer::clearDomainAndNonOwnedEntities() { fadeOutRenderable(renderer); } else { savedEntities[entry.first] = entry.second; + savedRenderables.insert(entry.second); } } } - _renderablesToUpdate = savedEntities; + _renderablesToUpdate = savedRenderables; _entitiesInScene = savedEntities; if (_layeredZones.clearDomainAndNonOwnedZones(sessionUUID)) { @@ -389,13 +391,7 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene PerformanceTimer pt("change"); std::unordered_set changedEntities; _changedEntitiesGuard.withWriteLock([&] { -#if 0 - // FIXME Weird build failure in latest VC update that fails to compile when using std::swap changedEntities.swap(_changedEntities); -#else - changedEntities.insert(_changedEntities.begin(), _changedEntities.end()); - _changedEntities.clear(); -#endif }); { @@ -404,7 +400,7 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene auto renderable = renderableForEntityId(entityId); if (renderable) { // only add valid renderables _renderablesToUpdate - _renderablesToUpdate.insert({ entityId, renderable }); + _renderablesToUpdate.insert(renderable); } } } @@ -414,8 +410,7 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene // we expect to update all renderables within available time budget PROFILE_RANGE_EX(simulation_physics, "UpdateRenderables", 0xffff00ff, (uint64_t)_renderablesToUpdate.size()); uint64_t updateStart = usecTimestampNow(); - for (const auto& entry : _renderablesToUpdate) { - const auto& renderable = entry.second; + for (const auto& renderable : _renderablesToUpdate) { assert(renderable); // only valid renderables are added to _renderablesToUpdate renderable->updateInScene(scene, transaction); } @@ -424,8 +419,8 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene // compute average per-renderable update cost float cost = (float)(usecTimestampNow() - updateStart) / (float)(numRenderables); - const float blend = 0.1f; - _avgRenderableUpdateCost = (1.0f - blend) * _avgRenderableUpdateCost + blend * cost; + const float BLEND = 0.1f; + _avgRenderableUpdateCost = (1.0f - BLEND) * _avgRenderableUpdateCost + BLEND * cost; } else { // we expect the cost to updating all renderables to exceed available time budget // so we first sort by priority and update in order until out of time @@ -450,43 +445,40 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene PrioritySortUtil::PriorityQueue sortedRenderables(views); sortedRenderables.reserve(_renderablesToUpdate.size()); { - PROFILE_RANGE_EX(simulation_physics, "SortRenderables", 0xffff00ff, (uint64_t)_renderablesToUpdate.size()); - std::unordered_map::iterator itr = _renderablesToUpdate.begin(); - while (itr != _renderablesToUpdate.end()) { - assert(itr->second); // only valid renderables are added to _renderablesToUpdate - sortedRenderables.push(SortableRenderer(itr->second)); - ++itr; + PROFILE_RANGE_EX(simulation_physics, "BuildSortedRenderables", 0xffff00ff, (uint64_t)_renderablesToUpdate.size()); + for (const auto& renderable : _renderablesToUpdate) { + assert(renderable); // only valid renderables are added to _renderablesToUpdate + sortedRenderables.push(SortableRenderer(renderable)); } } { - PROFILE_RANGE_EX(simulation_physics, "UpdateRenderables", 0xffff00ff, sortedRenderables.size()); + PROFILE_RANGE_EX(simulation_physics, "SortAndUpdateRenderables", 0xffff00ff, sortedRenderables.size()); // compute remaining time budget + const auto& sortedRenderablesVector = sortedRenderables.getSortedVector(); uint64_t updateStart = usecTimestampNow(); - uint64_t timeBudget = MIN_SORTED_UPDATE_RENDERABLES_TIME_BUDGET; uint64_t sortCost = updateStart - sortStart; + uint64_t timeBudget = MIN_SORTED_UPDATE_RENDERABLES_TIME_BUDGET; if (sortCost < MAX_UPDATE_RENDERABLES_TIME_BUDGET - MIN_SORTED_UPDATE_RENDERABLES_TIME_BUDGET) { timeBudget = MAX_UPDATE_RENDERABLES_TIME_BUDGET - sortCost; } uint64_t expiry = updateStart + timeBudget; // process the sorted renderables - size_t numSorted = sortedRenderables.size(); - const auto& sortedRenderablesVector = sortedRenderables.getSortedVector(); for (const auto& sortedRenderable : sortedRenderablesVector) { if (usecTimestampNow() > expiry) { break; } const auto& renderable = sortedRenderable.getRenderer(); renderable->updateInScene(scene, transaction); - _renderablesToUpdate.erase(renderable->getEntity()->getID()); + _renderablesToUpdate.erase(renderable); } // compute average per-renderable update cost - size_t numUpdated = numSorted - sortedRenderables.size() + 1; // add one to avoid divide by zero + size_t numUpdated = sortedRenderables.size() - _renderablesToUpdate.size() + 1; // add one to avoid divide by zero float cost = (float)(usecTimestampNow() - updateStart) / (float)(numUpdated); - const float blend = 0.1f; - _avgRenderableUpdateCost = (1.0f - blend) * _avgRenderableUpdateCost + blend * cost; + const float BLEND = 0.1f; + _avgRenderableUpdateCost = (1.0f - BLEND) * _avgRenderableUpdateCost + BLEND * cost; } } } @@ -990,7 +982,6 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) { void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) { // If it's in a pending queue, remove it - _renderablesToUpdate.erase(entityID); _entitiesToAdd.erase(entityID); auto itr = _entitiesInScene.find(entityID); @@ -1000,7 +991,7 @@ void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) { } if (_tree && !_shuttingDown && _entitiesScriptEngine && !itr->second->getEntity()->getScript().isEmpty()) { - if (itr->second->getEntity()->contains(_avatarPosition)) { + if (_currentEntitiesInside.contains(entityID)) { _entitiesScriptEngine->callEntityScriptMethod(entityID, "leaveEntity"); } _entitiesScriptEngine->unloadEntityScript(entityID, true); @@ -1013,6 +1004,7 @@ void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) { } auto renderable = itr->second; + _renderablesToUpdate.erase(renderable); _entitiesInScene.erase(itr); if (!renderable) { @@ -1047,7 +1039,7 @@ void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID, bool QString scriptUrl = entity->getScript(); if ((shouldLoad && unloadFirst) || scriptUrl.isEmpty()) { if (_entitiesScriptEngine) { - if (entity->contains(_avatarPosition)) { + if (_currentEntitiesInside.contains(entityID)) { _entitiesScriptEngine->callEntityScriptMethod(entityID, "leaveEntity"); } _entitiesScriptEngine->unloadEntityScript(entityID); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index f794d947ed..bea04f106b 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -246,7 +246,7 @@ private: ReadWriteLockable _changedEntitiesGuard; std::unordered_set _changedEntities; - std::unordered_map _renderablesToUpdate; + std::unordered_set _renderablesToUpdate; std::unordered_map _entitiesInScene; std::unordered_map _entitiesToAdd; diff --git a/libraries/shared/src/PrioritySortUtil.h b/libraries/shared/src/PrioritySortUtil.h index d6a740231c..e4a258a065 100644 --- a/libraries/shared/src/PrioritySortUtil.h +++ b/libraries/shared/src/PrioritySortUtil.h @@ -45,7 +45,7 @@ namespace PrioritySortUtil { class PriorityQueue { public: PriorityQueue() = delete; - PriorityQueue(const ConicalViewFrustums& views) : _views(views) { } + PriorityQueue(const ConicalViewFrustums& views) : _views(views), _usecCurrentTime(usecTimestampNow()) { } PriorityQueue(const ConicalViewFrustums& views, float angularWeight, float centerWeight, float ageWeight) : _views(views), _angularWeight(angularWeight), _centerWeight(centerWeight), _ageWeight(ageWeight) , _usecCurrentTime(usecTimestampNow()) { From e119afdeada368d895e7fd547c0aff0823adfda3 Mon Sep 17 00:00:00 2001 From: dante ruiz Date: Mon, 24 Jun 2019 14:35:59 -0700 Subject: [PATCH 19/21] terms of service --- .../cmake/modules/MacOSXBundleInfo.plist.in | 2 +- launchers/darwin/nib/DisplayNameScreen.xib | 32 ++++++++++++++++++- launchers/darwin/src/DisplayNameScreen.m | 5 +++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/launchers/darwin/cmake/modules/MacOSXBundleInfo.plist.in b/launchers/darwin/cmake/modules/MacOSXBundleInfo.plist.in index 4c87bff3cf..3fe8e80f7a 100644 --- a/launchers/darwin/cmake/modules/MacOSXBundleInfo.plist.in +++ b/launchers/darwin/cmake/modules/MacOSXBundleInfo.plist.in @@ -32,6 +32,6 @@ CFBundleName ${MACOSX_BUNDLE_BUNDLE_NAME} CFBundleDisplayName - CFBundleName + ${MACOSX_BUNDLE_BUNDLE_NAME} diff --git a/launchers/darwin/nib/DisplayNameScreen.xib b/launchers/darwin/nib/DisplayNameScreen.xib index e56f2bf66b..f75491fc13 100644 --- a/launchers/darwin/nib/DisplayNameScreen.xib +++ b/launchers/darwin/nib/DisplayNameScreen.xib @@ -69,8 +69,17 @@ + + + + + + + + + + + + + + + + + + + + + @@ -91,5 +112,14 @@ + + + + + + + + + diff --git a/launchers/darwin/src/DisplayNameScreen.m b/launchers/darwin/src/DisplayNameScreen.m index 7a402d792b..581eabc4ee 100644 --- a/launchers/darwin/src/DisplayNameScreen.m +++ b/launchers/darwin/src/DisplayNameScreen.m @@ -31,4 +31,9 @@ { [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://www.highfidelity.com/hq-support"]]; } + +- (IBAction)termsOfService:(id)sender +{ + [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://www.highfidelity.com/termsofservice"]]; +} @end From c5883a8d67dc361c5a87b48fe95a0e66ccd57a67 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Mon, 24 Jun 2019 14:58:06 -0700 Subject: [PATCH 20/21] CR fixes --- domain-server/src/NodeConnectionData.cpp | 2 +- libraries/networking/src/NodeList.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/domain-server/src/NodeConnectionData.cpp b/domain-server/src/NodeConnectionData.cpp index e3406aa797..5419014622 100644 --- a/domain-server/src/NodeConnectionData.cpp +++ b/domain-server/src/NodeConnectionData.cpp @@ -39,7 +39,7 @@ NodeConnectionData NodeConnectionData::fromDataStream(QDataStream& dataStream, c // and the operating system type QByteArray compressedSystemInfo; dataStream >> compressedSystemInfo; - if(!compressedSystemInfo.isEmpty()) { + if (!compressedSystemInfo.isEmpty()) { newHeader.SystemInfo = qUncompress(compressedSystemInfo); } diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 0dad7705f8..9dd7716823 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -426,7 +426,7 @@ void NodeList::sendDomainServerCheckIn() { QByteArray systemInfo(desc.dump().c_str()); QByteArray compressedSystemInfo = qCompress(systemInfo); - if(compressedSystemInfo.size() > MAX_SYSTEM_INFO_SIZE) { + if (compressedSystemInfo.size() > MAX_SYSTEM_INFO_SIZE) { // Highly unlikely, as not even unreasonable machines will // overflow the max size, but prevent MTU overflow anyway. // We could do something sophisticated like clearing specific From dd639c4191b3ba47acbcf8fa0d0355f70dd83d42 Mon Sep 17 00:00:00 2001 From: dante ruiz Date: Mon, 24 Jun 2019 15:33:47 -0700 Subject: [PATCH 21/21] fix typo --- launchers/darwin/nib/DisplayNameScreen.xib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launchers/darwin/nib/DisplayNameScreen.xib b/launchers/darwin/nib/DisplayNameScreen.xib index f75491fc13..3ba3deba53 100644 --- a/launchers/darwin/nib/DisplayNameScreen.xib +++ b/launchers/darwin/nib/DisplayNameScreen.xib @@ -72,7 +72,7 @@ - +