From 07600f2a81b98c8c3317fa53b02dfb7acd731529 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 3 May 2018 20:21:05 -0400 Subject: [PATCH 1/5] add etc2comp dependency on desktop and android --- android/build.gradle | 45 ++++++++++++++----------- cmake/externals/etc2comp/CMakeLists.txt | 44 ++++++++++++++++++++++++ cmake/macros/TargetEtc2Comp.cmake | 22 ++++++++++++ cmake/modules/FindEtc2Comp.cmake | 37 ++++++++++++++++++++ libraries/image/CMakeLists.txt | 1 + libraries/image/src/image/Image.cpp | 6 ++++ 6 files changed, 136 insertions(+), 19 deletions(-) create mode 100644 cmake/externals/etc2comp/CMakeLists.txt create mode 100644 cmake/macros/TargetEtc2Comp.cmake create mode 100644 cmake/modules/FindEtc2Comp.cmake diff --git a/android/build.gradle b/android/build.gradle index 1dfef97f91..e041142282 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -14,7 +14,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.0.1' + classpath 'com.android.tools.build:gradle:3.1.0' } } @@ -66,19 +66,19 @@ ext { def baseFolder = new File(HIFI_ANDROID_PRECOMPILED) def appDir = new File(projectDir, 'app') def jniFolder = new File(appDir, 'src/main/jniLibs/arm64-v8a') -def baseUrl = 'https://hifi-public.s3.amazonaws.com/austin/android/' +def baseUrl = 'https://hifi-public.s3.amazonaws.com/dependencies/android/' def qtFile='qt-5.9.3_linux_armv8-libcpp_openssl.tgz' def qtChecksum='04599670ccca84bd2b15f6915568eb2d' -def qtVersionId='PeoqzN31n.YvLfs9JE2SgHgZ4.IaKAlt' +def qtVersionId='8QbCma4ryEPgBYn_8kgYgB10IvNx9I1W' if (Os.isFamily(Os.FAMILY_MAC)) { qtFile = 'qt-5.9.3_osx_armv8-libcpp_openssl.tgz' qtChecksum='4b02de9d67d6bfb202355a808d2d9c59' - qtVersionId='HygCmtMLPYioyil0DfXckGVzhw2SXZA9' + qtVersionId='2gfgoYCggJGyXxKiazaPGsMs1Gn9j4og' } else if (Os.isFamily(Os.FAMILY_WINDOWS)) { qtFile = 'qt-5.9.3_win_armv8-libcpp_openssl.tgz' qtChecksum='c3e25db64002d0f43cf565e0ef708911' - qtVersionId='HeVObSVLCBoc7yY7He1oBMvPIH0VkClT' + qtVersionId='xKIteC6HO0xrmcWeMmhQcmKyPEsnUrcZ' } def packages = [ @@ -89,61 +89,66 @@ def packages = [ ], bullet: [ file: 'bullet-2.83_armv8-libcpp.tgz', - versionId: 'ljb7v.1IjVRqyopUKVDbVnLA4z88J8Eo', + versionId: 'L6MqTwt24yZAx0cHgLyN.GPky1kVGsq3', checksum: '2c558d604fce337f5eba3eb7ec1252fd', ], draco: [ file: 'draco_armv8-libcpp.tgz', - versionId: 'cA3tVJSmkvb1naA3l6D_Jv2Noh.4yc4m', + versionId: '3.B.uBj31kWlgND3_R2xwQzT_TP6Dz_8', checksum: '617a80d213a5ec69fbfa21a1f2f738cd', ], glad: [ file: 'glad_armv8-libcpp.zip', - versionId: 'Q9szthzeye8fFyAA.cY26Lgn2B8kezEE', + versionId: 'r5Zran.JSCtvrrB6Q4KaqfIoALPw3lYY', checksum: 'a8ee8584cf1ccd34766c7ddd9d5e5449', ], glm: [ file: 'glm-0.9.8.tgz', - versionId: 'BlkJNwaYV2Gfy5XwMeU7K0uzPDRKFMt2', + versionId: 'CHPAk.Un_8MC4v8cIqkEJ468Y4_RQDmd', checksum: 'd2b42cee31d2bc17bab6ce69e6b3f30a', ], gvr: [ file: 'gvrsdk_v1.101.0.tgz', - versionId: 'UTberAIFraEfF9IVjoV66u1DTPTopgeY', + versionId: 'nqBV_j81Uc31rC7bKIrlya_Hah4v3y5r', checksum: '57fd02baa069176ba18597a29b6b4fc7', ], nvtt: [ file: 'nvtt_armv8-libcpp.zip', - versionId: 'vLqrqThvpq4gp75BHMAqO6HhfTXaa0An', + versionId: 'lmkBVR5t4UF1UUwMwEirnk9H_8Nt90IO', checksum: 'eb46d0b683e66987190ed124aabf8910', sharedLibFolder: 'lib', includeLibs: ['libnvtt.so', 'libnvmath.so', 'libnvimage.so', 'libnvcore.so'], ], openssl: [ file: 'openssl-1.1.0g_armv8.tgz', - versionId: 'DmahmSGFS4ltpHyTdyQvv35WOeUOiib9', + versionId: 'AiiPjmgUZTgNj7YV1EEx2lL47aDvvvAW', checksum: 'cabb681fbccd79594f65fcc266e02f32', ], polyvox: [ file: 'polyvox_armv8-libcpp.tgz', - versionId: 'LDJtzMTvdm4SAc2KYg8Cg6uwWk4Vq3e3', - checksum: '349ad5b72aaf2749ca95d847e60c5314', + versionId: 'UmHp.EOFiepdXnv2YxwNXNO3J6nVsBkE', + checksum: '5c918288741ee754c16aeb12bb46b9e1', sharedLibFolder: 'lib', includeLibs: ['Release/libPolyVoxCore.so', 'libPolyVoxUtil.so'], ], tbb: [ file: 'tbb-2018_U1_armv8_libcpp.tgz', - versionId: 'YZliDD8.Menh1IVXKEuLPeO3xAjJ1UdF', + versionId: 'mrRbWnv4O4evcM1quRH43RJqimlRtaKB', checksum: '20768f298f53b195e71b414b0ae240c4', sharedLibFolder: 'lib/release', includeLibs: ['libtbb.so', 'libtbbmalloc.so'], ], hifiAC: [ file: 'libplugins_libhifiCodec.zip', - versionId: 'mzKhsRCgVmloqq5bvE.0IwYK1NjGQc_G', + versionId: 'i31pW.qNbvFOXRxbyiJUxg3sphaFNmZU', checksum: '9412a8e12c88a4096c1fc843bb9fe52d', sharedLibFolder: '', includeLibs: ['libplugins_libhifiCodec.so'] + ], + etc2comp: [ + file: 'etc2comp-armv8-libcpp.tgz', + versionId: '1WfqJYWLOP0g22eikYjBzn62gza7MKE6', + checksum: '0b4c2e6de728546845f0e471dfdeb604' ] ] @@ -152,15 +157,15 @@ def scribeLocalFile='scribe' + EXEC_SUFFIX def scribeFile='scribe_linux_x86_64' def scribeChecksum='ca4b904f52f4f993c29175ba96798fa6' -def scribeVersion='wgpf4dB2Ltzg4Lb2jJ4nPFsHoDkmK_OO' +def scribeVersion='u_iTrJDaE95i2abTPXOpPZckGBIim53G' if (Os.isFamily(Os.FAMILY_MAC)) { scribeFile = 'scribe_osx_x86_64' scribeChecksum='72db9d32d4e1e50add755570ac5eb749' - scribeVersion='o_NbPrktzEYtBkQf3Tn7zc1nZWzM52w6' + scribeVersion='DAW0DmnjCRib4MD8x93bgc2Z2MpPojZC' } else if (Os.isFamily(Os.FAMILY_WINDOWS)) { scribeFile = 'scribe_win32_x86_64.exe' scribeChecksum='678e43d290c90fda670c6fefe038a06d' - scribeVersion='GCCJxlmd2irvNOFWfZR0U1UCLHndHQrC' + scribeVersion='PuullrA_bPlO9kXZRt8rLe536X1UI.m7' } def options = [ @@ -361,6 +366,7 @@ task verifyOpenSSL(type: Verify) { def p = packages['openssl']; src new File(bas task verifyPolyvox(type: Verify) { def p = packages['polyvox']; src new File(baseFolder, p['file']); checksum p['checksum'] } task verifyTBB(type: Verify) { def p = packages['tbb']; src new File(baseFolder, p['file']); checksum p['checksum'] } task verifyHifiAC(type: Verify) { def p = packages['hifiAC']; src new File(baseFolder, p['file']); checksum p['checksum'] } +task verifyEtc2Comp(type: Verify) { def p = packages['etc2comp']; src new File(baseFolder, p['file']); checksum p['checksum'] } task verifyDependencyDownloads(dependsOn: downloadDependencies) { } verifyDependencyDownloads.dependsOn verifyQt @@ -371,6 +377,7 @@ verifyDependencyDownloads.dependsOn verifyOpenSSL verifyDependencyDownloads.dependsOn verifyPolyvox verifyDependencyDownloads.dependsOn verifyTBB verifyDependencyDownloads.dependsOn verifyHifiAC +verifyDependencyDownloads.dependsOn verifyEtc2Comp task extractDependencies(dependsOn: verifyDependencyDownloads) { doLast { diff --git a/cmake/externals/etc2comp/CMakeLists.txt b/cmake/externals/etc2comp/CMakeLists.txt new file mode 100644 index 0000000000..9cee0652bc --- /dev/null +++ b/cmake/externals/etc2comp/CMakeLists.txt @@ -0,0 +1,44 @@ +set(EXTERNAL_NAME etc2comp) + +if (ANDROID) + set(ANDROID_CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" "-DANDROID_NATIVE_API_LEVEL=19") +endif () + +include(ExternalProject) +ExternalProject_Add( + ${EXTERNAL_NAME} + URL https://hifi-public.s3.amazonaws.com/dependencies/etc2comp-master.zip + URL_MD5 d0969e14af6b10b3306f880c8e2b1184 + CMAKE_ARGS ${ANDROID_CMAKE_ARGS} + BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build + INSTALL_COMMAND "" + LOG_DOWNLOAD 1 + LOG_CONFIGURE 1 + LOG_BUILD 1 +) + +# Hide this external target (for ide users) +set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") + +ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) +ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) + +string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) + +if (WIN32) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/build/EtcLib/Debug/EtcLib.lib CACHE FILEPATH "Path to Etc2Comp debug library") + + # use generator expression to ensure the correct library is found when building different configurations in VS + set(_LIB_FOLDER "$<$:build/EtcLib/RelWithDebInfo>") + set(_LIB_FOLDER "${_LIB_FOLDER}$<$:build/EtcLib/MinSizeRel>") + set(_LIB_FOLDER "${_LIB_FOLDER}$<$,$>:build/EtcLib/Release>") + + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/${_LIB_FOLDER}/EtcLib.lib CACHE FILEPATH "Path to Etc2Comp release library") +else () + set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE FILEPATH "Path to EtcLib debug library") + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/build/EtcLib/libEtcLib.a CACHE FILEPATH "Path to EtcLib release library") +endif () + +set(ETC_INCLUDE_DIR ${SOURCE_DIR}/EtcLib/Etc CACHE FILEPATH "Path to Etc2Comp/Etc include directory") +set(ETCCODEC_INCLUDE_DIR ${SOURCE_DIR}/EtcLib/EtcCodec CACHE FILEPATH "Path to Etc2Comp/EtcCodec include directory") +# ETC2COMP_INCLUDE_DIRS will be set later by FindEtc2Comp \ No newline at end of file diff --git a/cmake/macros/TargetEtc2Comp.cmake b/cmake/macros/TargetEtc2Comp.cmake new file mode 100644 index 0000000000..8dfae175a9 --- /dev/null +++ b/cmake/macros/TargetEtc2Comp.cmake @@ -0,0 +1,22 @@ +# +# Copyright 2018 High Fidelity, Inc. +# Created by Sam Gondelman on 5/2/2018 +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# +macro(TARGET_ETC2COMP) + if (ANDROID) + set(INSTALL_DIR ${HIFI_ANDROID_PRECOMPILED}/etc2comp) + set(ETC2COMP_INCLUDE_DIRS "${INSTALL_DIR}/include/Etc" "${INSTALL_DIR}/include/EtcCodec") + set(ETC2COMP_LIBRARY_DEBUG ${INSTALL_DIR}/lib/libEtcLib.a) + set(ETC2COMP_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libEtcLib.a) + select_library_configurations(ETC2COMP) + else() + add_dependency_external_projects(etc2comp) + find_package(ETC2COMP REQUIRED) + endif() + + target_include_directories(${TARGET_NAME} PRIVATE ${ETC2COMP_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${ETC2COMP_LIBRARIES}) +endmacro() diff --git a/cmake/modules/FindEtc2Comp.cmake b/cmake/modules/FindEtc2Comp.cmake new file mode 100644 index 0000000000..1b990368fd --- /dev/null +++ b/cmake/modules/FindEtc2Comp.cmake @@ -0,0 +1,37 @@ +# +# FindEtc2Comp.cmake +# +# Try to find the Etc2Comp compression library. +# +# Once done this will define +# +# ETC2COMP_FOUND - system found Etc2Comp +# ETC2COMP_INCLUDE_DIRS - the Etc2Comp include directory +# ETC2COMP_LIBRARIES - link to this to use Etc2Comp +# +# Created on 5/2/2018 by Sam Gondelman +# Copyright 2018 High Fidelity, Inc. +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# + +include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") +hifi_library_search_hints("etc2comp") + +find_path(ETC_INCLUDE_DIR NAMES Etc.h HINTS ${ETC2COMP_SEARCH_DIRS}) +find_path(ETCCODEC_INCLUDE_DIR NAMES EtcBlock4x4.h HINTS ${ETC2COMP_SEARCH_DIRS}) +set(ETC2COMP_INCLUDE_DIRS "${ETC_INCLUDE_DIR}" "${ETCCODEC_INCLUDE_DIR}") + +find_library(ETC2COMP_LIBRARY_DEBUG NAMES ETC2COMP ETC2COMP_LIB PATH_SUFFIXES EtcLib/Debug HINTS ${ETC2COMP_SEARCH_DIRS}) +find_library(ETC2COMP_LIBRARY_RELEASE NAMES ETC2COMP ETC2COMP_LIB PATH_SUFFIXES EtcLib/Release EtcLib HINTS ${ETC2COMP_SEARCH_DIRS}) + +include(SelectLibraryConfigurations) +select_library_configurations(ETC2COMP) + +set(ETC2COMP_LIBRARIES ${ETC2COMP_LIBRARY}) + +find_package_handle_standard_args(ETC2COMP "Could NOT find ETC2COMP, try to set the path to ETC2COMP root folder in the system variable ETC2COMP_ROOT_DIR or create a directory etc2comp in HIFI_LIB_DIR and paste the necessary files there" + ETC2COMP_INCLUDE_DIRS ETC2COMP_LIBRARIES) + +mark_as_advanced(ETC2COMP_INCLUDE_DIRS ETC2COMP_LIBRARIES ETC2COMP_SEARCH_DIRS) diff --git a/libraries/image/CMakeLists.txt b/libraries/image/CMakeLists.txt index 8073cc2b5e..6bc5c762f5 100644 --- a/libraries/image/CMakeLists.txt +++ b/libraries/image/CMakeLists.txt @@ -2,3 +2,4 @@ set(TARGET_NAME image) setup_hifi_library() link_hifi_libraries(shared gpu) target_nvtt() +target_etc2comp() diff --git a/libraries/image/src/image/Image.cpp b/libraries/image/src/image/Image.cpp index c1c07838c7..1639dde246 100644 --- a/libraries/image/src/image/Image.cpp +++ b/libraries/image/src/image/Image.cpp @@ -31,8 +31,14 @@ using namespace gpu; #define CPU_MIPMAPS 1 #include +#include + static const glm::uvec2 SPARSE_PAGE_SIZE(128); +#ifdef Q_OS_ANDROID +static const glm::uvec2 MAX_TEXTURE_SIZE(1024); +#else static const glm::uvec2 MAX_TEXTURE_SIZE(4096); +#endif bool DEV_DECIMATE_TEXTURES = false; std::atomic DECIMATED_TEXTURE_COUNT{ 0 }; std::atomic RECTIFIED_TEXTURE_COUNT{ 0 }; From 7418fe782cabf2dccc3ea57ba1f79ead926021a1 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 9 May 2018 12:22:30 -0700 Subject: [PATCH 2/5] local compression on android --- libraries/image/src/image/Image.cpp | 121 +++++++++++++++++++++------- 1 file changed, 94 insertions(+), 27 deletions(-) diff --git a/libraries/image/src/image/Image.cpp b/libraries/image/src/image/Image.cpp index 1639dde246..55cafe9571 100644 --- a/libraries/image/src/image/Image.cpp +++ b/libraries/image/src/image/Image.cpp @@ -31,7 +31,10 @@ using namespace gpu; #define CPU_MIPMAPS 1 #include +#ifdef Q_OS_ANDROID #include +#include +#endif static const glm::uvec2 SPARSE_PAGE_SIZE(128); #ifdef Q_OS_ANDROID @@ -43,6 +46,7 @@ bool DEV_DECIMATE_TEXTURES = false; std::atomic DECIMATED_TEXTURE_COUNT{ 0 }; std::atomic RECTIFIED_TEXTURE_COUNT{ 0 }; +// TODO: pick compressed android hdr format static const auto HDR_FORMAT = gpu::Element::COLOR_R11G11B10; static std::atomic compressColorTextures { false }; @@ -560,7 +564,9 @@ void generateLDRMips(gpu::Texture* texture, QImage&& image, const std::atomic(localCopy.constBits()); + auto mipFormat = texture->getStoredMipFormat(); +#ifndef Q_OS_ANDROID nvtt::TextureType textureType = nvtt::TextureType_2D; nvtt::InputFormat inputFormat = nvtt::InputFormat_BGRA_8UB; nvtt::WrapMode wrapMode = nvtt::WrapMode_Mirror; @@ -590,8 +596,6 @@ void generateLDRMips(gpu::Texture* texture, QImage&& image, const std::atomicgetStoredMipFormat(); if (mipFormat == gpu::Element::COLOR_COMPRESSED_BCX_SRGB) { compressionOptions.setFormat(nvtt::Format_BC1); } else if (mipFormat == gpu::Element::COLOR_COMPRESSED_BCX_SRGBA_MASK) { @@ -675,6 +679,78 @@ void generateLDRMips(gpu::Texture* texture, QImage&& image, const std::atomic floatData; + floatData.resize(width * height); + for (int y = 0; y < height; y++) { + QRgb *line = (QRgb *) localCopy.scanLine(y); + for (int x = 0; x < width; x++) { + QRgb &pixel = line[x]; + floatData[x + y * width] = vec4(qRed(pixel), qGreen(pixel), qBlue(pixel), qAlpha(pixel)) / 255.0f; + } + } + + Etc::EncodeMipmaps( + (float *)floatData.data(), width, height, + etcFormat, errorMetric, effort, + numEncodeThreads, numEncodeThreads, + numMips, Etc::FILTER_WRAP_X | Etc::FILTER_WRAP_Y, + mipMaps, &encodingTime + ); + + // free up the memory afterward to avoid bloating the heap + data = nullptr; + localCopy = QImage(); // QImage doesn't have a clear function, so override it with an empty one. + + for (int i = 0; i < numMips; i++) { + if (face >= 0) { + texture->assignStoredMipFace(i, face, mipMaps[i].uiEncodingBitsBytes, static_cast(mipMaps[i].paucEncodingBits.get())); + } else { + texture->assignStoredMip(i, mipMaps[i].uiEncodingBitsBytes, static_cast(mipMaps[i].paucEncodingBits.get())); + } + } + + delete[] mipMaps; +#endif } #endif @@ -744,7 +820,6 @@ gpu::TexturePointer TextureUsage::process2DTextureColorFromImage(QImage&& srcIma gpu::Element formatMip; gpu::Element formatGPU; if (isColorTexturesCompressionEnabled()) { -#ifndef USE_GLES if (validAlpha) { // NOTE: This disables BC1a compression because it was producing odd artifacts on text textures // for the tutorial. Instead we use BC3 (which is larger) but doesn't produce the same artifacts). @@ -752,23 +827,15 @@ gpu::TexturePointer TextureUsage::process2DTextureColorFromImage(QImage&& srcIma } else { formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_SRGB; } -#else - if (validAlpha) { - formatGPU = gpu::Element::COLOR_COMPRESSED_ETC2_SRGBA; - } else { - formatGPU = gpu::Element::COLOR_COMPRESSED_ETC2_SRGB; - } -#endif - formatMip = formatGPU; } else { -#ifdef USE_GLES +#ifdef Q_OS_ANDROID // GLES does not support GL_BGRA - formatMip = gpu::Element::COLOR_SRGBA_32; + formatGPU = gpu::Element::COLOR_COMPRESSED_ETC2_SRGBA; #else - formatMip = gpu::Element::COLOR_SBGRA_32; + formatGPU = gpu::Element::COLOR_SBGRA_32; #endif - formatGPU = gpu::Element::COLOR_SRGBA_32; } + formatMip = formatGPU; if (isStrict) { theTexture = gpu::Texture::createStrict(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)); @@ -882,16 +949,18 @@ gpu::TexturePointer TextureUsage::process2DTextureNormalMapFromImage(QImage&& sr gpu::TexturePointer theTexture = nullptr; if ((image.width() > 0) && (image.height() > 0)) { - gpu::Element formatMip = gpu::Element::VEC2NU8_XY; - gpu::Element formatGPU = gpu::Element::VEC2NU8_XY; + gpu::Element formatMip; + gpu::Element formatGPU; if (isNormalTexturesCompressionEnabled()) { -#ifndef USE_GLES formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_XY; -#else + } else { +#ifdef Q_OS_ANDROID formatGPU = gpu::Element::COLOR_COMPRESSED_EAC_XY; +#else + formatGPU = gpu::Element::VEC2NU8_XY; #endif - formatMip = formatGPU; } + formatMip = formatGPU; theTexture = gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)); theTexture->setSource(srcImageName); @@ -923,16 +992,15 @@ gpu::TexturePointer TextureUsage::process2DTextureGrayscaleFromImage(QImage&& sr gpu::Element formatMip; gpu::Element formatGPU; if (isGrayscaleTexturesCompressionEnabled()) { -#ifndef USE_GLES formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_RED; -#else - formatGPU = gpu::Element::COLOR_COMPRESSED_EAC_RED; -#endif - formatMip = formatGPU; } else { - formatMip = gpu::Element::COLOR_R_8; +#ifdef Q_OS_ANDROID + formatGPU = gpu::Element::COLOR_COMPRESSED_EAC_RED; +#else formatGPU = gpu::Element::COLOR_R_8; +#endif } + formatMip = formatGPU; theTexture = gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)); theTexture->setSource(srcImageName); @@ -1295,7 +1363,6 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(QImage&& srcI gpu::Element formatMip; gpu::Element formatGPU; if (isCubeTexturesCompressionEnabled()) { - // TODO: gles: pick HDR ETC format formatMip = gpu::Element::COLOR_COMPRESSED_BCX_HDR_RGB; formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_HDR_RGB; } else { From 6b268191c82bcdcfa1f17b589ba8143b2cacc970 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 14 May 2018 15:29:36 -0700 Subject: [PATCH 3/5] local compression, patched etc2comp --- android/build.gradle | 6 +-- cmake/externals/etc2comp/CMakeLists.txt | 6 ++- libraries/gpu/src/gpu/Texture_ktx.cpp | 2 +- libraries/image/src/image/Image.cpp | 71 ++++++++++++------------- 4 files changed, 42 insertions(+), 43 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index e041142282..71d48e28d4 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -146,9 +146,9 @@ def packages = [ includeLibs: ['libplugins_libhifiCodec.so'] ], etc2comp: [ - file: 'etc2comp-armv8-libcpp.tgz', - versionId: '1WfqJYWLOP0g22eikYjBzn62gza7MKE6', - checksum: '0b4c2e6de728546845f0e471dfdeb604' + file: 'etc2comp-patched-armv8-libcpp.tgz', + versionId: 'bHhGECRAQR1vkpshBcK6ByNc1BQIM8gU', + checksum: '14b02795d774457a33bbc60e00a786bc' ] ] diff --git a/cmake/externals/etc2comp/CMakeLists.txt b/cmake/externals/etc2comp/CMakeLists.txt index 9cee0652bc..1de4932380 100644 --- a/cmake/externals/etc2comp/CMakeLists.txt +++ b/cmake/externals/etc2comp/CMakeLists.txt @@ -5,10 +5,12 @@ if (ANDROID) endif () include(ExternalProject) +# We use a patched version of etc2comp that properly generates all the necessary mips +# See https://github.com/google/etc2comp/pull/29 ExternalProject_Add( ${EXTERNAL_NAME} - URL https://hifi-public.s3.amazonaws.com/dependencies/etc2comp-master.zip - URL_MD5 d0969e14af6b10b3306f880c8e2b1184 + URL https://hifi-public.s3.amazonaws.com/dependencies/etc2comp-patched.zip + URL_MD5 6fe3629de8ff99bc99f8c14558d841a3 CMAKE_ARGS ${ANDROID_CMAKE_ARGS} BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build INSTALL_COMMAND "" diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index 129c125411..839cb915e2 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -352,7 +352,7 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) { if (!Texture::evalKTXFormat(mipFormat, texelFormat, header)) { return nullptr; } - + // Set Dimensions uint32_t numFaces = 1; switch (texture.getType()) { diff --git a/libraries/image/src/image/Image.cpp b/libraries/image/src/image/Image.cpp index 55cafe9571..2fc22b4eac 100644 --- a/libraries/image/src/image/Image.cpp +++ b/libraries/image/src/image/Image.cpp @@ -31,14 +31,14 @@ using namespace gpu; #define CPU_MIPMAPS 1 #include -#ifdef Q_OS_ANDROID +#ifdef USE_GLES #include #include #endif static const glm::uvec2 SPARSE_PAGE_SIZE(128); #ifdef Q_OS_ANDROID -static const glm::uvec2 MAX_TEXTURE_SIZE(1024); +static const glm::uvec2 MAX_TEXTURE_SIZE(2048); #else static const glm::uvec2 MAX_TEXTURE_SIZE(4096); #endif @@ -46,7 +46,6 @@ bool DEV_DECIMATE_TEXTURES = false; std::atomic DECIMATED_TEXTURE_COUNT{ 0 }; std::atomic RECTIFIED_TEXTURE_COUNT{ 0 }; -// TODO: pick compressed android hdr format static const auto HDR_FORMAT = gpu::Element::COLOR_R11G11B10; static std::atomic compressColorTextures { false }; @@ -563,10 +562,10 @@ void generateLDRMips(gpu::Texture* texture, QImage&& image, const std::atomic(localCopy.constBits()); auto mipFormat = texture->getStoredMipFormat(); -#ifndef Q_OS_ANDROID +#ifndef USE_GLES + const void* data = static_cast(localCopy.constBits()); nvtt::TextureType textureType = nvtt::TextureType_2D; nvtt::InputFormat inputFormat = nvtt::InputFormat_BGRA_8UB; nvtt::WrapMode wrapMode = nvtt::WrapMode_Mirror; @@ -681,43 +680,41 @@ void generateLDRMips(gpu::Texture* texture, QImage&& image, const std::atomic floatData; floatData.resize(width * height); @@ -725,27 +722,28 @@ void generateLDRMips(gpu::Texture* texture, QImage&& image, const std::atomic= 0) { - texture->assignStoredMipFace(i, face, mipMaps[i].uiEncodingBitsBytes, static_cast(mipMaps[i].paucEncodingBits.get())); - } else { - texture->assignStoredMip(i, mipMaps[i].uiEncodingBitsBytes, static_cast(mipMaps[i].paucEncodingBits.get())); + if (mipMaps[i].paucEncodingBits.get()) { + if (face >= 0) { + texture->assignStoredMipFace(i, face, mipMaps[i].uiEncodingBitsBytes, static_cast(mipMaps[i].paucEncodingBits.get())); + } else { + texture->assignStoredMip(i, mipMaps[i].uiEncodingBitsBytes, static_cast(mipMaps[i].paucEncodingBits.get())); + } } } @@ -755,8 +753,6 @@ void generateLDRMips(gpu::Texture* texture, QImage&& image, const std::atomic& abortProcessing = false, int face = -1) { #if CPU_MIPMAPS PROFILE_RANGE(resource_parse, "generateMips"); @@ -828,14 +824,15 @@ gpu::TexturePointer TextureUsage::process2DTextureColorFromImage(QImage&& srcIma formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_SRGB; } } else { -#ifdef Q_OS_ANDROID +#ifdef USE_GLES // GLES does not support GL_BGRA formatGPU = gpu::Element::COLOR_COMPRESSED_ETC2_SRGBA; + formatMip = formatGPU; #else - formatGPU = gpu::Element::COLOR_SBGRA_32; + formatGPU = gpu::Element::COLOR_SRGBA_32; + formatMip = gpu::Element::COLOR_SBGRA_32; #endif } - formatMip = formatGPU; if (isStrict) { theTexture = gpu::Texture::createStrict(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)); @@ -954,7 +951,7 @@ gpu::TexturePointer TextureUsage::process2DTextureNormalMapFromImage(QImage&& sr if (isNormalTexturesCompressionEnabled()) { formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_XY; } else { -#ifdef Q_OS_ANDROID +#ifdef USE_GLES formatGPU = gpu::Element::COLOR_COMPRESSED_EAC_XY; #else formatGPU = gpu::Element::VEC2NU8_XY; @@ -994,7 +991,7 @@ gpu::TexturePointer TextureUsage::process2DTextureGrayscaleFromImage(QImage&& sr if (isGrayscaleTexturesCompressionEnabled()) { formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_RED; } else { -#ifdef Q_OS_ANDROID +#ifdef USE_GLES formatGPU = gpu::Element::COLOR_COMPRESSED_EAC_RED; #else formatGPU = gpu::Element::COLOR_R_8; From 12b91a2ab720e8eb5c8c73822b01220003996e96 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 16 May 2018 18:06:12 -0700 Subject: [PATCH 4/5] compress skyboxes --- android/build.gradle | 6 ++--- cmake/macros/TargetEtc2Comp.cmake | 2 +- libraries/gpu/src/gpu/Texture.cpp | 14 +++++++++++- libraries/image/src/image/Image.cpp | 34 ++++++++++++++++++++++++----- 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 71d48e28d4..c771c776b5 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -14,7 +14,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.1.0' + classpath 'com.android.tools.build:gradle:3.0.1' } } @@ -126,8 +126,8 @@ def packages = [ ], polyvox: [ file: 'polyvox_armv8-libcpp.tgz', - versionId: 'UmHp.EOFiepdXnv2YxwNXNO3J6nVsBkE', - checksum: '5c918288741ee754c16aeb12bb46b9e1', + versionId: 'A2kbKiNhpIenGq23bKRRzg7IMAI5BI92', + checksum: 'dba88b3a098747af4bb169e9eb9af57e', sharedLibFolder: 'lib', includeLibs: ['Release/libPolyVoxCore.so', 'libPolyVoxUtil.so'], ], diff --git a/cmake/macros/TargetEtc2Comp.cmake b/cmake/macros/TargetEtc2Comp.cmake index 8dfae175a9..44152a58d2 100644 --- a/cmake/macros/TargetEtc2Comp.cmake +++ b/cmake/macros/TargetEtc2Comp.cmake @@ -14,7 +14,7 @@ macro(TARGET_ETC2COMP) select_library_configurations(ETC2COMP) else() add_dependency_external_projects(etc2comp) - find_package(ETC2COMP REQUIRED) + find_package(Etc2Comp REQUIRED) endif() target_include_directories(${TARGET_NAME} PRIVATE ${ETC2COMP_INCLUDE_DIRS}) diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index ed9505766b..a92243f808 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -684,9 +684,9 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector< PROFILE_RANGE(render_gpu, "sphericalHarmonicsFromTexture"); +#ifndef USE_GLES auto mipFormat = cubeTexture.getStoredMipFormat(); std::function unpackFunc; - switch (mipFormat.getSemantic()) { case gpu::R11G11B10: unpackFunc = glm::unpackF2x11_1x10; @@ -698,6 +698,7 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector< assert(false); break; } +#endif const uint sqOrder = order*order; @@ -732,7 +733,11 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector< for(int face=0; face < gpu::Texture::NUM_CUBE_FACES; face++) { PROFILE_RANGE(render_gpu, "ProcessFace"); +#ifndef USE_GLES auto data = reinterpret_cast( cubeTexture.accessStoredMipFace(0, face)->readData() ); +#else + auto data = cubeTexture.accessStoredMipFace(0, face)->readData(); +#endif if (data == nullptr) { continue; } @@ -816,8 +821,15 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector< glm::vec3 color{ 0.0f, 0.0f, 0.0f }; for (int i = 0; i < stride; ++i) { for (int j = 0; j < stride; ++j) { +#ifndef USE_GLES int k = (int)(x + i - halfStride + (y + j - halfStride) * width); color += unpackFunc(data[k]); +#else + const int NUM_COMPONENTS_PER_PIXEL = 4; + int k = NUM_COMPONENTS_PER_PIXEL * (int)(x + i - halfStride + (y + j - halfStride) * width); + // BGRA -> RGBA + color += glm::pow(glm::vec3(data[k + 2], data[k + 1], data[k]) / 255.0f, glm::vec3(2.2f)); +#endif } } diff --git a/libraries/image/src/image/Image.cpp b/libraries/image/src/image/Image.cpp index 2fc22b4eac..63a4725f64 100644 --- a/libraries/image/src/image/Image.cpp +++ b/libraries/image/src/image/Image.cpp @@ -84,7 +84,13 @@ const QStringList getSupportedFormats() { return stringFormats; } + +// On GLES, we don't use HDR skyboxes +#ifndef USE_GLES QImage::Format QIMAGE_HDR_FORMAT = QImage::Format_RGB30; +#else +QImage::Format QIMAGE_HDR_FORMAT = QImage::Format_RGB32; +#endif TextureUsage::TextureLoader TextureUsage::getTextureLoaderForType(Type type, const QVariantMap& options) { switch (type) { @@ -557,7 +563,7 @@ void generateLDRMips(gpu::Texture* texture, QImage&& image, const std::atomic #if CPU_MIPMAPS PROFILE_RANGE(resource_parse, "generateMips"); +#ifndef USE_GLES if (image.format() == QIMAGE_HDR_FORMAT) { generateHDRMips(texture, std::move(image), abortProcessing, face); } else { generateLDRMips(texture, std::move(image), abortProcessing, face); } +#else + generateLDRMips(texture, std::move(image), abortProcessing, face); +#endif #else texture->setAutoGenerateMips(true); #endif @@ -1354,18 +1364,25 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(QImage&& srcI QImage image = processSourceImage(std::move(localCopy), true); if (image.format() != QIMAGE_HDR_FORMAT) { +#ifndef USE_GLES image = convertToHDRFormat(std::move(image), HDR_FORMAT); +#else + image = image.convertToFormat(QImage::Format_RGB32); +#endif } gpu::Element formatMip; gpu::Element formatGPU; if (isCubeTexturesCompressionEnabled()) { - formatMip = gpu::Element::COLOR_COMPRESSED_BCX_HDR_RGB; formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_HDR_RGB; } else { - formatMip = HDR_FORMAT; +#ifdef USE_GLES + formatGPU = gpu::Element::COLOR_COMPRESSED_ETC2_SRGB; +#else formatGPU = HDR_FORMAT; +#endif } + formatMip = formatGPU; // Find the layout of the cubemap in the 2D image // Use the original image size since processSourceImage may have altered the size / aspect ratio @@ -1412,9 +1429,16 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(QImage&& srcI // Generate irradiance while we are at it if (generateIrradiance) { PROFILE_RANGE(resource_parse, "generateIrradiance"); - auto irradianceTexture = gpu::Texture::createCube(HDR_FORMAT, faces[0].width(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP)); + gpu::Element irradianceFormat; + // TODO: we could locally compress the irradiance texture on Android, but we don't need to +#ifndef USE_GLES + irradianceFormat = HDR_FORMAT; +#else + irradianceFormat = gpu::Element::COLOR_SRGBA_32; +#endif + auto irradianceTexture = gpu::Texture::createCube(irradianceFormat, faces[0].width(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP)); irradianceTexture->setSource(srcImageName); - irradianceTexture->setStoredMipFormat(HDR_FORMAT); + irradianceTexture->setStoredMipFormat(irradianceFormat); for (uint8 face = 0; face < faces.size(); ++face) { irradianceTexture->assignStoredMipFace(0, face, faces[face].byteCount(), faces[face].constBits()); } From 282e61c085563fd58f3430a66bc7eb634e587f69 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 21 May 2018 13:43:24 -0700 Subject: [PATCH 5/5] patch etc2comp for mac --- cmake/externals/etc2comp/CMakeLists.txt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/cmake/externals/etc2comp/CMakeLists.txt b/cmake/externals/etc2comp/CMakeLists.txt index 1de4932380..d6d21d6703 100644 --- a/cmake/externals/etc2comp/CMakeLists.txt +++ b/cmake/externals/etc2comp/CMakeLists.txt @@ -4,14 +4,20 @@ if (ANDROID) set(ANDROID_CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" "-DANDROID_NATIVE_API_LEVEL=19") endif () +if (APPLE) + set(EXTRA_CMAKE_FLAGS -DCMAKE_CXX_FLAGS=-stdlib=libc++ -DCMAKE_EXE_LINKER_FLAGS=-stdlib=libc++) +endif () + include(ExternalProject) # We use a patched version of etc2comp that properly generates all the necessary mips # See https://github.com/google/etc2comp/pull/29 +# We also use part of https://github.com/google/etc2comp/pull/1, which fixes a bug +# that would override CMAKE_CXX_FLAGS ExternalProject_Add( ${EXTERNAL_NAME} URL https://hifi-public.s3.amazonaws.com/dependencies/etc2comp-patched.zip - URL_MD5 6fe3629de8ff99bc99f8c14558d841a3 - CMAKE_ARGS ${ANDROID_CMAKE_ARGS} + URL_MD5 4c96153eb179acbe619e3d99d3330595 + CMAKE_ARGS ${ANDROID_CMAKE_ARGS} ${EXTRA_CMAKE_FLAGS} BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build INSTALL_COMMAND "" LOG_DOWNLOAD 1 @@ -36,6 +42,9 @@ if (WIN32) set(_LIB_FOLDER "${_LIB_FOLDER}$<$,$>:build/EtcLib/Release>") set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/${_LIB_FOLDER}/EtcLib.lib CACHE FILEPATH "Path to Etc2Comp release library") +elseif (APPLE) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/build/EtcLib/Debug/libEtcLib.a CACHE FILEPATH "Path to EtcLib debug library") + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/build/EtcLib/Release/libEtcLib.a CACHE FILEPATH "Path to EtcLib release library") else () set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE FILEPATH "Path to EtcLib debug library") set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/build/EtcLib/libEtcLib.a CACHE FILEPATH "Path to EtcLib release library")