diff options
74 files changed, 1363 insertions, 584 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index bad7958a10..fb643dd222 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,16 +26,24 @@ - [core] Add support for using `within expression` with layout propery. ([#16194](https://github.com/mapbox/mapbox-gl-native/pull/16194)) +### 🐞 Bug fixes + +- [core] Don't provide multiple responses with the same data for 304 replies ([#16200](https://github.com/mapbox/mapbox-gl-native/pull/16200)) + + In cases when cached resource is useable, yet don't have an expiration timestamp, we provided data to the requester from the cache and the same data was returned once 304 response was received from the network. + +- [core] Fix potential visual artifact for line-dasharray ([#16202](https://github.com/mapbox/mapbox-gl-native/pull/16202)) + +- Store gfx::DrawScope objects with associated render objects. ([#15395](https://github.com/mapbox/mapbox-gl-native/pull/15395)) + + We used some shared SegmentVectors, e.g. for drawing raster or background tiles. In longer running maps, this lead to resource accumulation. By storing the SegmentVectors and the contained gfx::DrawScope objects, we ensure that resources get released when the associated render objects vanish. + ### 🏁 Performance improvements - [core] Loading images to style optimization ([#16187](https://github.com/mapbox/mapbox-gl-native/pull/16187)) This change enables attaching images to the style with batches and avoids massive re-allocations. Thus, it improves UI performance especially at start-up time. - - [core] Fix excessive onSpriteLoaded() notifications ([#16196](https://github.com/mapbox/mapbox-gl-native/pull/16196)) - - The excessive `onSpriteLoaded()` notifications affected the render orchestration logic and could have significant negative performance impact. - ### 🧩 Architectural changes ##### ⚠️ Breaking changes diff --git a/CMakeLists.txt b/CMakeLists.txt index e008db2117..485ced04aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,26 @@ cmake_minimum_required(VERSION 3.10 FATAL_ERROR) project("Mapbox GL Native" LANGUAGES CXX C) +find_program(CCACHE_PROGRAM ccache) +if(CCACHE_PROGRAM AND CMAKE_SYSTEM_NAME STREQUAL "iOS") + # Set up wrapper scripts + set(C_LAUNCHER "${CCACHE_PROGRAM}") + set(CXX_LAUNCHER "${CCACHE_PROGRAM}") + configure_file(${PROJECT_SOURCE_DIR}/scripts/ci/ccache-c.in ccache-c) + configure_file(${PROJECT_SOURCE_DIR}/scripts/ci/ccache-cxx.in ccache-cxx) + execute_process( + COMMAND + chmod + a+rx + "${CMAKE_BINARY_DIR}/ccache-c" + "${CMAKE_BINARY_DIR}/ccache-cxx" + ) + + # Set Xcode project attributes to route compilation and linking through our scripts + set(CMAKE_XCODE_ATTRIBUTE_CC "${CMAKE_BINARY_DIR}/ccache-c") + set(CMAKE_XCODE_ATTRIBUTE_CXX "${CMAKE_BINARY_DIR}/ccache-cxx") +endif() + set_property(GLOBAL PROPERTY USE_FOLDERS ON) set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER Core) @@ -752,8 +772,6 @@ add_library( ${PROJECT_SOURCE_DIR}/src/mbgl/util/http_timeout.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/util/i18n.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/util/i18n.hpp - ${PROJECT_SOURCE_DIR}/src/mbgl/util/id.cpp - ${PROJECT_SOURCE_DIR}/src/mbgl/util/id.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/util/interpolate.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/util/intersection_tests.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/util/intersection_tests.hpp diff --git a/circle.yml b/circle.yml index cb54ae998a..a9c10b6395 100644 --- a/circle.yml +++ b/circle.yml @@ -20,6 +20,7 @@ workflows: - android-render-test-runner - android-unit-test-runner - ios-render-test-runner + - ios-unit-test-runner - baselines: requires: - android-arm64-v8a-release @@ -151,7 +152,12 @@ workflows: - macos-xcode11-release config_params: '-G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_BUILD_TYPE=Debug' style_tests: true - - ios-xcode11-release + - build-template: + name: ios-xcode11-release + executor_name: macos-11_0_0 + target_is_macos: true + config_params: '-G Xcode -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_ARCHITECTURES=arm64e -DCMAKE_OSX_SYSROOT=iphoneos' + build_params: '--config Release' # # Executors: we currently support two executors, one based on Ubuntu 19.04 aka Disco @@ -236,7 +242,7 @@ commands: name: Build command: | ccache --zero-stats --max-size=2G - cmake --build build -j $(nproc) << parameters.build_params >> + cmake --build build -j $(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null) << parameters.build_params >> ccache --show-stats install: steps: @@ -311,18 +317,6 @@ commands: gcloud auth activate-service-account --key-file secret.json --project android-gl-native rm secret.json jobs: - ios-xcode11-release: - executor: macos-11_0_0 - steps: - - checkout - - prepare - - prepare-macos - - run: - name: Build - command: | - cmake . -B Build -G Xcode -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_ARCHITECTURES=x86_64 -DCMAKE_OSX_SYSROOT=iphonesimulator - cd Build && xcodebuild -sdk iphonesimulator -project Mapbox\ GL\ Native.xcodeproj -configuration Release - - save ios-render-test-runner: executor: macos-11_0_0 steps: @@ -341,16 +335,15 @@ jobs: name: Build IOS RenderTestApp command: | cd render-test/ios - cmake ../.. -B Build -G Xcode -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphoneos -DMBGL_IOS_RENDER_TEST=ON - cd Build - xcodebuild -sdk iphoneos -project Mapbox\ GL\ Native.xcodeproj -scheme RenderTestApp build-for-testing -arch arm64 CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -configuration Release - xcodebuild -sdk iphoneos -project Mapbox\ GL\ Native.xcodeproj build -target RenderTestAppTests -arch arm64 CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -configuration Release + ccache --zero-stats --max-size=2G + cmake ../.. -B Build -G Xcode -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphoneos -DMBGL_IOS_RENDER_TEST=ON -DCMAKE_OSX_ARCHITECTURES=arm64e + cmake --build Build --config Release + ccache --show-stats - run: name: Codesign RenderTestApp for running on a physical device command: | cd render-test/ios ./codesigning/generate-entitlements.swift - ls codesigning cd Build ../codesigning/codesign_all.sh codesign -dv --verbose=4 Release-iphoneos/RenderTestApp.app # for debugging that app is signed or not @@ -398,6 +391,74 @@ jobs: fi fi - save + ios-unit-test-runner: + executor: macos-11_0_0 + steps: + - checkout + - prepare + - prepare-macos + - run: + name: Prepare codesign keychain + command: | + cd test/ios + fastlane run create_keychain name:fastlane_keychain password:$FASTLANE_PASSWORD timeout:false unlock:true + fastlane match + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $FASTLANE_PASSWORD fastlane_keychain + /usr/bin/env xcrun security find-identity -v -p codesigning + - run: + name: Build IOS UnitTestsApp + command: | + cd test/ios + ccache --zero-stats --max-size=2G + cmake ../.. -B Build -G Xcode -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphoneos -DMBGL_IOS_UNIT_TEST=1 -DCMAKE_OSX_ARCHITECTURES=arm64e + cmake --build Build --config Release + ccache --show-stats + - run: + name: Codesign UnitTestsApp for running on a physical device + command: | + cd test/ios + ./codesigning/generate-entitlements.swift + cd Build + ../codesigning/codesign_all.sh + codesign -dv --verbose=4 Release-iphoneos/UnitTestsApp.app + - run: + name: Login to IOS Google Cloud Platform + command: | + if [[ -n "${GCLOUD_SERVICE_ACCOUNT_JSON_IOS}" ]]; then + echo "${GCLOUD_SERVICE_ACCOUNT_JSON_IOS}" > iosAccount.json + gcloud auth activate-service-account --key-file iosAccount.json --project ios-mapbox-gl-native + rm iosAccount.json + fi + - run: + name: Run UnitTestsApp on Firebase + no_output_timeout: 20m + command: | + if [[ -n "${GCLOUD_SERVICE_ACCOUNT_JSON_IOS}" ]]; then + # arrange files in a way Firebase expects it, and package them in a zip file + cd test/ios/Build + cp ../UnitTestsApp_iphoneos13.2-arm64e-release.xctestrun . + zip testapp.zip -r Release-iphoneos/UnitTestsApp.app --quiet + zip testapp.zip UnitTestsApp_iphoneos13.2-arm64e-release.xctestrun + gcloud firebase test ios models list + gcloud firebase test ios run \ + --test testapp.zip \ + --device model=iphonexs,version=12.0,locale=en,orientation=portrait --xcode-version=11.1 --timeout 20m \ + --verbosity=debug --no-record-video --results-dir ios-unit-test-app-${CIRCLE_BUILD_NUM} + fi + - run: + name: Retrieve Test Result from gcloud + when: always + command: | + if [[ -n "${GCLOUD_SERVICE_ACCOUNT_JSON_IOS}" ]]; then + testResult=$(gsutil ls -d gs://test-lab-hn7kwqcz3108z-hjm4qtbqqkymk/ios-unit-test-app-${CIRCLE_BUILD_NUM}/iphonexs-12.0-en-portrait/TestLogs/) + mkdir -p unit-test-app + gsutil -m cp -r $testResult unit-test-app + cd unit-test-app/TestLogs + xcparse attachments *.xcresult && ls + cd ../.. && mkdir -p /tmp/tests/unit-test + if ls unit-test-app/TestLogs/*.xml 1> /dev/null 2>&1; then cp unit-test-app/TestLogs/*.xml /tmp/tests/unit-test/results.xml; fi + fi + - save android-benchmark-runner: executor: ubuntu-disco steps: diff --git a/metrics/android-render-test-runner/render-tests/line-dasharray/zero-length-gap/metrics.json b/metrics/android-render-test-runner/render-tests/line-dasharray/zero-length-gap/metrics.json new file mode 100644 index 0000000000..32c56fe8f4 --- /dev/null +++ b/metrics/android-render-test-runner/render-tests/line-dasharray/zero-length-gap/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 0, + 0 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 6, + 8, + 20, + 1, + [ + 34048, + 34048 + ], + [ + 58, + 58 + ], + [ + 784, + 784 + ] + ] + ] +}
\ No newline at end of file diff --git a/metrics/binary-size/linux-clang8/metrics.json b/metrics/binary-size/linux-clang8/metrics.json index 6f16bb1b15..067acd3306 100644 --- a/metrics/binary-size/linux-clang8/metrics.json +++ b/metrics/binary-size/linux-clang8/metrics.json @@ -3,17 +3,17 @@ [ "mbgl-glfw", "/tmp/attach/install/linux-clang8-release/bin/mbgl-glfw", - 6507720 + 6569176 ], [ "mbgl-offline", "/tmp/attach/install/linux-clang8-release/bin/mbgl-offline", - 5774024 + 5835480 ], [ "mbgl-render", "/tmp/attach/install/linux-clang8-release/bin/mbgl-render", - 6409144 + 6470600 ] ] -}
\ No newline at end of file +} diff --git a/metrics/ignores/platform-all.json b/metrics/ignores/platform-all.json index e9ee792f37..b53e923a9d 100644 --- a/metrics/ignores/platform-all.json +++ b/metrics/ignores/platform-all.json @@ -131,6 +131,5 @@ "render-tests/feature-state/promote-id-fill-extrusion": "https://github.com/mapbox/mapbox-gl-js/pull/9202", "render-tests/text-variable-anchor/left-top-right-buttom-offset-tile-map-mode":"https://github.com/mapbox/mapbox-gl-js/pull/9202", "render-tests/line-pattern/with-dasharray":"https://github.com/mapbox/mapbox-gl-js/pull/9189", - "render-tests/symbol-sort-key/placement-tile-boundary-right-then-left": "https://github.com/mapbox/mapbox-gl-js/pull/9054", - "render-tests/line-dasharray/zero-length-gap":"https://github.com/mapbox/mapbox-gl-js/pull/9246" + "render-tests/symbol-sort-key/placement-tile-boundary-right-then-left": "https://github.com/mapbox/mapbox-gl-js/pull/9054" } diff --git a/metrics/ios-render-test-runner/render-tests/line-dasharray/zero-length-gap/metrics.json b/metrics/ios-render-test-runner/render-tests/line-dasharray/zero-length-gap/metrics.json new file mode 100644 index 0000000000..32c56fe8f4 --- /dev/null +++ b/metrics/ios-render-test-runner/render-tests/line-dasharray/zero-length-gap/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 0, + 0 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 6, + 8, + 20, + 1, + [ + 34048, + 34048 + ], + [ + 58, + 58 + ], + [ + 784, + 784 + ] + ] + ] +}
\ No newline at end of file diff --git a/metrics/linux-clang8-release/render-tests/line-dasharray/zero-length-gap/metrics.json b/metrics/linux-clang8-release/render-tests/line-dasharray/zero-length-gap/metrics.json new file mode 100644 index 0000000000..32c56fe8f4 --- /dev/null +++ b/metrics/linux-clang8-release/render-tests/line-dasharray/zero-length-gap/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 0, + 0 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 6, + 8, + 20, + 1, + [ + 34048, + 34048 + ], + [ + 58, + 58 + ], + [ + 784, + 784 + ] + ] + ] +}
\ No newline at end of file diff --git a/metrics/linux-gcc8-release/render-tests/line-dasharray/zero-length-gap/metrics.json b/metrics/linux-gcc8-release/render-tests/line-dasharray/zero-length-gap/metrics.json new file mode 100644 index 0000000000..32c56fe8f4 --- /dev/null +++ b/metrics/linux-gcc8-release/render-tests/line-dasharray/zero-length-gap/metrics.json @@ -0,0 +1,35 @@ +{ + "network": [ + [ + "probeNetwork - default - end", + 0, + 0 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 6, + 8, + 20, + 1, + [ + 34048, + 34048 + ], + [ + 58, + 58 + ], + [ + 784, + 784 + ] + ] + ] +}
\ No newline at end of file diff --git a/platform/default/src/mbgl/storage/main_resource_loader.cpp b/platform/default/src/mbgl/storage/main_resource_loader.cpp index 9bdf09fa10..aa8d745170 100644 --- a/platform/default/src/mbgl/storage/main_resource_loader.cpp +++ b/platform/default/src/mbgl/storage/main_resource_loader.cpp @@ -81,13 +81,17 @@ public: callback(response); // Set the priority of existing resource to low if it's expired but usable. res.setPriority(Resource::Priority::Low); + } else { + // Set prior data only if it was not returned to the requester. + // Once we get 304 response from the network, we will forward response + // to the requester. + res.priorData = response.data; } // Copy response fields for cache control request res.priorModified = response.modified; res.priorExpires = response.expires; res.priorEtag = response.etag; - res.priorData = response.data; } tasks[req] = requestFromNetwork(res, std::move(tasks[req])); diff --git a/platform/ios/ios.cmake b/platform/ios/ios.cmake index aa22a376f8..18b2b2aad0 100644 --- a/platform/ios/ios.cmake +++ b/platform/ios/ios.cmake @@ -4,7 +4,7 @@ target_compile_definitions( ) if(NOT DEFINED IOS_DEPLOYMENT_TARGET) - set(IOS_DEPLOYMENT_TARGET "9.0") + set(IOS_DEPLOYMENT_TARGET "12.0") endif() macro(initialize_ios_target target) @@ -94,30 +94,26 @@ target_link_libraries( ) if(MBGL_IOS_RENDER_TEST) - set(CMAKE_OSX_ARCHITECTURES "armv7;i386;x86_64;arm64") - include(${PROJECT_SOURCE_DIR}/vendor/zip-archive.cmake) initialize_ios_target(mbgl-vendor-zip-archive) set(PREPARE_CMD "${PROJECT_SOURCE_DIR}/render-test/ios/setup_test_data.sh") - message("COMMAND: ${PREPARE_CMD}") execute_process(COMMAND ${PREPARE_CMD} RESULT_VARIABLE CMD_ERROR WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) - message(STATUS "CMD_ERROR:" ${CMD_ERROR}) - set(RESOURCES ${PROJECT_SOURCE_DIR}/render-test/ios/Main.storyboard ${PROJECT_SOURCE_DIR}/render-test/ios/LaunchScreen.storyboard - ${PROJECT_SOURCE_DIR}/test-data) + set(RESOURCES ${PROJECT_SOURCE_DIR}/platform/ios/test/common/Main.storyboard + ${PROJECT_SOURCE_DIR}/platform/ios/test/common/LaunchScreen.storyboard ${PROJECT_SOURCE_DIR}/test-data) add_executable( RenderTestApp - ${PROJECT_SOURCE_DIR}/render-test/ios/ios_test_runner.hpp + ${PROJECT_SOURCE_DIR}/platform/ios/test/common/ios_test_runner.hpp + ${PROJECT_SOURCE_DIR}/platform/ios/test/common/AppDelegate.h + ${PROJECT_SOURCE_DIR}/platform/ios/test/common/AppDelegate.m + ${PROJECT_SOURCE_DIR}/platform/ios/test/common/ViewController.h + ${PROJECT_SOURCE_DIR}/platform/ios/test/common/ViewController.m + ${PROJECT_SOURCE_DIR}/platform/ios/test/common/main.m ${PROJECT_SOURCE_DIR}/render-test/ios/ios_test_runner.cpp - ${PROJECT_SOURCE_DIR}/render-test/ios/AppDelegate.h - ${PROJECT_SOURCE_DIR}/render-test/ios/AppDelegate.m - ${PROJECT_SOURCE_DIR}/render-test/ios/ViewController.h - ${PROJECT_SOURCE_DIR}/render-test/ios/ViewController.m ${PROJECT_SOURCE_DIR}/render-test/ios/iosTestRunner.h ${PROJECT_SOURCE_DIR}/render-test/ios/iosTestRunner.mm - ${PROJECT_SOURCE_DIR}/render-test/ios/main.m ${RESOURCES} ) initialize_ios_target(RenderTestApp) @@ -147,6 +143,7 @@ if(MBGL_IOS_RENDER_TEST) ${PROJECT_SOURCE_DIR}/platform/darwin/include ${PROJECT_SOURCE_DIR}/platform/darwin/include/mbgl/interface/ ${PROJECT_SOURCE_DIR}/platform/default/include + ${PROJECT_SOURCE_DIR}/platform/ios/test/common ${PROJECT_SOURCE_DIR}/src ) @@ -168,19 +165,13 @@ if(MBGL_IOS_RENDER_TEST) mbgl-vendor-zip-archive ) + set_target_properties(RenderTestApp PROPERTIES XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "") + set_target_properties(RenderTestApp PROPERTIES XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO") + find_package(XCTest REQUIRED) xctest_add_bundle(RenderTestAppTests RenderTestApp ${PROJECT_SOURCE_DIR}/render-test/ios/tests/Tests.m) - set_target_properties( - RenderTestAppTests - PROPERTIES - XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET - "${IOS_DEPLOYMENT_TARGET}" - XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH - $<$<CONFIG:Debug>:YES> - ) - target_include_directories( RenderTestAppTests PUBLIC ${PROJECT_SOURCE_DIR}/render-test/ios @@ -188,7 +179,94 @@ if(MBGL_IOS_RENDER_TEST) xctest_add_test(XCTest.RenderTestApp RenderTestAppTests) + set_target_properties(RenderTestAppTests PROPERTIES XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "${IOS_DEPLOYMENT_TARGET}") + set_target_properties(RenderTestAppTests PROPERTIES XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH $<$<CONFIG:Debug>:YES>) set_target_properties(RenderTestAppTests PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/render-test/ios/tests/Info.plist) + set_target_properties(RenderTestAppTests PROPERTIES XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "") + set_target_properties(RenderTestAppTests PROPERTIES XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO") +endif() + +if(MBGL_IOS_UNIT_TEST) + execute_process(COMMAND ditto ${PROJECT_SOURCE_DIR}/test/fixtures ${CMAKE_CURRENT_BINARY_DIR}/test-data/test/fixtures) + execute_process( + COMMAND + ditto ${PROJECT_SOURCE_DIR}/mapbox-gl-js/src/style-spec/reference + ${CMAKE_CURRENT_BINARY_DIR}/test-data/mapbox-gl-js/src/style-spec/reference + ) + + set(RESOURCES ${PROJECT_SOURCE_DIR}/platform/ios/test/common/Main.storyboard + ${PROJECT_SOURCE_DIR}/platform/ios/test/common/LaunchScreen.storyboard ${CMAKE_CURRENT_BINARY_DIR}/test-data) + + add_executable( + UnitTestsApp + ${PROJECT_SOURCE_DIR}/platform/ios/test/common/ios_test_runner.hpp + ${PROJECT_SOURCE_DIR}/platform/ios/test/common/AppDelegate.h + ${PROJECT_SOURCE_DIR}/platform/ios/test/common/AppDelegate.m + ${PROJECT_SOURCE_DIR}/platform/ios/test/common/ViewController.h + ${PROJECT_SOURCE_DIR}/platform/ios/test/common/ViewController.m + ${PROJECT_SOURCE_DIR}/platform/ios/test/common/main.m + ${PROJECT_SOURCE_DIR}/test/ios/ios_test_runner.cpp + ${PROJECT_SOURCE_DIR}/test/ios/iosTestRunner.h + ${PROJECT_SOURCE_DIR}/test/ios/iosTestRunner.mm + ${RESOURCES} + ) + initialize_ios_target(UnitTestsApp) + + set_target_properties( + UnitTestsApp + PROPERTIES + MACOSX_BUNDLE + TRUE + MACOSX_BUNDLE_IDENTIFIER + com.mapbox.UnitTestsApp + MACOSX_BUNDLE_INFO_PLIST + ${PROJECT_SOURCE_DIR}/test/ios/Info.plist + RESOURCE + "${RESOURCES}" + ) + + target_include_directories( + UnitTestsApp + PUBLIC + ${PROJECT_SOURCE_DIR}/include + ${PROJECT_SOURCE_DIR}/platform/ios/test/common + ${PROJECT_SOURCE_DIR}/test/include + ${PROJECT_SOURCE_DIR}/test/ios + ) + + target_link_libraries( + UnitTestsApp + PRIVATE + "-framework CoreGraphics" + "-framework CoreLocation" + "-framework Foundation" + "-framework OpenGLES" + "-framework QuartzCore" + "-framework UIKit" + mbgl-compiler-options + -Wl,-force_load + mbgl-test + ) + + set_target_properties(UnitTestsApp PROPERTIES XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "") + set_target_properties(UnitTestsApp PROPERTIES XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO") + + find_package(XCTest REQUIRED) + + xctest_add_bundle(UnitTestsAppTests UnitTestsApp ${PROJECT_SOURCE_DIR}/platform/ios/test/common/Tests.m) + + target_include_directories( + UnitTestsAppTests + PUBLIC ${PROJECT_SOURCE_DIR}/test/ios + ) + + xctest_add_test(XCTest.UnitTestsApp UnitTestsAppTests) + + set_target_properties(UnitTestsAppTests PROPERTIES XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "${IOS_DEPLOYMENT_TARGET}") + set_target_properties(UnitTestsAppTests PROPERTIES XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH $<$<CONFIG:Debug>:YES>) + set_target_properties(UnitTestsAppTests PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/test/ios/tests/Info.plist) + set_target_properties(UnitTestsAppTests PROPERTIES XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "") + set_target_properties(UnitTestsAppTests PROPERTIES XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO") endif() unset(IOS_DEPLOYMENT_TARGET CACHE) diff --git a/render-test/ios/AppDelegate.h b/platform/ios/test/common/AppDelegate.h index 134c8063dc..134c8063dc 100644 --- a/render-test/ios/AppDelegate.h +++ b/platform/ios/test/common/AppDelegate.h diff --git a/render-test/ios/AppDelegate.m b/platform/ios/test/common/AppDelegate.m index 874d18de2a..874d18de2a 100644 --- a/render-test/ios/AppDelegate.m +++ b/platform/ios/test/common/AppDelegate.m diff --git a/render-test/ios/LaunchScreen.storyboard b/platform/ios/test/common/LaunchScreen.storyboard index c9b7564332..c9b7564332 100644 --- a/render-test/ios/LaunchScreen.storyboard +++ b/platform/ios/test/common/LaunchScreen.storyboard diff --git a/render-test/ios/Main.storyboard b/platform/ios/test/common/Main.storyboard index 34d4c7e2ec..34d4c7e2ec 100644 --- a/render-test/ios/Main.storyboard +++ b/platform/ios/test/common/Main.storyboard diff --git a/platform/ios/test/common/Tests.m b/platform/ios/test/common/Tests.m new file mode 100644 index 0000000000..8d0719705a --- /dev/null +++ b/platform/ios/test/common/Tests.m @@ -0,0 +1,37 @@ +#import <XCTest/XCTest.h> +#import "iosTestRunner.h" +@interface Tests : XCTestCase + +@end + +@implementation Tests + +- (void)setUp { + [super setUp]; +} + +- (void)tearDown { + [super tearDown]; +} + +- (void)testStartTestRunner { + IosTestRunner* runner = [[IosTestRunner alloc] init]; + XCTAssert(runner, @"IOSTestRunner is not initialized correctly"); + + NSString* testResult = [runner getResultPath]; + XCTAssert(testResult, @"IOSTestRunner did not produce a test result file"); + + NSFileManager *fileManager = [NSFileManager defaultManager]; + BOOL fileFound = [fileManager fileExistsAtPath: testResult]; + XCTAssert(fileFound, @"Test result file '%@' does not exit", testResult); + NSURL *resultURL = [NSURL fileURLWithPath:testResult]; + XCTAttachment *attachment1URL = [XCTAttachment attachmentWithContentsOfFileAtURL: resultURL]; + XCTAssert(attachment1URL, @"Failed to attach test result '%@'", testResult); + attachment1URL.lifetime = XCTAttachmentLifetimeKeepAlways; + [self addAttachment:attachment1URL]; + + BOOL success = [runner getTestStatus]; + XCTAssert(success, @"IOSTestRunner reports error because some of the tests are not passed, please check the test report"); +} + +@end diff --git a/render-test/ios/ViewController.h b/platform/ios/test/common/ViewController.h index 9c7dfc57ec..9c7dfc57ec 100644 --- a/render-test/ios/ViewController.h +++ b/platform/ios/test/common/ViewController.h diff --git a/render-test/ios/ViewController.m b/platform/ios/test/common/ViewController.m index e9c526122a..e9c526122a 100644 --- a/render-test/ios/ViewController.m +++ b/platform/ios/test/common/ViewController.m diff --git a/render-test/ios/ios_test_runner.hpp b/platform/ios/test/common/ios_test_runner.hpp index 4ec1da93b0..db263dc73c 100644 --- a/render-test/ios/ios_test_runner.hpp +++ b/platform/ios/test/common/ios_test_runner.hpp @@ -8,7 +8,7 @@ public: TestRunner() = default; ~TestRunner() = default; - bool startTest(const std::string& manifest); + bool startTest(const std::string& path); }; #endif /* ios_test_runner_hpp */ diff --git a/platform/ios/test/common/main.m b/platform/ios/test/common/main.m new file mode 100644 index 0000000000..f813c8fea9 --- /dev/null +++ b/platform/ios/test/common/main.m @@ -0,0 +1,9 @@ +#import <UIKit/UIKit.h> +#import "AppDelegate.h" + +int main(int argc, char * argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/render-test/ios/Gemfile b/render-test/ios/Gemfile deleted file mode 100644 index adc90d98cf..0000000000 --- a/render-test/ios/Gemfile +++ /dev/null @@ -1,3 +0,0 @@ -source "https://rubygems.org" - -gem "fastlane"
\ No newline at end of file diff --git a/render-test/ios/Gemfile.lock b/render-test/ios/Gemfile.lock deleted file mode 100644 index 23018150b9..0000000000 --- a/render-test/ios/Gemfile.lock +++ /dev/null @@ -1,159 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - CFPropertyList (3.0.2) - addressable (2.7.0) - public_suffix (>= 2.0.2, < 5.0) - atomos (0.1.3) - babosa (1.0.3) - claide (1.0.3) - colored (1.2) - colored2 (3.1.2) - commander-fastlane (4.4.6) - highline (~> 1.7.2) - declarative (0.0.10) - declarative-option (0.1.0) - digest-crc (0.4.1) - domain_name (0.5.20190701) - unf (>= 0.0.5, < 1.0.0) - dotenv (2.7.5) - emoji_regex (1.0.1) - excon (0.71.1) - faraday (0.17.3) - multipart-post (>= 1.2, < 3) - faraday-cookie_jar (0.0.6) - faraday (>= 0.7.4) - http-cookie (~> 1.0.0) - faraday_middleware (0.13.1) - faraday (>= 0.7.4, < 1.0) - fastimage (2.1.7) - fastlane (2.139.0) - CFPropertyList (>= 2.3, < 4.0.0) - addressable (>= 2.3, < 3.0.0) - babosa (>= 1.0.2, < 2.0.0) - bundler (>= 1.12.0, < 3.0.0) - colored - commander-fastlane (>= 4.4.6, < 5.0.0) - dotenv (>= 2.1.1, < 3.0.0) - emoji_regex (>= 0.1, < 2.0) - excon (>= 0.71.0, < 1.0.0) - faraday (~> 0.17) - faraday-cookie_jar (~> 0.0.6) - faraday_middleware (~> 0.13.1) - fastimage (>= 2.1.0, < 3.0.0) - gh_inspector (>= 1.1.2, < 2.0.0) - google-api-client (>= 0.29.2, < 0.37.0) - google-cloud-storage (>= 1.15.0, < 2.0.0) - highline (>= 1.7.2, < 2.0.0) - json (< 3.0.0) - jwt (~> 2.1.0) - mini_magick (>= 4.9.4, < 5.0.0) - multi_xml (~> 0.5) - multipart-post (~> 2.0.0) - plist (>= 3.1.0, < 4.0.0) - public_suffix (~> 2.0.0) - rubyzip (>= 1.3.0, < 2.0.0) - security (= 0.1.3) - simctl (~> 1.6.3) - slack-notifier (>= 2.0.0, < 3.0.0) - terminal-notifier (>= 2.0.0, < 3.0.0) - terminal-table (>= 1.4.5, < 2.0.0) - tty-screen (>= 0.6.3, < 1.0.0) - tty-spinner (>= 0.8.0, < 1.0.0) - word_wrap (~> 1.0.0) - xcodeproj (>= 1.13.0, < 2.0.0) - xcpretty (~> 0.3.0) - xcpretty-travis-formatter (>= 0.0.3) - gh_inspector (1.1.3) - google-api-client (0.36.4) - addressable (~> 2.5, >= 2.5.1) - googleauth (~> 0.9) - httpclient (>= 2.8.1, < 3.0) - mini_mime (~> 1.0) - representable (~> 3.0) - retriable (>= 2.0, < 4.0) - signet (~> 0.12) - google-cloud-core (1.4.1) - google-cloud-env (~> 1.0) - google-cloud-env (1.3.0) - faraday (~> 0.11) - google-cloud-storage (1.25.0) - addressable (~> 2.5) - digest-crc (~> 0.4) - google-api-client (~> 0.33) - google-cloud-core (~> 1.2) - googleauth (~> 0.9) - mini_mime (~> 1.0) - googleauth (0.10.0) - faraday (~> 0.12) - jwt (>= 1.4, < 3.0) - memoist (~> 0.16) - multi_json (~> 1.11) - os (>= 0.9, < 2.0) - signet (~> 0.12) - highline (1.7.10) - http-cookie (1.0.3) - domain_name (~> 0.5) - httpclient (2.8.3) - json (2.3.0) - jwt (2.1.0) - memoist (0.16.2) - mini_magick (4.10.1) - mini_mime (1.0.2) - multi_json (1.14.1) - multi_xml (0.6.0) - multipart-post (2.0.0) - nanaimo (0.2.6) - naturally (2.2.0) - os (1.0.1) - plist (3.5.0) - public_suffix (2.0.5) - representable (3.0.4) - declarative (< 0.1.0) - declarative-option (< 0.2.0) - uber (< 0.2.0) - retriable (3.1.2) - rouge (2.0.7) - rubyzip (1.3.0) - security (0.1.3) - signet (0.12.0) - addressable (~> 2.3) - faraday (~> 0.9) - jwt (>= 1.5, < 3.0) - multi_json (~> 1.10) - simctl (1.6.7) - CFPropertyList - naturally - slack-notifier (2.3.2) - terminal-notifier (2.0.0) - terminal-table (1.8.0) - unicode-display_width (~> 1.1, >= 1.1.1) - tty-cursor (0.7.0) - tty-screen (0.7.0) - tty-spinner (0.9.2) - tty-cursor (~> 0.7) - uber (0.1.0) - unf (0.1.4) - unf_ext - unf_ext (0.0.7.6) - unicode-display_width (1.6.0) - word_wrap (1.0.0) - xcodeproj (1.14.0) - CFPropertyList (>= 2.3.3, < 4.0) - atomos (~> 0.1.3) - claide (>= 1.0.2, < 2.0) - colored2 (~> 3.1) - nanaimo (~> 0.2.6) - xcpretty (0.3.0) - rouge (~> 2.0.7) - xcpretty-travis-formatter (1.0.0) - xcpretty (~> 0.2, >= 0.0.7) - -PLATFORMS - ruby - -DEPENDENCIES - fastlane - -BUNDLED WITH - 2.1.4 diff --git a/scripts/ci/ccache-c.in b/scripts/ci/ccache-c.in new file mode 100644 index 0000000000..f75d456e5d --- /dev/null +++ b/scripts/ci/ccache-c.in @@ -0,0 +1,9 @@ +#!/bin/sh + +# Xcode generator doesn't include the compiler as the +# first argument, Ninja and Makefiles do. Handle both cases. +if [[ "$1" = "${CMAKE_C_COMPILER}" ]] ; then + shift +fi + +exec "${C_LAUNCHER}" "${CMAKE_C_COMPILER}" "$@" diff --git a/scripts/ci/ccache-cxx.in b/scripts/ci/ccache-cxx.in new file mode 100644 index 0000000000..81831ad4dc --- /dev/null +++ b/scripts/ci/ccache-cxx.in @@ -0,0 +1,9 @@ +#!/bin/sh + +# Xcode generator doesn't include the compiler as the +# first argument, Ninja and Makefiles do. Handle both cases. +if [[ "$1" = "${CMAKE_CXX_COMPILER}" ]] ; then + shift +fi + +exec "${CXX_LAUNCHER}" "${CMAKE_CXX_COMPILER}" "$@" diff --git a/src/mbgl/geometry/line_atlas.cpp b/src/mbgl/geometry/line_atlas.cpp index f272101a5b..3b6d82c46c 100644 --- a/src/mbgl/geometry/line_atlas.cpp +++ b/src/mbgl/geometry/line_atlas.cpp @@ -1,3 +1,4 @@ +#include <cmath> #include <mbgl/geometry/line_atlas.hpp> #include <mbgl/gfx/upload_pass.hpp> #include <mbgl/math/log2.hpp> @@ -6,8 +7,6 @@ #include <mbgl/util/logging.hpp> #include <mbgl/util/platform.hpp> -#include <cmath> - namespace mbgl { namespace { @@ -20,82 +19,143 @@ size_t getDashPatternHash(const std::vector<float>& dasharray, const LinePattern return key; } -LinePatternPos addDashPattern(AlphaImage& image, - const int32_t yOffset, - const std::vector<float>& dasharray, - const LinePatternCap patternCap) { - const uint8_t n = patternCap == LinePatternCap::Round ? 7 : 0; - constexpr const uint8_t offset = 128; +std::vector<DashRange> getDashRanges(const std::vector<float>& dasharray, float stretch) { + // If dasharray has an odd length, both the first and last parts + // are dashes and should be joined seamlessly. + const bool oddDashArray = dasharray.size() % 2 == 1; - if (dasharray.size() < 2) { - Log::Warning(Event::ParseStyle, "line dasharray requires at least two elements"); - return LinePatternPos(); - } + float left = oddDashArray ? -dasharray.back() * stretch : 0.0f; + float right = dasharray.front() * stretch; + bool isDash = true; - float length = 0; - for (const float part : dasharray) { - length += part; + std::vector<DashRange> ranges; + ranges.reserve(dasharray.size()); + ranges.push_back({left, right, isDash, dasharray.front() == 0.0f}); + + float currentDashLength = dasharray.front(); + for (size_t i = 1; i < dasharray.size(); ++i) { + isDash = !isDash; + + const float dashLength = dasharray[i]; + left = currentDashLength * stretch; + currentDashLength += dashLength; + right = currentDashLength * stretch; + + ranges.push_back({left, right, isDash, dashLength == 0.0f}); } - float stretch = image.size.width / length; - float halfWidth = stretch * 0.5; - // If dasharray has an odd length, both the first and last parts - // are dashes and should be joined seamlessly. - bool oddLength = dasharray.size() % 2 == 1; + return ranges; +} + +void addRoundDash( + const std::vector<DashRange>& ranges, uint32_t yOffset, float stretch, const int n, AlphaImage& image) { + const float halfStretch = stretch * 0.5f; for (int y = -n; y <= n; y++) { int row = yOffset + n + y; - int index = image.size.width * row; + const uint32_t index = image.size.width * row; + uint32_t currIndex = 0; + DashRange range = ranges[currIndex]; - float left = 0; - float right = dasharray[0]; - unsigned int partIndex = 1; + for (uint32_t x = 0; x < image.size.width; x++) { + if (x / range.right > 1.0f) { + range = ranges[++currIndex]; + } - if (oddLength) { - left -= dasharray.back(); - } + float distLeft = fabsf(x - range.left); + float distRight = fabsf(x - range.right); + float minDist = fminf(distLeft, distRight); + float signedDistance; - for (uint32_t x = 0; x < image.size.width; x++) { - while (right < x / stretch) { - left = right; - if (partIndex >= dasharray.size()) { - return LinePatternPos(); - } - right = right + dasharray[partIndex]; - - if (oddLength && partIndex == dasharray.size() - 1) { - right += dasharray.front(); - } - - partIndex++; + float distMiddle = static_cast<float>(y) / n * (halfStretch + 1.0f); + if (range.isDash) { + float distEdge = halfStretch - fabsf(distMiddle); + signedDistance = sqrtf(minDist * minDist + distEdge * distEdge); + } else { + signedDistance = halfStretch - sqrtf(minDist * minDist + distMiddle * distMiddle); } - float distLeft = fabs(x - left * stretch); - float distRight = fabs(x - right * stretch); - float dist = fmin(distLeft, distRight); - bool inside = (partIndex % 2) == 1; - int signedDistance; - - if (patternCap == LinePatternCap::Round) { - float distMiddle = n ? (float)y / n * (halfWidth + 1) : 0; - if (inside) { - float distEdge = halfWidth - fabs(distMiddle); - signedDistance = sqrt(dist * dist + distEdge * distEdge); - } else { - signedDistance = halfWidth - sqrt(dist * dist + distMiddle * distMiddle); - } + image.data[index + x] = static_cast<uint8_t>(fmaxf(0.0f, fminf(255.0f, signedDistance + 128.0f))); + } + } +} +void addRegularDash(std::vector<DashRange>& ranges, uint32_t yOffset, AlphaImage& image) { + // Collapse any zero-length range + for (auto it = ranges.begin(); it != ranges.end();) { + if (it->isZeroLength) { + ranges.erase(it); + } else { + ++it; + } + } + + if (ranges.size() >= 2) { + // Collapse neighbouring same-type parts into a single part + for (auto curr = ranges.begin(), next = ranges.begin() + 1; curr != ranges.end() && next != ranges.end();) { + if (next->isDash == curr->isDash) { + next->left = curr->left; + ranges.erase(curr); } else { - signedDistance = int((inside ? 1 : -1) * dist); + ++curr; + ++next; } + } + } + + DashRange& first = ranges.front(); + DashRange& last = ranges.back(); + if (first.isDash == last.isDash) { + first.left = last.left - image.size.width; + last.right = first.right + image.size.width; + } + + const uint32_t index = image.size.width * yOffset; + uint32_t currIndex = 0; + DashRange range = ranges[currIndex]; - image.data[index + x] = fmax(0, fmin(255, signedDistance + offset)); + for (uint32_t x = 0; x < image.size.width; ++x) { + if (x / range.right > 1.0f) { + range = ranges[++currIndex]; } + + float distLeft = fabsf(x - range.left); + float distRight = fabsf(x - range.right); + float minDist = fminf(distLeft, distRight); + float signedDistance = range.isDash ? minDist : -minDist; + + image.data[index + x] = static_cast<uint8_t>(fmaxf(0.0f, fminf(255.0f, signedDistance + 128.0f))); + } +} + +LinePatternPos addDashPattern(AlphaImage& image, + uint32_t yOffset, + const std::vector<float>& dasharray, + const LinePatternCap patternCap) { + const uint8_t n = patternCap == LinePatternCap::Round ? 7 : 0; + + if (dasharray.size() < 2) { + Log::Warning(Event::ParseStyle, "line dasharray requires at least two elements"); + return LinePatternPos(); + } + + float length = 0; + for (const float part : dasharray) { + length += part; + } + + float stretch = image.size.width / length; + std::vector<DashRange> ranges = getDashRanges(dasharray, stretch); + + if (patternCap == LinePatternCap::Round) { + addRoundDash(ranges, yOffset, stretch, n, image); + } else { + addRegularDash(ranges, yOffset, image); } LinePatternPos position; - position.y = (0.5 + yOffset + n) / image.size.height; - position.height = (2.0 * n + 1) / image.size.height; + position.y = (0.5f + yOffset + n) / image.size.height; + position.height = (2.0f * n + 1) / image.size.height; position.width = length; return position; @@ -107,7 +167,7 @@ DashPatternTexture::DashPatternTexture(const std::vector<float>& from_, const std::vector<float>& to_, const LinePatternCap cap) { const bool patternsIdentical = from_ == to_; - const int32_t patternHeight = cap == LinePatternCap::Round ? 15 : 1; + const uint32_t patternHeight = cap == LinePatternCap::Round ? 15 : 1; const uint32_t height = (patternsIdentical ? 1 : 2) * patternHeight; // The OpenGL ES 2.0 spec, section 3.8.2 states: diff --git a/src/mbgl/geometry/line_atlas.hpp b/src/mbgl/geometry/line_atlas.hpp index 853305d138..1be7cbf073 100644 --- a/src/mbgl/geometry/line_atlas.hpp +++ b/src/mbgl/geometry/line_atlas.hpp @@ -27,6 +27,13 @@ enum class LinePatternCap : bool { Round = true, }; +struct DashRange { + float left; + float right; + bool isDash; + bool isZeroLength; +}; + class DashPatternTexture { public: DashPatternTexture(const std::vector<float>& from, const std::vector<float>& to, LinePatternCap); diff --git a/src/mbgl/renderer/buckets/debug_bucket.cpp b/src/mbgl/renderer/buckets/debug_bucket.cpp index 13380c0905..fcdc727f4b 100644 --- a/src/mbgl/renderer/buckets/debug_bucket.cpp +++ b/src/mbgl/renderer/buckets/debug_bucket.cpp @@ -2,7 +2,6 @@ #include <mbgl/geometry/debug_font_data.hpp> #include <mbgl/tile/tile_id.hpp> #include <mbgl/util/string.hpp> -#include <mbgl/util/id.hpp> #include <cmath> #include <string> @@ -20,9 +19,7 @@ DebugBucket::DebugBucket(const OverscaledTileID& id, complete(complete_), modified(std::move(modified_)), expires(std::move(expires_)), - debugMode(debugMode_), - drawScopeID("__debug/" + util::toHex(util::nextID())) { - + debugMode(debugMode_) { auto addText = [&] (const std::string& text, double left, double baseline, double scale) { for (uint8_t c : text) { if (c < 32 || c >= 127) diff --git a/src/mbgl/renderer/buckets/debug_bucket.hpp b/src/mbgl/renderer/buckets/debug_bucket.hpp index 2b735b4987..78b1cbb8ff 100644 --- a/src/mbgl/renderer/buckets/debug_bucket.hpp +++ b/src/mbgl/renderer/buckets/debug_bucket.hpp @@ -40,9 +40,9 @@ public: gfx::IndexVector<gfx::Lines> indices; SegmentVector<DebugAttributes> segments; + SegmentVector<DebugAttributes> tileBorderSegments; optional<gfx::VertexBuffer<DebugLayoutVertex>> vertexBuffer; optional<gfx::IndexBuffer> indexBuffer; - const std::string drawScopeID; }; } // namespace mbgl diff --git a/src/mbgl/renderer/buckets/raster_bucket.cpp b/src/mbgl/renderer/buckets/raster_bucket.cpp index a26b9a5065..859ee8d2a2 100644 --- a/src/mbgl/renderer/buckets/raster_bucket.cpp +++ b/src/mbgl/renderer/buckets/raster_bucket.cpp @@ -2,21 +2,15 @@ #include <mbgl/renderer/layers/render_raster_layer.hpp> #include <mbgl/programs/raster_program.hpp> #include <mbgl/gfx/upload_pass.hpp> -#include <mbgl/util/id.hpp> namespace mbgl { using namespace style; RasterBucket::RasterBucket(PremultipliedImage&& image_) - : image(std::make_shared<PremultipliedImage>(std::move(image_))), - drawScopeID(util::toHex(util::nextID())) { -} + : image(std::make_shared<PremultipliedImage>(std::move(image_))) {} -RasterBucket::RasterBucket(std::shared_ptr<PremultipliedImage> image_) - : image(std::move(image_)), - drawScopeID(util::toHex(util::nextID())) { -} +RasterBucket::RasterBucket(std::shared_ptr<PremultipliedImage> image_) : image(std::move(image_)) {} RasterBucket::~RasterBucket() = default; @@ -27,8 +21,10 @@ void RasterBucket::upload(gfx::UploadPass& uploadPass) { if (!texture) { texture = uploadPass.createTexture(*image); } - if (!segments.empty()) { + if (!vertices.empty()) { vertexBuffer = uploadPass.createVertexBuffer(std::move(vertices)); + } + if (!indices.empty()) { indexBuffer = uploadPass.createIndexBuffer(std::move(indices)); } uploaded = true; diff --git a/src/mbgl/renderer/buckets/raster_bucket.hpp b/src/mbgl/renderer/buckets/raster_bucket.hpp index f880903167..0fa3c4299e 100644 --- a/src/mbgl/renderer/buckets/raster_bucket.hpp +++ b/src/mbgl/renderer/buckets/raster_bucket.hpp @@ -37,7 +37,6 @@ public: optional<gfx::VertexBuffer<RasterLayoutVertex>> vertexBuffer; optional<gfx::IndexBuffer> indexBuffer; - const std::string drawScopeID; }; } // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_background_layer.cpp b/src/mbgl/renderer/layers/render_background_layer.cpp index 694addcc97..96a4c44f08 100644 --- a/src/mbgl/renderer/layers/render_background_layer.cpp +++ b/src/mbgl/renderer/layers/render_background_layer.cpp @@ -7,7 +7,6 @@ #include <mbgl/renderer/image_manager.hpp> #include <mbgl/renderer/render_static_data.hpp> #include <mbgl/programs/programs.hpp> -#include <mbgl/programs/background_program.hpp> #include <mbgl/util/tile_cover.hpp> #include <mbgl/map/transform_state.hpp> #include <mbgl/gfx/cull_face_mode.hpp> @@ -18,7 +17,7 @@ using namespace style; namespace { -inline const BackgroundLayer::Impl& impl(const Immutable<style::Layer::Impl>& impl) { +inline const BackgroundLayer::Impl& impl_cast(const Immutable<style::Layer::Impl>& impl) { assert(impl->getTypeInfo() == BackgroundLayer::Impl::staticTypeInfo()); return static_cast<const style::BackgroundLayer::Impl&>(*impl); } @@ -27,13 +26,12 @@ inline const BackgroundLayer::Impl& impl(const Immutable<style::Layer::Impl>& im RenderBackgroundLayer::RenderBackgroundLayer(Immutable<style::BackgroundLayer::Impl> _impl) : RenderLayer(makeMutable<BackgroundLayerProperties>(std::move(_impl))), - unevaluated(impl(baseImpl).paint.untransitioned()) { -} + unevaluated(impl_cast(baseImpl).paint.untransitioned()) {} RenderBackgroundLayer::~RenderBackgroundLayer() = default; void RenderBackgroundLayer::transition(const TransitionParameters ¶meters) { - unevaluated = impl(baseImpl).paint.transitioned(parameters, std::move(unevaluated)); + unevaluated = impl_cast(baseImpl).paint.transitioned(parameters, std::move(unevaluated)); } void RenderBackgroundLayer::evaluate(const PropertyEvaluationParameters ¶meters) { @@ -69,7 +67,7 @@ void RenderBackgroundLayer::render(PaintParameters& parameters) { const Properties<>::PossiblyEvaluated properties; const BackgroundProgram::Binders paintAttributeData(properties, 0); - auto draw = [&](auto& program, auto&& uniformValues, const auto& textureBindings, const UnwrappedTileID& id) { + auto draw = [&](auto& program, auto&& uniformValues, const auto& textureBindings, const uint32_t id) { const auto allUniformValues = program.computeAllUniformValues( std::move(uniformValues), paintAttributeData, @@ -88,20 +86,24 @@ void RenderBackgroundLayer::render(PaintParameters& parameters) { parameters.context, *parameters.renderPass, gfx::Triangles(), - parameters.depthModeForSublayer(0, parameters.pass == RenderPass::Opaque - ? gfx::DepthMaskType::ReadWrite - : gfx::DepthMaskType::ReadOnly), + parameters.depthModeForSublayer( + 0, + parameters.pass == RenderPass::Opaque ? gfx::DepthMaskType::ReadWrite : gfx::DepthMaskType::ReadOnly), gfx::StencilMode::disabled(), parameters.colorModeForRenderPass(), gfx::CullFaceMode::disabled(), *parameters.staticData.quadTriangleIndexBuffer, - parameters.staticData.tileTriangleSegments, + segments, allUniformValues, allAttributeBindings, textureBindings, - getID() + "/" + util::toString(id) - ); + util::toString(id)); }; + + if (segments.empty()) { + segments = parameters.staticData.tileTriangleSegments(); + } + const auto& evaluated = static_cast<const BackgroundLayerProperties&>(*evaluatedProperties).evaluated; const auto& crossfade = static_cast<const BackgroundLayerProperties&>(*evaluatedProperties).crossfade; if (!evaluated.get<BackgroundPattern>().to.empty()) { @@ -113,24 +115,21 @@ void RenderBackgroundLayer::render(PaintParameters& parameters) { if (!imagePosA || !imagePosB) return; + uint32_t i = 0; for (const auto& tileID : util::tileCover(parameters.state, parameters.state.getIntegerZoom())) { - draw( - parameters.programs.getBackgroundLayerPrograms().backgroundPattern, - BackgroundPatternProgram::layoutUniformValues( - parameters.matrixForTile(tileID), - evaluated.get<BackgroundOpacity>(), - parameters.patternAtlas.getPixelSize(), - *imagePosA, - *imagePosB, - crossfade, - tileID, - parameters.state - ), - BackgroundPatternProgram::TextureBindings{ - textures::image::Value{ parameters.patternAtlas.textureBinding() }, - }, - tileID - ); + draw(parameters.programs.getBackgroundLayerPrograms().backgroundPattern, + BackgroundPatternProgram::layoutUniformValues(parameters.matrixForTile(tileID), + evaluated.get<BackgroundOpacity>(), + parameters.patternAtlas.getPixelSize(), + *imagePosA, + *imagePosB, + crossfade, + tileID, + parameters.state), + BackgroundPatternProgram::TextureBindings{ + textures::image::Value{parameters.patternAtlas.textureBinding()}, + }, + i++); } } else { auto backgroundRenderPass = (evaluated.get<BackgroundColor>().a >= 1.0f @@ -139,17 +138,16 @@ void RenderBackgroundLayer::render(PaintParameters& parameters) { if (parameters.pass != backgroundRenderPass) { return; } + uint32_t i = 0; for (const auto& tileID : util::tileCover(parameters.state, parameters.state.getIntegerZoom())) { - draw( - parameters.programs.getBackgroundLayerPrograms().background, - BackgroundProgram::LayoutUniformValues { - uniforms::matrix::Value( parameters.matrixForTile(tileID) ), - uniforms::color::Value( evaluated.get<BackgroundColor>() ), - uniforms::opacity::Value( evaluated.get<BackgroundOpacity>() ), - }, - BackgroundProgram::TextureBindings{}, - tileID - ); + draw(parameters.programs.getBackgroundLayerPrograms().background, + BackgroundProgram::LayoutUniformValues{ + uniforms::matrix::Value(parameters.matrixForTile(tileID)), + uniforms::color::Value(evaluated.get<BackgroundColor>()), + uniforms::opacity::Value(evaluated.get<BackgroundOpacity>()), + }, + BackgroundProgram::TextureBindings{}, + i++); } } } diff --git a/src/mbgl/renderer/layers/render_background_layer.hpp b/src/mbgl/renderer/layers/render_background_layer.hpp index dfc2adf76e..dab733172b 100644 --- a/src/mbgl/renderer/layers/render_background_layer.hpp +++ b/src/mbgl/renderer/layers/render_background_layer.hpp @@ -1,5 +1,6 @@ #pragma once +#include <mbgl/programs/background_program.hpp> #include <mbgl/renderer/render_layer.hpp> #include <mbgl/style/layers/background_layer_impl.hpp> #include <mbgl/style/layers/background_layer_properties.hpp> @@ -22,6 +23,7 @@ private: // Paint properties style::BackgroundPaintProperties::Unevaluated unevaluated; + SegmentVector<BackgroundAttributes> segments; }; } // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_circle_layer.cpp b/src/mbgl/renderer/layers/render_circle_layer.cpp index b88a026e11..e5d7e6230e 100644 --- a/src/mbgl/renderer/layers/render_circle_layer.cpp +++ b/src/mbgl/renderer/layers/render_circle_layer.cpp @@ -17,7 +17,7 @@ using namespace style; namespace { -inline const style::CircleLayer::Impl& impl(const Immutable<style::Layer::Impl>& impl) { +inline const style::CircleLayer::Impl& impl_cast(const Immutable<style::Layer::Impl>& impl) { assert(impl->getTypeInfo() == CircleLayer::Impl::staticTypeInfo()); return static_cast<const style::CircleLayer::Impl&>(*impl); } @@ -26,11 +26,10 @@ inline const style::CircleLayer::Impl& impl(const Immutable<style::Layer::Impl>& RenderCircleLayer::RenderCircleLayer(Immutable<style::CircleLayer::Impl> _impl) : RenderLayer(makeMutable<CircleLayerProperties>(std::move(_impl))), - unevaluated(impl(baseImpl).paint.untransitioned()) { -} + unevaluated(impl_cast(baseImpl).paint.untransitioned()) {} void RenderCircleLayer::transition(const TransitionParameters& parameters) { - unevaluated = impl(baseImpl).paint.transitioned(parameters, std::move(unevaluated)); + unevaluated = impl_cast(baseImpl).paint.transitioned(parameters, std::move(unevaluated)); } void RenderCircleLayer::evaluate(const PropertyEvaluationParameters& parameters) { diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp index af0bc788d0..4eaec6e55f 100644 --- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp @@ -23,7 +23,7 @@ using namespace style; namespace { -inline const FillExtrusionLayer::Impl& impl(const Immutable<style::Layer::Impl>& impl) { +inline const FillExtrusionLayer::Impl& impl_cast(const Immutable<style::Layer::Impl>& impl) { assert(impl->getTypeInfo() == FillExtrusionLayer::Impl::staticTypeInfo()); return static_cast<const FillExtrusionLayer::Impl&>(*impl); } @@ -32,13 +32,12 @@ inline const FillExtrusionLayer::Impl& impl(const Immutable<style::Layer::Impl>& RenderFillExtrusionLayer::RenderFillExtrusionLayer(Immutable<style::FillExtrusionLayer::Impl> _impl) : RenderLayer(makeMutable<FillExtrusionLayerProperties>(std::move(_impl))), - unevaluated(impl(baseImpl).paint.untransitioned()) { -} + unevaluated(impl_cast(baseImpl).paint.untransitioned()) {} RenderFillExtrusionLayer::~RenderFillExtrusionLayer() = default; void RenderFillExtrusionLayer::transition(const TransitionParameters& parameters) { - unevaluated = impl(baseImpl).paint.transitioned(parameters, std::move(unevaluated)); + unevaluated = impl_cast(baseImpl).paint.transitioned(parameters, std::move(unevaluated)); } void RenderFillExtrusionLayer::evaluate(const PropertyEvaluationParameters& parameters) { diff --git a/src/mbgl/renderer/layers/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp index bbfcef7aba..31b847b6a7 100644 --- a/src/mbgl/renderer/layers/render_fill_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_layer.cpp @@ -24,7 +24,7 @@ using namespace style; namespace { -inline const FillLayer::Impl& impl(const Immutable<style::Layer::Impl>& impl) { +inline const FillLayer::Impl& impl_cast(const Immutable<style::Layer::Impl>& impl) { assert(impl->getTypeInfo() == FillLayer::Impl::staticTypeInfo()); return static_cast<const FillLayer::Impl&>(*impl); } @@ -33,13 +33,12 @@ inline const FillLayer::Impl& impl(const Immutable<style::Layer::Impl>& impl) { RenderFillLayer::RenderFillLayer(Immutable<style::FillLayer::Impl> _impl) : RenderLayer(makeMutable<FillLayerProperties>(std::move(_impl))), - unevaluated(impl(baseImpl).paint.untransitioned()) { -} + unevaluated(impl_cast(baseImpl).paint.untransitioned()) {} RenderFillLayer::~RenderFillLayer() = default; void RenderFillLayer::transition(const TransitionParameters& parameters) { - unevaluated = impl(baseImpl).paint.transitioned(parameters, std::move(unevaluated)); + unevaluated = impl_cast(baseImpl).paint.transitioned(parameters, std::move(unevaluated)); } void RenderFillLayer::evaluate(const PropertyEvaluationParameters& parameters) { diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.cpp b/src/mbgl/renderer/layers/render_heatmap_layer.cpp index 797aedd297..5f3c36e440 100644 --- a/src/mbgl/renderer/layers/render_heatmap_layer.cpp +++ b/src/mbgl/renderer/layers/render_heatmap_layer.cpp @@ -4,7 +4,6 @@ #include <mbgl/renderer/paint_parameters.hpp> #include <mbgl/renderer/render_static_data.hpp> #include <mbgl/programs/programs.hpp> -#include <mbgl/programs/heatmap_program.hpp> #include <mbgl/tile/tile.hpp> #include <mbgl/style/layers/heatmap_layer.hpp> #include <mbgl/style/layers/heatmap_layer_impl.hpp> @@ -21,7 +20,7 @@ using namespace style; namespace { -inline const HeatmapLayer::Impl& impl(const Immutable<Layer::Impl>& impl) { +inline const HeatmapLayer::Impl& impl_cast(const Immutable<Layer::Impl>& impl) { assert(impl->getTypeInfo() == HeatmapLayer::Impl::staticTypeInfo()); return static_cast<const HeatmapLayer::Impl&>(*impl); } @@ -30,13 +29,13 @@ inline const HeatmapLayer::Impl& impl(const Immutable<Layer::Impl>& impl) { RenderHeatmapLayer::RenderHeatmapLayer(Immutable<HeatmapLayer::Impl> _impl) : RenderLayer(makeMutable<HeatmapLayerProperties>(std::move(_impl))), - unevaluated(impl(baseImpl).paint.untransitioned()), colorRamp({256, 1}) { -} + unevaluated(impl_cast(baseImpl).paint.untransitioned()), + colorRamp({256, 1}) {} RenderHeatmapLayer::~RenderHeatmapLayer() = default; void RenderHeatmapLayer::transition(const TransitionParameters& parameters) { - unevaluated = impl(baseImpl).paint.transitioned(parameters, std::move(unevaluated)); + unevaluated = impl_cast(baseImpl).paint.transitioned(parameters, std::move(unevaluated)); updateColorRamp(); } @@ -177,6 +176,10 @@ void RenderHeatmapLayer::render(PaintParameters& parameters) { checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); + if (segments.empty()) { + // Copy over the segments so that we can create our own DrawScopes. + segments = parameters.staticData.heatmapTextureSegments(); + } programInstance.draw( parameters.context, *parameters.renderPass, @@ -186,15 +189,14 @@ void RenderHeatmapLayer::render(PaintParameters& parameters) { parameters.colorModeForRenderPass(), gfx::CullFaceMode::disabled(), *parameters.staticData.quadTriangleIndexBuffer, - parameters.staticData.heatmapTextureSegments, + segments, allUniformValues, allAttributeBindings, HeatmapTextureProgram::TextureBindings{ - textures::image::Value{ renderTexture->getTexture().getResource(), gfx::TextureFilterType::Linear }, - textures::color_ramp::Value{ colorRampTexture->getResource(), gfx::TextureFilterType::Linear }, + textures::image::Value{renderTexture->getTexture().getResource(), gfx::TextureFilterType::Linear}, + textures::color_ramp::Value{colorRampTexture->getResource(), gfx::TextureFilterType::Linear}, }, - getID() - ); + getID()); } } diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.hpp b/src/mbgl/renderer/layers/render_heatmap_layer.hpp index 1e9b1063ae..b7a03a6ba5 100644 --- a/src/mbgl/renderer/layers/render_heatmap_layer.hpp +++ b/src/mbgl/renderer/layers/render_heatmap_layer.hpp @@ -1,10 +1,11 @@ #pragma once +#include <mbgl/gfx/offscreen_texture.hpp> +#include <mbgl/gfx/texture.hpp> +#include <mbgl/programs/heatmap_program.hpp> #include <mbgl/renderer/render_layer.hpp> #include <mbgl/style/layers/heatmap_layer_impl.hpp> #include <mbgl/style/layers/heatmap_layer_properties.hpp> -#include <mbgl/gfx/texture.hpp> -#include <mbgl/gfx/offscreen_texture.hpp> #include <mbgl/util/optional.hpp> namespace mbgl { @@ -24,14 +25,14 @@ private: bool queryIntersectsFeature(const GeometryCoordinates&, const GeometryTileFeature&, const float, const TransformState&, const float, const mat4&, const FeatureState&) const override; + void updateColorRamp(); // Paint properties style::HeatmapPaintProperties::Unevaluated unevaluated; PremultipliedImage colorRamp; std::unique_ptr<gfx::OffscreenTexture> renderTexture; optional<gfx::Texture> colorRampTexture; - - void updateColorRamp(); + SegmentVector<HeatmapTextureAttributes> segments; }; } // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_hillshade_layer.cpp b/src/mbgl/renderer/layers/render_hillshade_layer.cpp index b570d9c4c9..bf899221f8 100644 --- a/src/mbgl/renderer/layers/render_hillshade_layer.cpp +++ b/src/mbgl/renderer/layers/render_hillshade_layer.cpp @@ -20,7 +20,7 @@ using namespace style; namespace { -inline const HillshadeLayer::Impl& impl(const Immutable<style::Layer::Impl>& impl) { +inline const HillshadeLayer::Impl& impl_cast(const Immutable<style::Layer::Impl>& impl) { assert(impl->getTypeInfo() == HillshadeLayer::Impl::staticTypeInfo()); return static_cast<const HillshadeLayer::Impl&>(*impl); } @@ -29,8 +29,7 @@ inline const HillshadeLayer::Impl& impl(const Immutable<style::Layer::Impl>& imp RenderHillshadeLayer::RenderHillshadeLayer(Immutable<style::HillshadeLayer::Impl> _impl) : RenderLayer(makeMutable<HillshadeLayerProperties>(std::move(_impl))), - unevaluated(impl(baseImpl).paint.untransitioned()) { -} + unevaluated(impl_cast(baseImpl).paint.untransitioned()) {} RenderHillshadeLayer::~RenderHillshadeLayer() = default; @@ -48,7 +47,7 @@ const std::array<float, 2> RenderHillshadeLayer::getLight(const PaintParameters& } void RenderHillshadeLayer::transition(const TransitionParameters& parameters) { - unevaluated = impl(baseImpl).paint.transitioned(parameters, std::move(unevaluated)); + unevaluated = impl_cast(baseImpl).paint.transitioned(parameters, std::move(unevaluated)); } void RenderHillshadeLayer::evaluate(const PropertyEvaluationParameters& parameters) { @@ -111,21 +110,19 @@ void RenderHillshadeLayer::render(PaintParameters& parameters) { checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); - programInstance.draw( - parameters.context, - *parameters.renderPass, - gfx::Triangles(), - parameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly), - gfx::StencilMode::disabled(), - parameters.colorModeForRenderPass(), - gfx::CullFaceMode::disabled(), - indexBuffer, - segments, - allUniformValues, - allAttributeBindings, - textureBindings, - getID() + "/" + util::toString(id) - ); + programInstance.draw(parameters.context, + *parameters.renderPass, + gfx::Triangles(), + parameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly), + gfx::StencilMode::disabled(), + parameters.colorModeForRenderPass(), + gfx::CullFaceMode::disabled(), + indexBuffer, + segments, + allUniformValues, + allAttributeBindings, + textureBindings, + getID()); }; mat4 mat; @@ -177,29 +174,30 @@ void RenderHillshadeLayer::render(PaintParameters& parameters) { checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); - programInstance.draw( - parameters.context, - *renderPass, - gfx::Triangles(), - parameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly), - gfx::StencilMode::disabled(), - parameters.colorModeForRenderPass(), - gfx::CullFaceMode::disabled(), - *parameters.staticData.quadTriangleIndexBuffer, - parameters.staticData.rasterSegments, - allUniformValues, - allAttributeBindings, - HillshadePrepareProgram::TextureBindings{ - textures::image::Value{ bucket.dem->getResource() }, - }, - getID() + "/p/" + util::toString(tile.id) - ); + // Copy over the segments so that we can create our own DrawScopes that get destroyed + // after this draw call. + auto segments = parameters.staticData.rasterSegments(); + programInstance.draw(parameters.context, + *renderPass, + gfx::Triangles(), + parameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly), + gfx::StencilMode::disabled(), + parameters.colorModeForRenderPass(), + gfx::CullFaceMode::disabled(), + *parameters.staticData.quadTriangleIndexBuffer, + segments, + allUniformValues, + allAttributeBindings, + HillshadePrepareProgram::TextureBindings{ + textures::image::Value{bucket.dem->getResource()}, + }, + "prepare"); bucket.texture = std::move(view->getTexture()); bucket.setPrepared(true); } else if (parameters.pass == RenderPass::Translucent) { assert(bucket.texture); - if (bucket.vertexBuffer && bucket.indexBuffer && !bucket.segments.empty()) { + if (bucket.vertexBuffer && bucket.indexBuffer) { // Draw only the parts of the tile that aren't drawn by another tile in the layer. draw(parameters.matrixForTile(tile.id, true), *bucket.vertexBuffer, @@ -211,13 +209,17 @@ void RenderHillshadeLayer::render(PaintParameters& parameters) { }); } else { // Draw the full tile. + if (bucket.segments.empty()) { + // Copy over the segments so that we can create our own DrawScopes. + bucket.segments = parameters.staticData.rasterSegments(); + } draw(parameters.matrixForTile(tile.id, true), *parameters.staticData.rasterVertexBuffer, *parameters.staticData.quadTriangleIndexBuffer, - parameters.staticData.rasterSegments, + bucket.segments, tile.id, HillshadeProgram::TextureBindings{ - textures::image::Value{ bucket.texture->getResource(), gfx::TextureFilterType::Linear }, + textures::image::Value{bucket.texture->getResource(), gfx::TextureFilterType::Linear}, }); } } diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp index 588cf6286c..90bb38b9f9 100644 --- a/src/mbgl/renderer/layers/render_line_layer.cpp +++ b/src/mbgl/renderer/layers/render_line_layer.cpp @@ -23,7 +23,7 @@ using namespace style; namespace { -inline const LineLayer::Impl& impl(const Immutable<style::Layer::Impl>& impl) { +inline const LineLayer::Impl& impl_cast(const Immutable<style::Layer::Impl>& impl) { assert(impl->getTypeInfo() == LineLayer::Impl::staticTypeInfo()); return static_cast<const LineLayer::Impl&>(*impl); } @@ -32,14 +32,13 @@ inline const LineLayer::Impl& impl(const Immutable<style::Layer::Impl>& impl) { RenderLineLayer::RenderLineLayer(Immutable<style::LineLayer::Impl> _impl) : RenderLayer(makeMutable<LineLayerProperties>(std::move(_impl))), - unevaluated(impl(baseImpl).paint.untransitioned()), - colorRamp({256, 1}) { -} + unevaluated(impl_cast(baseImpl).paint.untransitioned()), + colorRamp({256, 1}) {} RenderLineLayer::~RenderLineLayer() = default; void RenderLineLayer::transition(const TransitionParameters& parameters) { - unevaluated = impl(baseImpl).paint.transitioned(parameters, std::move(unevaluated)); + unevaluated = impl_cast(baseImpl).paint.transitioned(parameters, std::move(unevaluated)); updateColorRamp(); } diff --git a/src/mbgl/renderer/layers/render_raster_layer.cpp b/src/mbgl/renderer/layers/render_raster_layer.cpp index 8a1a8a6c28..047333d5e5 100644 --- a/src/mbgl/renderer/layers/render_raster_layer.cpp +++ b/src/mbgl/renderer/layers/render_raster_layer.cpp @@ -16,7 +16,7 @@ using namespace style; namespace { -inline const RasterLayer::Impl& impl(const Immutable<style::Layer::Impl>& impl) { +inline const RasterLayer::Impl& impl_cast(const Immutable<style::Layer::Impl>& impl) { assert(impl->getTypeInfo() == RasterLayer::Impl::staticTypeInfo()); return static_cast<const RasterLayer::Impl&>(*impl); } @@ -25,13 +25,12 @@ inline const RasterLayer::Impl& impl(const Immutable<style::Layer::Impl>& impl) RenderRasterLayer::RenderRasterLayer(Immutable<style::RasterLayer::Impl> _impl) : RenderLayer(makeMutable<RasterLayerProperties>(std::move(_impl))), - unevaluated(impl(baseImpl).paint.untransitioned()) { -} + unevaluated(impl_cast(baseImpl).paint.untransitioned()) {} RenderRasterLayer::~RenderRasterLayer() = default; void RenderRasterLayer::transition(const TransitionParameters& parameters) { - unevaluated = impl(baseImpl).paint.transitioned(parameters, std::move(unevaluated)); + unevaluated = impl_cast(baseImpl).paint.transitioned(parameters, std::move(unevaluated)); } void RenderRasterLayer::evaluate(const PropertyEvaluationParameters& parameters) { @@ -153,14 +152,14 @@ void RenderRasterLayer::render(PaintParameters& parameters) { size_t i = 0; for (const auto& matrix_ : imageData->matrices) { draw(matrix_, - *bucket.vertexBuffer, - *bucket.indexBuffer, - bucket.segments, - RasterProgram::TextureBindings{ - textures::image0::Value{ bucket.texture->getResource(), filter }, - textures::image1::Value{ bucket.texture->getResource(), filter }, - }, - bucket.drawScopeID + std::to_string(i++)); + *bucket.vertexBuffer, + *bucket.indexBuffer, + bucket.segments, + RasterProgram::TextureBindings{ + textures::image0::Value{bucket.texture->getResource(), filter}, + textures::image1::Value{bucket.texture->getResource(), filter}, + }, + std::to_string(i++)); } } else if (renderTiles) { for (const RenderTile& tile : *renderTiles) { @@ -174,28 +173,32 @@ void RenderRasterLayer::render(PaintParameters& parameters) { continue; assert(bucket.texture); - if (bucket.vertexBuffer && bucket.indexBuffer && !bucket.segments.empty()) { + if (bucket.vertexBuffer && bucket.indexBuffer) { // Draw only the parts of the tile that aren't drawn by another tile in the layer. draw(parameters.matrixForTile(tile.id, true), *bucket.vertexBuffer, *bucket.indexBuffer, bucket.segments, RasterProgram::TextureBindings{ - textures::image0::Value{ bucket.texture->getResource(), filter }, - textures::image1::Value{ bucket.texture->getResource(), filter }, + textures::image0::Value{bucket.texture->getResource(), filter}, + textures::image1::Value{bucket.texture->getResource(), filter}, }, - bucket.drawScopeID); + "image"); } else { // Draw the full tile. + if (bucket.segments.empty()) { + // Copy over the segments so that we can create our own DrawScopes. + bucket.segments = parameters.staticData.rasterSegments(); + } draw(parameters.matrixForTile(tile.id, true), *parameters.staticData.rasterVertexBuffer, *parameters.staticData.quadTriangleIndexBuffer, - parameters.staticData.rasterSegments, + bucket.segments, RasterProgram::TextureBindings{ - textures::image0::Value{ bucket.texture->getResource(), filter }, - textures::image1::Value{ bucket.texture->getResource(), filter }, + textures::image0::Value{bucket.texture->getResource(), filter}, + textures::image1::Value{bucket.texture->getResource(), filter}, }, - bucket.drawScopeID); + "image"); } } } diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 955ad2ce51..2a94c452c7 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -290,7 +290,7 @@ void drawText(const DrawFn& draw, } } -inline const SymbolLayer::Impl& impl(const Immutable<style::Layer::Impl>& impl) { +inline const SymbolLayer::Impl& impl_cast(const Immutable<style::Layer::Impl>& impl) { assert(impl->getTypeInfo() == SymbolLayer::Impl::staticTypeInfo()); return static_cast<const SymbolLayer::Impl&>(*impl); } @@ -299,14 +299,14 @@ inline const SymbolLayer::Impl& impl(const Immutable<style::Layer::Impl>& impl) RenderSymbolLayer::RenderSymbolLayer(Immutable<style::SymbolLayer::Impl> _impl) : RenderLayer(makeMutable<SymbolLayerProperties>(std::move(_impl))), - unevaluated(impl(baseImpl).paint.untransitioned()) { -} + unevaluated(impl_cast(baseImpl).paint.untransitioned()) {} RenderSymbolLayer::~RenderSymbolLayer() = default; void RenderSymbolLayer::transition(const TransitionParameters& parameters) { - unevaluated = impl(baseImpl).paint.transitioned(parameters, std::move(unevaluated)); - hasFormatSectionOverrides = SymbolLayerPaintPropertyOverrides::hasOverrides(impl(baseImpl).layout.get<TextField>()); + unevaluated = impl_cast(baseImpl).paint.transitioned(parameters, std::move(unevaluated)); + hasFormatSectionOverrides = + SymbolLayerPaintPropertyOverrides::hasOverrides(impl_cast(baseImpl).layout.get<TextField>()); } void RenderSymbolLayer::evaluate(const PropertyEvaluationParameters& parameters) { @@ -314,7 +314,7 @@ void RenderSymbolLayer::evaluate(const PropertyEvaluationParameters& parameters) staticImmutableCast<SymbolLayer::Impl>(baseImpl), unevaluated.evaluate(parameters)); auto& evaluated = properties->evaluated; - auto& layout = impl(baseImpl).layout; + auto& layout = impl_cast(baseImpl).layout; if (hasFormatSectionOverrides) { SymbolLayerPaintPropertyOverrides::setOverrides(layout, evaluated); @@ -346,7 +346,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters) { return; } - const bool sortFeaturesByKey = !impl(baseImpl).layout.get<SymbolSortKey>().isUndefined(); + const bool sortFeaturesByKey = !impl_cast(baseImpl).layout.get<SymbolSortKey>().isUndefined(); std::multiset<RenderableSegment> renderableSegments; const auto draw = [¶meters, this] (auto& programInstance, diff --git a/src/mbgl/renderer/paint_parameters.cpp b/src/mbgl/renderer/paint_parameters.cpp index 6c6abc008b..b2f958b14e 100644 --- a/src/mbgl/renderer/paint_parameters.cpp +++ b/src/mbgl/renderer/paint_parameters.cpp @@ -129,39 +129,30 @@ void PaintParameters::renderTileClippingMasks(const RenderTiles& renderTiles) { const int32_t stencilID = nextStencilID++; tileClippingMaskIDs.emplace(renderTile.id, stencilID); - program.draw( - context, - *renderPass, - gfx::Triangles(), - gfx::DepthMode::disabled(), - gfx::StencilMode { - gfx::StencilMode::Always{}, - stencilID, - 0b11111111, - gfx::StencilOpType::Keep, - gfx::StencilOpType::Keep, - gfx::StencilOpType::Replace - }, - gfx::ColorMode::disabled(), - gfx::CullFaceMode::disabled(), - *staticData.quadTriangleIndexBuffer, - staticData.tileTriangleSegments, - program.computeAllUniformValues( - ClippingMaskProgram::LayoutUniformValues { - uniforms::matrix::Value( matrixForTile(renderTile.id) ), - }, - paintAttributeData, - properties, - state.getZoom() - ), - program.computeAllAttributeBindings( - *staticData.tileVertexBuffer, - paintAttributeData, - properties - ), - ClippingMaskProgram::TextureBindings{}, - "clipping/" + util::toString(stencilID) - ); + program.draw(context, + *renderPass, + gfx::Triangles(), + gfx::DepthMode::disabled(), + gfx::StencilMode{gfx::StencilMode::Always{}, + stencilID, + 0b11111111, + gfx::StencilOpType::Keep, + gfx::StencilOpType::Keep, + gfx::StencilOpType::Replace}, + gfx::ColorMode::disabled(), + gfx::CullFaceMode::disabled(), + *staticData.quadTriangleIndexBuffer, + staticData.clippingMaskSegments, + program.computeAllUniformValues( + ClippingMaskProgram::LayoutUniformValues{ + uniforms::matrix::Value(matrixForTile(renderTile.id)), + }, + paintAttributeData, + properties, + state.getZoom()), + program.computeAllAttributeBindings(*staticData.tileVertexBuffer, paintAttributeData, properties), + ClippingMaskProgram::TextureBindings{}, + "clipping/" + util::toString(stencilID)); } } diff --git a/src/mbgl/renderer/render_static_data.cpp b/src/mbgl/renderer/render_static_data.cpp index 6378ad9989..f7d9c18a78 100644 --- a/src/mbgl/renderer/render_static_data.cpp +++ b/src/mbgl/renderer/render_static_data.cpp @@ -50,15 +50,37 @@ static gfx::VertexVector<HeatmapTextureLayoutVertex> heatmapTextureVertices() { } RenderStaticData::RenderStaticData(gfx::Context& context, float pixelRatio) - : programs(context, ProgramParameters { pixelRatio, false }) + : programs(context, ProgramParameters{pixelRatio, false}), + clippingMaskSegments(tileTriangleSegments()) #ifndef NDEBUG - , overdrawPrograms(context, ProgramParameters { pixelRatio, true }) + , + overdrawPrograms(context, ProgramParameters{pixelRatio, true}) #endif { - tileTriangleSegments.emplace_back(0, 0, 4, 6); - tileBorderSegments.emplace_back(0, 0, 4, 5); - rasterSegments.emplace_back(0, 0, 4, 6); - heatmapTextureSegments.emplace_back(0, 0, 4, 6); +} + +SegmentVector<BackgroundAttributes> RenderStaticData::tileTriangleSegments() { + SegmentVector<BackgroundAttributes> segments; + segments.emplace_back(0, 0, 4, 6); + return segments; +} + +SegmentVector<DebugAttributes> RenderStaticData::tileBorderSegments() { + SegmentVector<DebugAttributes> segments; + segments.emplace_back(0, 0, 4, 5); + return segments; +} + +SegmentVector<RasterAttributes> RenderStaticData::rasterSegments() { + SegmentVector<RasterAttributes> segments; + segments.emplace_back(0, 0, 4, 6); + return segments; +} + +SegmentVector<HeatmapTextureAttributes> RenderStaticData::heatmapTextureSegments() { + SegmentVector<HeatmapTextureAttributes> segments; + segments.emplace_back(0, 0, 4, 6); + return segments; } void RenderStaticData::upload(gfx::UploadPass& uploadPass) { diff --git a/src/mbgl/renderer/render_static_data.hpp b/src/mbgl/renderer/render_static_data.hpp index 6bf2c846f4..22b29387db 100644 --- a/src/mbgl/renderer/render_static_data.hpp +++ b/src/mbgl/renderer/render_static_data.hpp @@ -30,10 +30,10 @@ public: optional<gfx::IndexBuffer> quadTriangleIndexBuffer; optional<gfx::IndexBuffer> tileBorderIndexBuffer; - SegmentVector<BackgroundAttributes> tileTriangleSegments; - SegmentVector<DebugAttributes> tileBorderSegments; - SegmentVector<RasterAttributes> rasterSegments; - SegmentVector<HeatmapTextureAttributes> heatmapTextureSegments; + static SegmentVector<BackgroundAttributes> tileTriangleSegments(); + static SegmentVector<DebugAttributes> tileBorderSegments(); + static SegmentVector<RasterAttributes> rasterSegments(); + static SegmentVector<HeatmapTextureAttributes> heatmapTextureSegments(); optional<gfx::Renderbuffer<gfx::RenderbufferPixelType::Depth>> depthRenderbuffer; bool has3D = false; @@ -42,6 +42,8 @@ public: Programs programs; + const SegmentVector<BackgroundAttributes> clippingMaskSegments; + #ifndef NDEBUG Programs overdrawPrograms; #endif diff --git a/src/mbgl/renderer/render_tile.cpp b/src/mbgl/renderer/render_tile.cpp index 70db10fa08..ce5fef05b8 100644 --- a/src/mbgl/renderer/render_tile.cpp +++ b/src/mbgl/renderer/render_tile.cpp @@ -147,81 +147,66 @@ void RenderTile::finishRender(PaintParameters& parameters) const { program.draw( parameters.context, *parameters.renderPass, - gfx::Lines { 4.0f * parameters.pixelRatio }, + gfx::Lines{4.0f * parameters.pixelRatio}, gfx::DepthMode::disabled(), gfx::StencilMode::disabled(), gfx::ColorMode::unblended(), gfx::CullFaceMode::disabled(), *debugBucket->indexBuffer, debugBucket->segments, - program.computeAllUniformValues( - DebugProgram::LayoutUniformValues { - uniforms::matrix::Value( matrix ), - uniforms::color::Value( Color::white() ) - }, - paintAttributeData, - properties, - parameters.state.getZoom() - ), + program.computeAllUniformValues(DebugProgram::LayoutUniformValues{uniforms::matrix::Value(matrix), + uniforms::color::Value(Color::white())}, + paintAttributeData, + properties, + parameters.state.getZoom()), allAttributeBindings, DebugProgram::TextureBindings{}, - "__debug/" + debugBucket->drawScopeID + "/text-outline" - ); + "text-outline"); program.draw( parameters.context, *parameters.renderPass, - gfx::Lines { 2.0f * parameters.pixelRatio }, + gfx::Lines{2.0f * parameters.pixelRatio}, gfx::DepthMode::disabled(), gfx::StencilMode::disabled(), gfx::ColorMode::unblended(), gfx::CullFaceMode::disabled(), *debugBucket->indexBuffer, debugBucket->segments, - program.computeAllUniformValues( - DebugProgram::LayoutUniformValues { - uniforms::matrix::Value( matrix ), - uniforms::color::Value( Color::black() ) - }, - paintAttributeData, - properties, - parameters.state.getZoom() - ), + program.computeAllUniformValues(DebugProgram::LayoutUniformValues{uniforms::matrix::Value(matrix), + uniforms::color::Value(Color::black())}, + paintAttributeData, + properties, + parameters.state.getZoom()), allAttributeBindings, DebugProgram::TextureBindings{}, - "__debug/" + debugBucket->drawScopeID + "/text" - ); + "text"); } if (parameters.debugOptions & MapDebugOptions::TileBorders) { assert(debugBucket); + if (debugBucket->tileBorderSegments.empty()) { + debugBucket->tileBorderSegments = parameters.staticData.tileBorderSegments(); + } parameters.programs.debug.draw( parameters.context, *parameters.renderPass, - gfx::LineStrip { 4.0f * parameters.pixelRatio }, + gfx::LineStrip{4.0f * parameters.pixelRatio}, gfx::DepthMode::disabled(), gfx::StencilMode::disabled(), gfx::ColorMode::unblended(), gfx::CullFaceMode::disabled(), *parameters.staticData.tileBorderIndexBuffer, - parameters.staticData.tileBorderSegments, - program.computeAllUniformValues( - DebugProgram::LayoutUniformValues { - uniforms::matrix::Value( matrix ), - uniforms::color::Value( Color::red() ) - }, - paintAttributeData, - properties, - parameters.state.getZoom() - ), + debugBucket->tileBorderSegments, + program.computeAllUniformValues(DebugProgram::LayoutUniformValues{uniforms::matrix::Value(matrix), + uniforms::color::Value(Color::red())}, + paintAttributeData, + properties, + parameters.state.getZoom()), program.computeAllAttributeBindings( - *parameters.staticData.tileVertexBuffer, - paintAttributeData, - properties - ), + *parameters.staticData.tileVertexBuffer, paintAttributeData, properties), DebugProgram::TextureBindings{}, - "__debug/" + debugBucket->drawScopeID - ); + "border"); } } diff --git a/src/mbgl/renderer/sources/render_image_source.cpp b/src/mbgl/renderer/sources/render_image_source.cpp index 6d197df9db..30f1bbcee6 100644 --- a/src/mbgl/renderer/sources/render_image_source.cpp +++ b/src/mbgl/renderer/sources/render_image_source.cpp @@ -36,33 +36,25 @@ void ImageSourceRenderData::render(PaintParameters& parameters) const { auto& programInstance = parameters.programs.debug; for (auto matrix : matrices) { - programInstance.draw( - parameters.context, - *parameters.renderPass, - gfx::LineStrip { 4.0f * parameters.pixelRatio }, - gfx::DepthMode::disabled(), - gfx::StencilMode::disabled(), - gfx::ColorMode::unblended(), - gfx::CullFaceMode::disabled(), - *parameters.staticData.tileBorderIndexBuffer, - parameters.staticData.tileBorderSegments, - programInstance.computeAllUniformValues( - DebugProgram::LayoutUniformValues { - uniforms::matrix::Value( matrix ), - uniforms::color::Value( Color::red() ) - }, - paintAttributeData, - properties, - parameters.state.getZoom() - ), - programInstance.computeAllAttributeBindings( - *parameters.staticData.tileVertexBuffer, - paintAttributeData, - properties - ), - DebugProgram::TextureBindings{}, - "image" - ); + programInstance.draw(parameters.context, + *parameters.renderPass, + gfx::LineStrip{4.0f * parameters.pixelRatio}, + gfx::DepthMode::disabled(), + gfx::StencilMode::disabled(), + gfx::ColorMode::unblended(), + gfx::CullFaceMode::disabled(), + *parameters.staticData.tileBorderIndexBuffer, + parameters.staticData.tileBorderSegments(), + programInstance.computeAllUniformValues( + DebugProgram::LayoutUniformValues{uniforms::matrix::Value(matrix), + uniforms::color::Value(Color::red())}, + paintAttributeData, + properties, + parameters.state.getZoom()), + programInstance.computeAllAttributeBindings( + *parameters.staticData.tileVertexBuffer, paintAttributeData, properties), + DebugProgram::TextureBindings{}, + "image"); } } diff --git a/src/mbgl/sprite/sprite_loader.cpp b/src/mbgl/sprite/sprite_loader.cpp index 6051de7ef4..60bab2bf6e 100644 --- a/src/mbgl/sprite/sprite_loader.cpp +++ b/src/mbgl/sprite/sprite_loader.cpp @@ -58,8 +58,9 @@ void SpriteLoader::load(const std::string& url, FileSource& fileSource) { } else if (res.noContent) { loader->json = std::make_shared<std::string>(); emitSpriteLoadedIfComplete(); - } else if (loader->json != res.data) { // They can be equal, see OnlineFileRequest::completed(). + } else { // Only trigger a sprite loaded event we got new data. + assert(loader->json != res.data); loader->json = std::move(res.data); emitSpriteLoadedIfComplete(); } @@ -73,7 +74,8 @@ void SpriteLoader::load(const std::string& url, FileSource& fileSource) { } else if (res.noContent) { loader->image = std::make_shared<std::string>(); emitSpriteLoadedIfComplete(); - } else if (loader->image != res.data) { // They can be equal - see OnlineFileRequest::completed(). + } else { + assert(loader->image != res.data); loader->image = std::move(res.data); emitSpriteLoadedIfComplete(); } diff --git a/src/mbgl/util/id.cpp b/src/mbgl/util/id.cpp deleted file mode 100644 index 4486194de4..0000000000 --- a/src/mbgl/util/id.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include <mbgl/util/id.hpp> - -#include <atomic> - -namespace mbgl { -namespace util { - -uint64_t nextID() { - static std::atomic<uint64_t> GUID { 0 }; - return GUID++; -} - -} // namespace util -} // namespace mbgl diff --git a/src/mbgl/util/id.hpp b/src/mbgl/util/id.hpp deleted file mode 100644 index 12e23dfc2d..0000000000 --- a/src/mbgl/util/id.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include <cstdint> - -namespace mbgl { -namespace util { - -uint64_t nextID(); - -} // namespace util -} // namespace mbgl diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index dcde7cd21a..a9ae0ac874 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -134,6 +134,12 @@ else() COMPILE_FLAGS -Wno-shadow ) + set_source_files_properties( + ${PROJECT_SOURCE_DIR}/test/src/mbgl/test/http_server.cpp + PROPERTIES + COMPILE_OPTIONS + $<$<STREQUAL:${CMAKE_SYSTEM_NAME},iOS>:-Wno-shorten-64-to-32> + ) target_include_directories( mbgl-test PRIVATE ${PROJECT_SOURCE_DIR}/vendor/cpp-httplib @@ -167,6 +173,18 @@ target_include_directories( include(${PROJECT_SOURCE_DIR}/vendor/googletest.cmake) +if(CMAKE_SYSTEM_NAME STREQUAL iOS) + set_target_properties(mbgl-vendor-googletest PROPERTIES XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "${IOS_DEPLOYMENT_TARGET}") + set_target_properties(mbgl-vendor-googletest PROPERTIES XCODE_ATTRIBUTE_ENABLE_BITCODE "YES") + set_target_properties(mbgl-vendor-googletest PROPERTIES XCODE_ATTRIBUTE_BITCODE_GENERATION_MODE bitcode) + set_target_properties(mbgl-vendor-googletest PROPERTIES XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH $<$<CONFIG:Debug>:YES>) + + set_target_properties(mbgl-test PROPERTIES XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "${IOS_DEPLOYMENT_TARGET}") + set_target_properties(mbgl-test PROPERTIES XCODE_ATTRIBUTE_ENABLE_BITCODE "YES") + set_target_properties(mbgl-test PROPERTIES XCODE_ATTRIBUTE_BITCODE_GENERATION_MODE bitcode) + set_target_properties(mbgl-test PROPERTIES XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH $<$<CONFIG:Debug>:YES>) +endif() + # Needed for testing private classes get_target_property(MBGL_CORE_PRIVATE_LIBRARIES mbgl-core LINK_LIBRARIES) diff --git a/test/fixtures/local_glyphs/ping_fang/expected.png b/test/fixtures/local_glyphs/ping_fang/expected.png Binary files differindex 2ec62e1bc6..8c891a5232 100644 --- a/test/fixtures/local_glyphs/ping_fang/expected.png +++ b/test/fixtures/local_glyphs/ping_fang/expected.png diff --git a/test/include/mbgl/test/util.hpp b/test/include/mbgl/test/util.hpp index 959b3e646f..a8b1d1b2c6 100644 --- a/test/include/mbgl/test/util.hpp +++ b/test/include/mbgl/test/util.hpp @@ -4,17 +4,12 @@ #include <TargetConditionals.h> #endif -#if ANDROID - #define TEST_READ_ONLY 0 -#elif TARGET_OS_IOS - #define TEST_READ_ONLY 1 - #undef TEST_HAS_SERVER - #define TEST_HAS_SERVER 0 -#else - #define TEST_READ_ONLY 0 - #ifndef TEST_HAS_SERVER - #define TEST_HAS_SERVER 1 - #endif +#define TEST_READ_ONLY 0 + +#if !ANDROID +#ifndef TEST_HAS_SERVER +#define TEST_HAS_SERVER 1 +#endif #endif #if TARGET_OS_SIMULATOR diff --git a/test/ios/Info.plist b/test/ios/Info.plist new file mode 100644 index 0000000000..c53d0d06e9 --- /dev/null +++ b/test/ios/Info.plist @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN""http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>en</string> + <key>CFBundleDisplayName</key> + <string>${PRODUCT_NAME}</string> + <key>CFBundleExecutable</key> + <string>UnitTestsApp</string> + <key>CFBundleIdentifier</key> + <string>com.mapbox.UnitTestsApp</string> + <key>CFBundleGetInfoString</key> + <string>com.mapbox.UnitTestsApp</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>1.0</string> + <key>CFBundleLongVersionString</key> + <string>1.0</string> + <key>CFBundleName</key> + <string>com.mapbox.UnitTestsApp</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleSignature</key> + <string>MBGL</string> + <key>CFBundleVersion</key> + <string>7877</string> + <key>CSResourcesFileMapped</key> + <true/> + <key>NSHumanReadableCopyright</key> + <string>© 2014–2020 Mapbox</string> + <key>LSMinimumSystemVersion</key> + <string>${MACOSX_DEPLOYMENT_TARGET}</string> + <key>LSRequiresIPhoneOS</key> + <true/> + <key>UILaunchStoryboardName</key> + <string>LaunchScreen</string> + <key>UIMainStoryboardFile</key> + <string>Main</string> + <key>UIBackgroundModes</key> + <array> + <string>fetch</string> + <string>remote-notification</string> + </array> + <key>UIRequiredDeviceCapabilities</key> + <array> + <string>armv7</string> + </array> + <key>UISupportedInterfaceOrientations</key> + <array> + <string>UIInterfaceOrientationPortrait</string> + <string>UIInterfaceOrientationLandscapeLeft</string> + <string>UIInterfaceOrientationLandscapeRight</string> + </array> + <key>NSAppTransportSecurity</key> + <dict> + <key>NSAllowsArbitraryLoads</key> + <true/> + </dict> +</dict> +</plist>
\ No newline at end of file diff --git a/test/ios/README.md b/test/ios/README.md new file mode 100644 index 0000000000..5b0d1f6a08 --- /dev/null +++ b/test/ios/README.md @@ -0,0 +1,7 @@ +# iOS UnitTestsRunner App + +This is a blank single-view-controller iOS app, linked against to a C++ static libraries, plus a a simple unit xctest. We use CMake to create an Xcode-friendly out-of-source build system. In another word, the build system is maintained by `CMakeLists` file,instead of a configured `.xcodeproj` file. + +This CMake project can build the executable UnitTestsApp which is linked to the static C++ library 'mbgl-test'. CMakeLists.txt files are the only build configuration kept in source control. This is in contrast to committing the `.xcodeproj` directory which includes the backing XML, which is nonsensically hard to edit by hand. + +The test instantiates ObjC object of class `IosTestRunner` from the app, the class will instantiates a C++ object from the linked library `mbgl-test` and calls running unit test function on it. It subsequently deletes the C++ object pointer. In the end, the test will check the existence of test report, which is an xml file that attach to xctest result. diff --git a/test/ios/UnitTestsApp_iphoneos13.2-arm64e-debug.xctestrun b/test/ios/UnitTestsApp_iphoneos13.2-arm64e-debug.xctestrun new file mode 100644 index 0000000000..b6b7a9d1b0 --- /dev/null +++ b/test/ios/UnitTestsApp_iphoneos13.2-arm64e-debug.xctestrun @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>UnitTestsAppTests</key> + <dict> + <key>BlueprintName</key> + <string>UnitTestsAppTests</string> + <key>BundleIdentifiersForCrashReportEmphasis</key> + <array> + <string>com.mapbox.UnitTestsApp</string> + <string>com.mapbox.UnitTestsAppTests</string> + </array> + <key>CommandLineArguments</key> + <array/> + <key>DependentProductPaths</key> + <array> + <string>__TESTROOT__/Debug-iphoneos/UnitTestsApp.app</string> + <string>__TESTROOT__/Debug-iphoneos/UnitTestsApp.app/PlugIns/UnitTestsAppTests.xctest</string> + </array> + <key>EnvironmentVariables</key> + <dict> + <key>OS_ACTIVITY_DT_MODE</key> + <string>YES</string> + <key>SQLITE_ENABLE_THREAD_ASSERTIONS</key> + <string>1</string> + </dict> + <key>IsAppHostedTestBundle</key> + <true/> + <key>ProductModuleName</key> + <string>UnitTestsAppTests</string> + <key>RunOrder</key> + <integer>0</integer> + <key>SystemAttachmentLifetime</key> + <string>deleteOnSuccess</string> + <key>TestBundlePath</key> + <string>__TESTHOST__/PlugIns/UnitTestsAppTests.xctest</string> + <key>TestHostBundleIdentifier</key> + <string>com.mapbox.UnitTestsApp</string> + <key>TestHostPath</key> + <string>__TESTROOT__/Debug-iphoneos/UnitTestsApp.app</string> + <key>TestLanguage</key> + <string></string> + <key>TestRegion</key> + <string></string> + <key>TestingEnvironmentVariables</key> + <dict> + <key>DYLD_FALLBACK_FRAMEWORK_PATH</key> + <string></string> + <key>DYLD_INSERT_LIBRARIES</key> + <string>__PLATFORMS__/iPhoneOS.platform/Developer/usr/lib/libXCTestBundleInject.dylib</string> + <key>XCInjectBundleInto</key> + <string>unused</string> + </dict> + <key>ToolchainsSettingValue</key> + <array/> + <key>UITargetAppCommandLineArguments</key> + <array/> + <key>UserAttachmentLifetime</key> + <string>deleteOnSuccess</string> + </dict> + <key>__xctestrun_metadata__</key> + <dict> + <key>FormatVersion</key> + <integer>1</integer> + </dict> +</dict> +</plist> diff --git a/test/ios/UnitTestsApp_iphoneos13.2-arm64e-release.xctestrun b/test/ios/UnitTestsApp_iphoneos13.2-arm64e-release.xctestrun new file mode 100644 index 0000000000..02038a4417 --- /dev/null +++ b/test/ios/UnitTestsApp_iphoneos13.2-arm64e-release.xctestrun @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>UnitTestsAppTests</key> + <dict> + <key>BlueprintName</key> + <string>UnitTestsAppTests</string> + <key>BundleIdentifiersForCrashReportEmphasis</key> + <array> + <string>com.mapbox.UnitTestsApp</string> + <string>com.mapbox.UnitTestsAppTests</string> + </array> + <key>CommandLineArguments</key> + <array/> + <key>DependentProductPaths</key> + <array> + <string>__TESTROOT__/Release-iphoneos/UnitTestsApp.app</string> + <string>__TESTROOT__/Release-iphoneos/UnitTestsApp.app/PlugIns/UnitTestsAppTests.xctest</string> + </array> + <key>EnvironmentVariables</key> + <dict> + <key>OS_ACTIVITY_DT_MODE</key> + <string>YES</string> + <key>SQLITE_ENABLE_THREAD_ASSERTIONS</key> + <string>1</string> + </dict> + <key>IsAppHostedTestBundle</key> + <true/> + <key>ProductModuleName</key> + <string>UnitTestsAppTests</string> + <key>RunOrder</key> + <integer>0</integer> + <key>SystemAttachmentLifetime</key> + <string>deleteOnSuccess</string> + <key>TestBundlePath</key> + <string>__TESTHOST__/PlugIns/UnitTestsAppTests.xctest</string> + <key>TestHostBundleIdentifier</key> + <string>com.mapbox.UnitTestsApp</string> + <key>TestHostPath</key> + <string>__TESTROOT__/Release-iphoneos/UnitTestsApp.app</string> + <key>TestLanguage</key> + <string></string> + <key>TestRegion</key> + <string></string> + <key>TestingEnvironmentVariables</key> + <dict> + <key>DYLD_FALLBACK_FRAMEWORK_PATH</key> + <string></string> + <key>DYLD_INSERT_LIBRARIES</key> + <string>__PLATFORMS__/iPhoneOS.platform/Developer/usr/lib/libXCTestBundleInject.dylib</string> + <key>XCInjectBundleInto</key> + <string>unused</string> + </dict> + <key>ToolchainsSettingValue</key> + <array/> + <key>UITargetAppCommandLineArguments</key> + <array/> + <key>UserAttachmentLifetime</key> + <string>deleteOnSuccess</string> + </dict> + <key>__xctestrun_metadata__</key> + <dict> + <key>FormatVersion</key> + <integer>1</integer> + </dict> +</dict> +</plist> diff --git a/test/ios/codesigning/UnitTestsApp.app.xcent.template b/test/ios/codesigning/UnitTestsApp.app.xcent.template new file mode 100644 index 0000000000..a851541766 --- /dev/null +++ b/test/ios/codesigning/UnitTestsApp.app.xcent.template @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>application-identifier</key> + <string>$TEAM_ID.com.mapbox.UnitTestsApp</string> + <key>com.apple.developer.team-identifier</key> + <string>$TEAM_ID</string> + <key>get-task-allow</key> + <true/> + <key>keychain-access-groups</key> + <array> + <string>$TEAM_ID.com.mapbox.UnitTestsApp</string> + </array> +</dict> +</plist>
\ No newline at end of file diff --git a/test/ios/codesigning/UnitTestsAppTests.xctest.xcent.template b/test/ios/codesigning/UnitTestsAppTests.xctest.xcent.template new file mode 100644 index 0000000000..72b2dbbb9d --- /dev/null +++ b/test/ios/codesigning/UnitTestsAppTests.xctest.xcent.template @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>application-identifier</key> + <string>$TEAM_ID.com.mapbox.UnitTestsAppTests</string> + <key>com.apple.developer.team-identifier</key> + <string>$TEAM_ID</string> + <key>get-task-allow</key> + <true/> + <key>keychain-access-groups</key> + <array> + <string>$TEAM_ID.com.mapbox.UnitTestsAppTests</string> + </array> +</dict> +</plist>
\ No newline at end of file diff --git a/test/ios/codesigning/XCTAutomationSupport.framework.xcent.template b/test/ios/codesigning/XCTAutomationSupport.framework.xcent.template new file mode 100644 index 0000000000..72b2dbbb9d --- /dev/null +++ b/test/ios/codesigning/XCTAutomationSupport.framework.xcent.template @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>application-identifier</key> + <string>$TEAM_ID.com.mapbox.UnitTestsAppTests</string> + <key>com.apple.developer.team-identifier</key> + <string>$TEAM_ID</string> + <key>get-task-allow</key> + <true/> + <key>keychain-access-groups</key> + <array> + <string>$TEAM_ID.com.mapbox.UnitTestsAppTests</string> + </array> +</dict> +</plist>
\ No newline at end of file diff --git a/test/ios/codesigning/XCTest.framework.xcent.template b/test/ios/codesigning/XCTest.framework.xcent.template new file mode 100644 index 0000000000..72b2dbbb9d --- /dev/null +++ b/test/ios/codesigning/XCTest.framework.xcent.template @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>application-identifier</key> + <string>$TEAM_ID.com.mapbox.UnitTestsAppTests</string> + <key>com.apple.developer.team-identifier</key> + <string>$TEAM_ID</string> + <key>get-task-allow</key> + <true/> + <key>keychain-access-groups</key> + <array> + <string>$TEAM_ID.com.mapbox.UnitTestsAppTests</string> + </array> +</dict> +</plist>
\ No newline at end of file diff --git a/test/ios/codesigning/codesign_all.sh b/test/ios/codesigning/codesign_all.sh new file mode 100755 index 0000000000..1a6007ea94 --- /dev/null +++ b/test/ios/codesigning/codesign_all.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +codesign --force --sign $CODESIGNIDENTITY --entitlements ../codesigning/UnitTestsApp.app.xcent --timestamp=none ./Release-iphoneos/UnitTestsApp.app +codesign --force --sign $CODESIGNIDENTITY --deep --preserve-metadata=identifier,entitlements,flags --timestamp=none ./Release-iphoneos/UnitTestsApp.app/Frameworks/libXCTestSwiftSupport.dylib +codesign --force --sign $CODESIGNIDENTITY --deep --preserve-metadata=identifier,entitlements,flags --timestamp=none ./Release-iphoneos/UnitTestsApp.app/Frameworks/libXCTestBundleInject.dylib +codesign --force --sign $CODESIGNIDENTITY --deep --preserve-metadata=identifier,entitlements,flags --timestamp=none ./Release-iphoneos/UnitTestsApp.app/Frameworks/XCTAutomationSupport.framework +codesign --force --sign $CODESIGNIDENTITY --deep --preserve-metadata=identifier,entitlements,flags --timestamp=none ./Release-iphoneos/UnitTestsApp.app/Frameworks/XCTest.framework +codesign --force --sign $CODESIGNIDENTITY --deep --entitlements ../codesigning/UnitTestsAppTests.xctest.xcent --timestamp=none ./Release-iphoneos/UnitTestsApp.app/PlugIns/UnitTestsAppTests.xctest diff --git a/test/ios/codesigning/generate-entitlements.swift b/test/ios/codesigning/generate-entitlements.swift new file mode 100755 index 0000000000..83834483bf --- /dev/null +++ b/test/ios/codesigning/generate-entitlements.swift @@ -0,0 +1,40 @@ +#!/usr/bin/swift + +/// Generates Entitlement files .xcent for codesigning, containing the correct team id +import Swift +import Foundation + +let fileManager = FileManager.default + +let contentsOfCurrentWorkingDirectory = try FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: "./codesigning/"), includingPropertiesForKeys: nil, options: []) + +guard let rawTeamIdEnv = getenv("IOS_DEVELOPMENT_TEAM") else { + print("Please add a IOS_DEVELOPMENT_TEAM environment variable.") + exit(1) +} + +let teamId2 = String(utf8String: rawTeamIdEnv) + +for file in contentsOfCurrentWorkingDirectory { + if (file.pathExtension == "template") { + var content = "" + do { + content = try String(contentsOf: file, encoding: .utf8) + } + catch { + print("Error reading xcent file: \(error).") + } + + content = content.replacingOccurrences(of: "$TEAM_ID", with: teamId2!) + + var targetFile = file + targetFile.deletePathExtension() + do { + try content.write(to: targetFile, atomically: false, encoding: .utf8) + print("Entitlement " + targetFile.absoluteString + " generated.") + } + catch { + print("Error writing xcent file: \(error).") + } + } +}
\ No newline at end of file diff --git a/test/ios/codesigning/libXCTestSwiftSupport.dylib.xcent.template b/test/ios/codesigning/libXCTestSwiftSupport.dylib.xcent.template new file mode 100644 index 0000000000..72b2dbbb9d --- /dev/null +++ b/test/ios/codesigning/libXCTestSwiftSupport.dylib.xcent.template @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>application-identifier</key> + <string>$TEAM_ID.com.mapbox.UnitTestsAppTests</string> + <key>com.apple.developer.team-identifier</key> + <string>$TEAM_ID</string> + <key>get-task-allow</key> + <true/> + <key>keychain-access-groups</key> + <array> + <string>$TEAM_ID.com.mapbox.UnitTestsAppTests</string> + </array> +</dict> +</plist>
\ No newline at end of file diff --git a/test/ios/fastlane/Appfile b/test/ios/fastlane/Appfile new file mode 100644 index 0000000000..f9e7e1e7c1 --- /dev/null +++ b/test/ios/fastlane/Appfile @@ -0,0 +1,3 @@ +app_identifier("com.mapbox.UnitTestsApp") # The bundle identifier of your app +apple_id ENV['MAPBOX_APPLE_ID'] +team_id ENV['MAPBOX_APPLE_TEAM_ID'] # Developer Portal Team ID
\ No newline at end of file diff --git a/test/ios/fastlane/Matchfile b/test/ios/fastlane/Matchfile new file mode 100644 index 0000000000..2a815bfc8e --- /dev/null +++ b/test/ios/fastlane/Matchfile @@ -0,0 +1,5 @@ +git_url("git@github.com:mapbox/apple-certificates.git") +type("development") # The default type, can be: appstore, adhoc, enterprise or development +app_identifier(["com.mapbox.UnitTestsApp", "com.mapbox.UnitTestsAppTests"]) +username ENV['MAPBOX_APPLE_ID'] +keychain_name("fastlane_keychain")
\ No newline at end of file diff --git a/test/ios/iosTestRunner.h b/test/ios/iosTestRunner.h new file mode 100644 index 0000000000..dcbb77e9d4 --- /dev/null +++ b/test/ios/iosTestRunner.h @@ -0,0 +1,9 @@ +#import <Foundation/Foundation.h> + +__attribute__((visibility ("default"))) +@interface IosTestRunner : NSObject + +- (NSString*) getResultPath; +- (BOOL) getTestStatus; + +@end diff --git a/test/ios/iosTestRunner.mm b/test/ios/iosTestRunner.mm new file mode 100644 index 0000000000..d3f6113a05 --- /dev/null +++ b/test/ios/iosTestRunner.mm @@ -0,0 +1,82 @@ +#import "iosTestRunner.h" + +#include <ios_test_runner.hpp> + +#include <string> + +@interface IosTestRunner () + +@property (nullable) TestRunner* runner; + +@property (copy, nullable) NSString *resultPath; + +@property BOOL testStatus; + +@end + +@implementation IosTestRunner + +-(instancetype)init +{ + self = [super init]; + if (self) { + self.testStatus = NO; + self.runner = new TestRunner(); + NSError *error; + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSString *bundleRoot = [[NSBundle mainBundle] bundlePath]; + NSArray *bundleContents = [fileManager contentsOfDirectoryAtPath: bundleRoot error: &error]; + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDir = [paths objectAtIndex: 0]; + + for (uint32_t i = 0; i < bundleContents.count; i++) { + NSString *dirName = [bundleContents objectAtIndex: i]; + if ([dirName isEqualToString:@"test-data"]) { + NSString *destinationPath = [documentsDir stringByAppendingPathComponent: dirName]; + BOOL success = [fileManager fileExistsAtPath: destinationPath]; + if (success) { + [fileManager removeItemAtPath:destinationPath error:NULL]; + } + + success = [fileManager fileExistsAtPath: destinationPath]; + if (!success) { + NSString *copyDirPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent: dirName]; + success = [fileManager copyItemAtPath: copyDirPath toPath: destinationPath error: &error]; + + if (!success) { + NSLog(@"Failed to copy file '%@'", dirName); + NSAssert1(0, @"Failed to copy file, error '%@'", [error localizedDescription]); + } else { + NSLog(@"File '%@' copied OK", dirName); + } + } else { + NSLog(@"Failed to remove file '%@'", dirName); + NSAssert1(0, @"Failed to remove file, error '%@'", [error localizedDescription]); + } + break; + } + } + std::string basePath = std::string([documentsDir UTF8String]) + std::string("/test-data"); + self.testStatus = self.runner->startTest(basePath) ? YES : NO; + self.resultPath = [documentsDir stringByAppendingPathComponent:@"/test-data/test/results.xml"]; + + BOOL fileFound = [fileManager fileExistsAtPath: self.resultPath]; + if (fileFound == NO) { + NSLog(@"Test result file '%@' does not exist", self.resultPath); + self.testStatus = NO; + } + + delete self.runner; + self.runner = nullptr; + } + return self; +} + +- (NSString*) getResultPath { + return self.resultPath; +} + +- (BOOL) getTestStatus { + return self.testStatus; +} +@end diff --git a/test/ios/ios_test_runner.cpp b/test/ios/ios_test_runner.cpp new file mode 100644 index 0000000000..c99d8c3f30 --- /dev/null +++ b/test/ios/ios_test_runner.cpp @@ -0,0 +1,31 @@ +#include <ios_test_runner.hpp> + +#include <mbgl/test.hpp> + +#include <mbgl/util/logging.hpp> + +#include <unistd.h> +#include <vector> + +#define EXPORT __attribute__((visibility("default"))) + +EXPORT +bool TestRunner::startTest(const std::string& basePath) { + std::vector<std::string> arguments = {"mbgl-test-runner", "--gtest_output=xml:" + basePath + "/test/results.xml"}; + std::vector<char*> argv; + for (const auto& arg : arguments) { + argv.push_back(const_cast<char*>(arg.data())); + } + argv.push_back(nullptr); + + if (chdir(basePath.c_str())) { + mbgl::Log::Error(mbgl::Event::General, "Failed to change the directory to " + basePath); + return false; + } + + mbgl::Log::Info(mbgl::Event::General, "Start TestRunner"); + int status = mbgl::runTests(static_cast<uint32_t>(argv.size()), argv.data()); + mbgl::Log::Info(mbgl::Event::General, "TestRunner finished with status: '%d'", status); + + return status == 0; +} diff --git a/test/ios/tests/Info.plist b/test/ios/tests/Info.plist new file mode 100644 index 0000000000..ba6b34e5b6 --- /dev/null +++ b/test/ios/tests/Info.plist @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>en</string> + <key>CFBundleExecutable</key> + <string>UnitTestsAppTests</string> + <key>CFBundleIdentifier</key> + <string>com.mapbox.UnitTestsAppTests</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>1.0</string> + <key>CFBundleName</key> + <string>UnitTestsAppTests</string> + <key>CFBundlePackageType</key> + <string>BNDL</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleVersion</key> + <string>1</string> +</dict> +</plist> diff --git a/test/map/transform.test.cpp b/test/map/transform.test.cpp index 95fb744206..02ecbfbee4 100644 --- a/test/map/transform.test.cpp +++ b/test/map/transform.test.cpp @@ -621,7 +621,8 @@ TEST(Transform, LatLngBounds) { } transform.jumpTo(CameraOptions().withCenter(sanFrancisco)); - ASSERT_EQ(transform.getLatLng(), sanFrancisco); + ASSERT_NEAR(transform.getLatLng().latitude(), sanFrancisco.latitude(), 1e-8); + ASSERT_NEAR(transform.getLatLng().longitude(), sanFrancisco.longitude(), 1e-8); // Single location. transform.setLatLngBounds(LatLngBounds::singleton(sanFrancisco)); @@ -655,7 +656,7 @@ TEST(Transform, LatLngBounds) { // └───┴───┸───┴───┸───┴───┘ transform.setLatLngBounds(LatLngBounds::hull({ -90.0, 0.0 }, { 90.0, 180.0 })); transform.jumpTo(CameraOptions().withCenter(sanFrancisco)); - ASSERT_EQ(transform.getLatLng().latitude(), sanFrancisco.latitude()); + ASSERT_NEAR(transform.getLatLng().latitude(), sanFrancisco.latitude(), 1e-8); ASSERT_EQ(transform.getLatLng().longitude(), 0.0); // -1 | 0 | +1 diff --git a/test/storage/main_resource_loader.test.cpp b/test/storage/main_resource_loader.test.cpp index ee9211b064..b5245dbad8 100644 --- a/test/storage/main_resource_loader.test.cpp +++ b/test/storage/main_resource_loader.test.cpp @@ -8,6 +8,7 @@ #include <mbgl/storage/resource_transform.hpp> #include <mbgl/test/util.hpp> #include <mbgl/util/run_loop.hpp> +#include <mbgl/util/timer.hpp> using namespace mbgl; @@ -749,3 +750,38 @@ TEST(MainResourceLoader, TEST_REQUIRES_SERVER(CachedResourceLowPriority)) { loop.run(); } + +TEST(MainResourceLoader, TEST_REQUIRES_SERVER(NoDoubleDispatch)) { + util::RunLoop loop; + MainResourceLoader fs(ResourceOptions{}); + + const Resource resource{Resource::Unknown, "http://127.0.0.1:3000/revalidate-same"}; + Response response; + response.data = std::make_shared<std::string>("data"); + response.etag.emplace("snowfall"); + + std::unique_ptr<AsyncRequest> req; + unsigned responseCount = 0u; + auto dbfs = FileSourceManager::get()->getFileSource(FileSourceType::Database, ResourceOptions{}); + dbfs->forward(resource, response, [&] { + req = fs.request(resource, [&](Response res) { + EXPECT_EQ(nullptr, res.error); + EXPECT_FALSE(bool(res.modified)); + EXPECT_TRUE(bool(res.etag)); + EXPECT_EQ("snowfall", *res.etag); + if (!res.notModified) { + ASSERT_TRUE(res.data.get()); + EXPECT_EQ("data", *res.data); + ++responseCount; + } + }); + }); + + util::Timer timer; + timer.start(Milliseconds(100), Duration::zero(), [&loop, &responseCount] { + EXPECT_EQ(1u, responseCount); + loop.stop(); + }); + + loop.run(); +} diff --git a/test/storage/offline_database.test.cpp b/test/storage/offline_database.test.cpp index f988457dac..f344151297 100644 --- a/test/storage/offline_database.test.cpp +++ b/test/storage/offline_database.test.cpp @@ -779,7 +779,7 @@ TEST(OfflineDatabase, MapboxTileLimitExceeded) { db.put(ambientTile, response); }; - auto insertRegionTile = [&](int64_t regionID, unsigned i) { + auto insertRegionTile = [&](int64_t regionID, uint64_t i) { const Resource tile = Resource::tile("mapbox://region_tile_" + std::to_string(i), 1, 0, 0, 0, Tileset::Scheme::XYZ); db.putRegionResource(regionID, tile, response); }; @@ -801,14 +801,14 @@ TEST(OfflineDatabase, MapboxTileLimitExceeded) { ASSERT_EQ(db.getOfflineMapboxTileCount(), 0); // Fine because this region is under the tile limit. - for (unsigned i = 0; i < limit - 10; ++i) { + for (uint64_t i = 0; i < limit - 10; ++i) { insertRegionTile(region1->getID(), i); } ASSERT_EQ(db.getOfflineMapboxTileCount(), limit - 10); // Fine because this region + the previous is at the limit. - for (unsigned i = limit; i < limit + 10; ++i) { + for (uint64_t i = limit; i < limit + 10; ++i) { insertRegionTile(region2->getID(), i); } @@ -848,7 +848,7 @@ TEST(OfflineDatabase, MapboxTileLimitExceeded) { // 10, which would blow up the limit if it wasn't // for the fact that tile 60 is already on the // database and will not count. - for (unsigned i = limit; i < limit + 10; ++i) { + for (uint64_t i = limit; i < limit + 10; ++i) { insertRegionTile(region1->getID(), i); } diff --git a/test/tile/vector_tile.test.cpp b/test/tile/vector_tile.test.cpp index a31915498a..7bf5dae267 100644 --- a/test/tile/vector_tile.test.cpp +++ b/test/tile/vector_tile.test.cpp @@ -91,6 +91,8 @@ TEST(VectorTileData, ParseResults) { ASSERT_TRUE(false) << "should throw: feature index is out of range."; } catch (const std::out_of_range&) { ASSERT_TRUE(true); + } catch (...) { // needed for iOS when MBGL_WITH_RTTI=OFF + ASSERT_TRUE(true); } std::unique_ptr<GeometryTileFeature> feature = layer->getFeature(0u); diff --git a/test/util/tile_cover.test.cpp b/test/util/tile_cover.test.cpp index af9f0c4884..ba39bfa61b 100644 --- a/test/util/tile_cover.test.cpp +++ b/test/util/tile_cover.test.cpp @@ -365,7 +365,7 @@ TEST(TileCount, BoundsCrossingAntimeridian) { TEST(TileCover, DISABLED_FuzzPoly) { while(true) { - std::srand (time(nullptr)); + std::srand(static_cast<uint32_t>(time(nullptr))); std::size_t len = std::rand() % 10000 + 3; Polygon<double> polygon; @@ -393,7 +393,7 @@ TEST(TileCover, DISABLED_FuzzPoly) { TEST(TileCover, DISABLED_FuzzLine) { while(true) { - std::srand (time(nullptr)); + std::srand(static_cast<uint32_t>(time(nullptr))); std::size_t len = std::rand() % 10000 + 3; MultiLineString<double> mls; |