From 8eb68a905e2985539cd517c4a7f7b5b5aab6f1d5 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 15 Dec 2023 13:38:03 +0100 Subject: [PATCH 1/9] Add initial ASTC pixel format support --- Source/Engine/Graphics/PixelFormat.h | 10 ++ .../Engine/Graphics/PixelFormatExtensions.cpp | 50 ++++--- .../Engine/Graphics/PixelFormatExtensions.h | 11 +- .../Vulkan/RenderToolsVulkan.cpp | 126 +++++++----------- 4 files changed, 98 insertions(+), 99 deletions(-) diff --git a/Source/Engine/Graphics/PixelFormat.h b/Source/Engine/Graphics/PixelFormat.h index 1257e42b7..f6793e543 100644 --- a/Source/Engine/Graphics/PixelFormat.h +++ b/Source/Engine/Graphics/PixelFormat.h @@ -513,6 +513,16 @@ API_ENUM() enum class PixelFormat : uint32 /// BC7_UNorm_sRGB = 99, + /// + /// A four-component ASTC (4x4 pixel block in 128 bits) block-compression format that supports RGBA channels. + /// + ASTC_4x4_UNorm = 100, + + /// + /// A four-component ASTC (4x4 pixel block in 128 bits) block-compression format that supports RGBA channels. + /// + ASTC_4x4_UNorm_sRGB = 101, + /// /// The maximum format value (for internal use only). /// diff --git a/Source/Engine/Graphics/PixelFormatExtensions.cpp b/Source/Engine/Graphics/PixelFormatExtensions.cpp index 991844b22..4369ebb8b 100644 --- a/Source/Engine/Graphics/PixelFormatExtensions.cpp +++ b/Source/Engine/Graphics/PixelFormatExtensions.cpp @@ -5,19 +5,12 @@ // ReSharper disable CppClangTidyClangDiagnosticSwitchEnum -#define MAX_PIXEL_FORMATS 256 - namespace { - int32 sizeOfInBits[MAX_PIXEL_FORMATS]; - - int32 GetIndex(const PixelFormat format) - { - return (int32)format; - } + int32 sizeOfInBits[(int32)PixelFormat::MAX]; } -#define InitFormat(formats, bitCount) for(int i = 0; i < ARRAY_COUNT(formats); i++) { sizeOfInBits[GetIndex(formats[i])] = bitCount; } +#define InitFormat(formats, bitCount) for(int i = 0; i < ARRAY_COUNT(formats); i++) { sizeOfInBits[(int32)formats[i]] = bitCount; } void PixelFormatExtensions::Init() { @@ -35,7 +28,9 @@ void PixelFormatExtensions::Init() PixelFormat::R8_SNorm, PixelFormat::R8_Typeless, PixelFormat::R8_UInt, - PixelFormat::R8_UNorm + PixelFormat::R8_UNorm, + PixelFormat::ASTC_4x4_UNorm, + PixelFormat::ASTC_4x4_UNorm_sRGB, }; InitFormat(formats2, 8); @@ -53,8 +48,7 @@ void PixelFormatExtensions::Init() PixelFormat::R8G8_SNorm, PixelFormat::R8G8_Typeless, PixelFormat::R8G8_UInt, - PixelFormat::R8G8_UNorm - + PixelFormat::R8G8_UNorm, }; InitFormat(formats3, 16); @@ -163,7 +157,7 @@ void PixelFormatExtensions::Init() int32 PixelFormatExtensions::SizeInBits(PixelFormat format) { - return sizeOfInBits[GetIndex(format)]; + return sizeOfInBits[(int32)format]; } int32 PixelFormatExtensions::AlphaSizeInBits(const PixelFormat format) @@ -319,6 +313,8 @@ bool PixelFormatExtensions::IsCompressed(const PixelFormat format) case PixelFormat::BC7_Typeless: case PixelFormat::BC7_UNorm: case PixelFormat::BC7_UNorm_sRGB: + case PixelFormat::ASTC_4x4_UNorm: + case PixelFormat::ASTC_4x4_UNorm_sRGB: return true; default: return false; @@ -356,6 +352,18 @@ bool PixelFormatExtensions::IsCompressedBC(PixelFormat format) } } +bool PixelFormatExtensions::IsCompressedASTC(PixelFormat format) +{ + switch (format) + { + case PixelFormat::ASTC_4x4_UNorm: + case PixelFormat::ASTC_4x4_UNorm_sRGB: + return true; + default: + return false; + } +} + bool PixelFormatExtensions::IsPacked(const PixelFormat format) { return format == PixelFormat::R8G8_B8G8_UNorm || format == PixelFormat::G8R8_G8B8_UNorm; @@ -382,6 +390,7 @@ bool PixelFormatExtensions::IsSRGB(const PixelFormat format) case PixelFormat::B8G8R8A8_UNorm_sRGB: case PixelFormat::B8G8R8X8_UNorm_sRGB: case PixelFormat::BC7_UNorm_sRGB: + case PixelFormat::ASTC_4x4_UNorm_sRGB: return true; default: return false; @@ -392,6 +401,8 @@ bool PixelFormatExtensions::IsHDR(const PixelFormat format) { switch (format) { + case PixelFormat::R11G11B10_Float: + case PixelFormat::R10G10B10A2_UNorm: case PixelFormat::R16G16B16A16_Float: case PixelFormat::R32G32B32A32_Float: case PixelFormat::R16G16_Float: @@ -399,7 +410,6 @@ bool PixelFormatExtensions::IsHDR(const PixelFormat format) case PixelFormat::BC6H_Sf16: case PixelFormat::BC6H_Uf16: return true; - default: return false; } @@ -527,7 +537,7 @@ bool PixelFormatExtensions::IsInteger(const PixelFormat format) } } -int PixelFormatExtensions::ComputeScanlineCount(const PixelFormat format, int32 height) +int32 PixelFormatExtensions::ComputeScanlineCount(const PixelFormat format, int32 height) { switch (format) { @@ -552,13 +562,15 @@ int PixelFormatExtensions::ComputeScanlineCount(const PixelFormat format, int32 case PixelFormat::BC7_Typeless: case PixelFormat::BC7_UNorm: case PixelFormat::BC7_UNorm_sRGB: + case PixelFormat::ASTC_4x4_UNorm: + case PixelFormat::ASTC_4x4_UNorm_sRGB: return Math::Max(1, (height + 3) / 4); default: return height; } } -int PixelFormatExtensions::ComputeComponentsCount(const PixelFormat format) +int32 PixelFormatExtensions::ComputeComponentsCount(const PixelFormat format) { switch (format) { @@ -599,6 +611,8 @@ int PixelFormatExtensions::ComputeComponentsCount(const PixelFormat format) case PixelFormat::B8G8R8A8_UNorm_sRGB: case PixelFormat::B8G8R8X8_Typeless: case PixelFormat::B8G8R8X8_UNorm_sRGB: + case PixelFormat::ASTC_4x4_UNorm: + case PixelFormat::ASTC_4x4_UNorm_sRGB: return 4; case PixelFormat::R32G32B32_Typeless: case PixelFormat::R32G32B32_Float: @@ -678,6 +692,8 @@ PixelFormat PixelFormatExtensions::TosRGB(const PixelFormat format) return PixelFormat::B8G8R8X8_UNorm_sRGB; case PixelFormat::BC7_UNorm: return PixelFormat::BC7_UNorm_sRGB; + case PixelFormat::ASTC_4x4_UNorm: + return PixelFormat::ASTC_4x4_UNorm_sRGB; default: return format; } @@ -701,6 +717,8 @@ PixelFormat PixelFormatExtensions::ToNonsRGB(const PixelFormat format) return PixelFormat::B8G8R8X8_UNorm; case PixelFormat::BC7_UNorm_sRGB: return PixelFormat::BC7_UNorm; + case PixelFormat::ASTC_4x4_UNorm_sRGB: + return PixelFormat::ASTC_4x4_UNorm; default: return format; } diff --git a/Source/Engine/Graphics/PixelFormatExtensions.h b/Source/Engine/Graphics/PixelFormatExtensions.h index 604bcb2c3..67049cd5a 100644 --- a/Source/Engine/Graphics/PixelFormatExtensions.h +++ b/Source/Engine/Graphics/PixelFormatExtensions.h @@ -95,6 +95,13 @@ public: /// True if the is a compressed format from BC formats family. API_FUNCTION() static bool IsCompressedBC(PixelFormat format); + /// + /// Returns true if the is a compressed format from ASTC formats family (various block sizes). + /// + /// The format to check for compressed. + /// True if the is a compressed format from ASTC formats family. + API_FUNCTION() static bool IsCompressedASTC(PixelFormat format); + /// /// Determines whether the specified is packed. /// @@ -164,14 +171,14 @@ public: /// The . /// The height. /// The scanline count. - API_FUNCTION() static int ComputeScanlineCount(PixelFormat format, int32 height); + API_FUNCTION() static int32 ComputeScanlineCount(PixelFormat format, int32 height); /// /// Computes the format components count (number of R, G, B, A channels). /// /// The . /// The components count. - API_FUNCTION() static int ComputeComponentsCount(PixelFormat format); + API_FUNCTION() static int32 ComputeComponentsCount(PixelFormat format); /// /// Finds the equivalent sRGB format to the provided format. diff --git a/Source/Engine/GraphicsDevice/Vulkan/RenderToolsVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/RenderToolsVulkan.cpp index 7bf254f6a..3a5a91e5e 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/RenderToolsVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/RenderToolsVulkan.cpp @@ -6,8 +6,8 @@ #include "Engine/Core/Types/StringBuilder.h" #include "Engine/Core/Log.h" -VkFormat RenderToolsVulkan::PixelFormatToVkFormat[static_cast(PixelFormat::MAX)] = { - +VkFormat RenderToolsVulkan::PixelFormatToVkFormat[102] = +{ VK_FORMAT_UNDEFINED, VK_FORMAT_R32G32B32A32_SFLOAT, VK_FORMAT_R32G32B32A32_SFLOAT, @@ -27,13 +27,10 @@ VkFormat RenderToolsVulkan::PixelFormatToVkFormat[static_cast(PixelFormat VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_R32G32_UINT, VK_FORMAT_R32G32_SINT, - VK_FORMAT_UNDEFINED, - // TODO: R32G8X24_Typeless + VK_FORMAT_UNDEFINED, // TODO: R32G8X24_Typeless VK_FORMAT_D32_SFLOAT_S8_UINT, - VK_FORMAT_UNDEFINED, - // TODO: R32_Float_X8X24_Typeless - VK_FORMAT_UNDEFINED, - // TODO: X32_Typeless_G8X24_UInt + VK_FORMAT_UNDEFINED, // TODO: R32_Float_X8X24_Typeless + VK_FORMAT_UNDEFINED, // TODO: X32_Typeless_G8X24_UInt VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_FORMAT_A2B10G10R10_UINT_PACK32, @@ -76,15 +73,11 @@ VkFormat RenderToolsVulkan::PixelFormatToVkFormat[static_cast(PixelFormat VK_FORMAT_R8_UINT, VK_FORMAT_R8_SNORM, VK_FORMAT_R8_SINT, - VK_FORMAT_UNDEFINED, - // TODO: A8_UNorm - VK_FORMAT_UNDEFINED, - // TODO: R1_UNorm + VK_FORMAT_UNDEFINED, // TODO: A8_UNorm + VK_FORMAT_UNDEFINED, // TODO: R1_UNorm VK_FORMAT_E5B9G9R9_UFLOAT_PACK32, - VK_FORMAT_UNDEFINED, - // TODO: R8G8_B8G8_UNorm - VK_FORMAT_UNDEFINED, - // TODO: G8R8_G8B8_UNorm + VK_FORMAT_UNDEFINED, // TODO: R8G8_B8G8_UNorm + VK_FORMAT_UNDEFINED, // TODO: G8R8_G8B8_UNorm VK_FORMAT_BC1_RGBA_UNORM_BLOCK, VK_FORMAT_BC1_RGBA_UNORM_BLOCK, VK_FORMAT_BC1_RGBA_SRGB_BLOCK, @@ -104,8 +97,7 @@ VkFormat RenderToolsVulkan::PixelFormatToVkFormat[static_cast(PixelFormat VK_FORMAT_B5G5R5A1_UNORM_PACK16, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_UNORM, - VK_FORMAT_UNDEFINED, - // TODO: R10G10B10_Xr_Bias_A2_UNorm + VK_FORMAT_UNDEFINED, // TODO: R10G10B10_Xr_Bias_A2_UNorm VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_B8G8R8A8_UNORM, @@ -116,81 +108,53 @@ VkFormat RenderToolsVulkan::PixelFormatToVkFormat[static_cast(PixelFormat VK_FORMAT_BC7_UNORM_BLOCK, VK_FORMAT_BC7_UNORM_BLOCK, VK_FORMAT_BC7_SRGB_BLOCK, + VK_FORMAT_ASTC_4x4_UNORM_BLOCK, + VK_FORMAT_ASTC_4x4_SRGB_BLOCK, }; -VkBlendFactor RenderToolsVulkan::BlendToVkBlendFactor[static_cast(BlendingMode::Blend::MAX)] = +VkBlendFactor RenderToolsVulkan::BlendToVkBlendFactor[20] = { VK_BLEND_FACTOR_MAX_ENUM, - VK_BLEND_FACTOR_ZERO, - // Zero - VK_BLEND_FACTOR_ONE, - // One - VK_BLEND_FACTOR_SRC_COLOR, - // SrcColor - VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, - // InvSrcColor - VK_BLEND_FACTOR_SRC_ALPHA, - // SrcAlpha - VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - // InvSrcAlpha - VK_BLEND_FACTOR_DST_ALPHA, - // DestAlpha - VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA, - // InvDestAlpha - VK_BLEND_FACTOR_DST_COLOR, - // DestColor, - VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR, - // InvDestColor - VK_BLEND_FACTOR_SRC_ALPHA_SATURATE, - // SrcAlphaSat - VK_BLEND_FACTOR_CONSTANT_ALPHA, - // BlendFactor - VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA, - // BlendInvFactor - VK_BLEND_FACTOR_SRC1_COLOR, - // Src1Color - VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR, - // InvSrc1Color - VK_BLEND_FACTOR_SRC1_ALPHA, - // Src1Alpha - VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA, - // InvSrc1Alpha + VK_BLEND_FACTOR_ZERO, // Zero + VK_BLEND_FACTOR_ONE, // One + VK_BLEND_FACTOR_SRC_COLOR, // SrcColor + VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, // InvSrcColor + VK_BLEND_FACTOR_SRC_ALPHA, // SrcAlpha + VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, // InvSrcAlpha + VK_BLEND_FACTOR_DST_ALPHA, // DestAlpha + VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA, // InvDestAlpha + VK_BLEND_FACTOR_DST_COLOR, // DestColor, + VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR, // InvDestColor + VK_BLEND_FACTOR_SRC_ALPHA_SATURATE, // SrcAlphaSat + VK_BLEND_FACTOR_CONSTANT_ALPHA, // BlendFactor + VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA, // BlendInvFactor + VK_BLEND_FACTOR_SRC1_COLOR, // Src1Color + VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR, // InvSrc1Color + VK_BLEND_FACTOR_SRC1_ALPHA, // Src1Alpha + VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA, // InvSrc1Alpha }; -VkBlendOp RenderToolsVulkan::OperationToVkBlendOp[static_cast(BlendingMode::Operation::MAX)] = +VkBlendOp RenderToolsVulkan::OperationToVkBlendOp[6] = { VK_BLEND_OP_MAX_ENUM, - VK_BLEND_OP_ADD, - // Add - VK_BLEND_OP_SUBTRACT, - // Subtract - VK_BLEND_OP_REVERSE_SUBTRACT, - // RevSubtract - VK_BLEND_OP_MIN, - // Min - VK_BLEND_OP_MAX, - // Max + VK_BLEND_OP_ADD, // Add + VK_BLEND_OP_SUBTRACT, // Subtract + VK_BLEND_OP_REVERSE_SUBTRACT, // RevSubtract + VK_BLEND_OP_MIN, // Min + VK_BLEND_OP_MAX, // Max }; -VkCompareOp RenderToolsVulkan::ComparisonFuncToVkCompareOp[static_cast(ComparisonFunc::MAX)] = +VkCompareOp RenderToolsVulkan::ComparisonFuncToVkCompareOp[9] = { VK_COMPARE_OP_MAX_ENUM, - VK_COMPARE_OP_NEVER, - // Never - VK_COMPARE_OP_LESS, - // Less - VK_COMPARE_OP_EQUAL, - // Equal - VK_COMPARE_OP_LESS_OR_EQUAL, - // LessEqual - VK_COMPARE_OP_GREATER, - // Grather - VK_COMPARE_OP_NOT_EQUAL, - // NotEqual - VK_COMPARE_OP_GREATER_OR_EQUAL, - // GratherEqual - VK_COMPARE_OP_ALWAYS, - // Always + VK_COMPARE_OP_NEVER, // Never + VK_COMPARE_OP_LESS, // Less + VK_COMPARE_OP_EQUAL, // Equal + VK_COMPARE_OP_LESS_OR_EQUAL, // LessEqual + VK_COMPARE_OP_GREATER, // Grather + VK_COMPARE_OP_NOT_EQUAL, // NotEqual + VK_COMPARE_OP_GREATER_OR_EQUAL, // GratherEqual + VK_COMPARE_OP_ALWAYS, // Always }; #define VKERR(x) case x: sb.Append(TEXT(#x)); break From 3761eb5a1e00a0e0feb8d7458aa36166023b9623 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 15 Dec 2023 13:41:37 +0100 Subject: [PATCH 2/9] Add normal logs for deps build subcommands --- .../Flax.Build/Deps/Dependencies/OpenAL.cs | 18 ++++++------- .../Flax.Build/Deps/Dependencies/PhysX.cs | 8 +++--- .../Flax.Build/Deps/Dependencies/freetype.cs | 8 +++--- .../Flax.Build/Deps/Dependencies/glslang.cs | 16 ++++++------ .../Tools/Flax.Build/Deps/Dependencies/ogg.cs | 12 ++++----- .../Flax.Build/Deps/Dependencies/vorbis.cs | 20 +++++++------- Source/Tools/Flax.Build/Deps/Dependency.cs | 26 +++++++++---------- 7 files changed, 54 insertions(+), 54 deletions(-) diff --git a/Source/Tools/Flax.Build/Deps/Dependencies/OpenAL.cs b/Source/Tools/Flax.Build/Deps/Dependencies/OpenAL.cs index 1adb73bb3..96ef05dd8 100644 --- a/Source/Tools/Flax.Build/Deps/Dependencies/OpenAL.cs +++ b/Source/Tools/Flax.Build/Deps/Dependencies/OpenAL.cs @@ -102,7 +102,7 @@ namespace Flax.Deps.Dependencies var packagePath = Path.Combine(root, "package.zip"); File.Delete(packagePath); Downloader.DownloadFileFromUrlToPath("https://openal-soft.org/openal-releases/openal-soft-" + version + ".tar.bz2", packagePath); - Utilities.Run("tar", "xjf " + packagePath.Replace('\\', '/'), null, root, Utilities.RunOptions.None); + Utilities.Run("tar", "xjf " + packagePath.Replace('\\', '/'), null, root, Utilities.RunOptions.ConsoleLogOutput); // Use separate build directory root = Path.Combine(root, "openal-soft-" + version); @@ -110,8 +110,8 @@ namespace Flax.Deps.Dependencies SetupDirectory(buildDir, true); // Build for Linux - Utilities.Run("cmake", "-G \"Unix Makefiles\" -DCMAKE_BUILD_TYPE=Release -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DLIBTYPE=STATIC " + config + " ..", null, buildDir, Utilities.RunOptions.None, envVars); - Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.None, envVars); + Utilities.Run("cmake", "-G \"Unix Makefiles\" -DCMAKE_BUILD_TYPE=Release -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DLIBTYPE=STATIC " + config + " ..", null, buildDir, Utilities.RunOptions.ConsoleLogOutput, envVars); + Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.ConsoleLogOutput, envVars); var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.x64); foreach (var file in binariesToCopy) Utilities.FileCopy(Path.Combine(buildDir, file), Path.Combine(depsFolder, file)); @@ -137,7 +137,7 @@ namespace Flax.Deps.Dependencies } else { - Utilities.Run("tar", "xjf " + packagePath.Replace('\\', '/'), null, root, Utilities.RunOptions.None); + Utilities.Run("tar", "xjf " + packagePath.Replace('\\', '/'), null, root, Utilities.RunOptions.ConsoleLogOutput); } // Use separate build directory @@ -147,7 +147,7 @@ namespace Flax.Deps.Dependencies // Build RunCmake(buildDir, platform, TargetArchitecture.ARM64, ".. -DLIBTYPE=STATIC -DCMAKE_BUILD_TYPE=Release " + config); - Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.None); + Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.ConsoleLogOutput); var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.ARM64); foreach (var file in binariesToCopy) Utilities.FileCopy(Path.Combine(buildDir, file), Path.Combine(depsFolder, file)); @@ -165,7 +165,7 @@ namespace Flax.Deps.Dependencies var packagePath = Path.Combine(root, "package.zip"); File.Delete(packagePath); Downloader.DownloadFileFromUrlToPath("https://openal-soft.org/openal-releases/openal-soft-" + version + ".tar.bz2", packagePath); - Utilities.Run("tar", "xjf " + packagePath.Replace('\\', '/'), null, root, Utilities.RunOptions.None); + Utilities.Run("tar", "xjf " + packagePath.Replace('\\', '/'), null, root, Utilities.RunOptions.ConsoleLogOutput); // Use separate build directory root = Path.Combine(root, "openal-soft-" + version); @@ -176,7 +176,7 @@ namespace Flax.Deps.Dependencies { SetupDirectory(buildDir, true); RunCmake(buildDir, platform, architecture, ".. -DLIBTYPE=STATIC -DCMAKE_BUILD_TYPE=Release " + config); - Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.None); + Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.ConsoleLogOutput); var depsFolder = GetThirdPartyFolder(options, platform, architecture); foreach (var file in binariesToCopy) Utilities.FileCopy(Path.Combine(buildDir, file), Path.Combine(depsFolder, file)); @@ -196,7 +196,7 @@ namespace Flax.Deps.Dependencies if (!File.Exists(packagePath)) { Downloader.DownloadFileFromUrlToPath("https://openal-soft.org/openal-releases/openal-soft-" + version + ".tar.bz2", packagePath); - Utilities.Run("tar", "xjf " + packagePath.Replace('\\', '/'), null, root, Utilities.RunOptions.None); + Utilities.Run("tar", "xjf " + packagePath.Replace('\\', '/'), null, root, Utilities.RunOptions.ConsoleLogOutput); } // Use separate build directory @@ -206,7 +206,7 @@ namespace Flax.Deps.Dependencies // Build for iOS SetupDirectory(buildDir, true); RunCmake(buildDir, platform, TargetArchitecture.ARM64, ".. -DCMAKE_SYSTEM_NAME=iOS -DALSOFT_OSX_FRAMEWORK=ON -DLIBTYPE=STATIC -DCMAKE_BUILD_TYPE=Release " + config); - Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.None); + Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.ConsoleLogOutput); var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.ARM64); foreach (var file in binariesToCopy) Utilities.FileCopy(Path.Combine(buildDir, file), Path.Combine(depsFolder, file)); diff --git a/Source/Tools/Flax.Build/Deps/Dependencies/PhysX.cs b/Source/Tools/Flax.Build/Deps/Dependencies/PhysX.cs index 2de1f64a5..f26440482 100644 --- a/Source/Tools/Flax.Build/Deps/Dependencies/PhysX.cs +++ b/Source/Tools/Flax.Build/Deps/Dependencies/PhysX.cs @@ -283,7 +283,7 @@ namespace Flax.Deps.Dependencies switch (targetPlatform) { case TargetPlatform.Android: - Utilities.Run("cmake", "--build .", null, Path.Combine(root, "physx\\compiler\\android-" + configuration), Utilities.RunOptions.None, envVars); + Utilities.Run("cmake", "--build .", null, Path.Combine(root, "physx\\compiler\\android-" + configuration), Utilities.RunOptions.ConsoleLogOutput, envVars); break; default: VCEnvironment.BuildSolution(Path.Combine(solutionFilesRoot, preset, "PhysXSDK.sln"), configuration, buildPlatform, msBuildProps, msBuild); @@ -291,10 +291,10 @@ namespace Flax.Deps.Dependencies } break; case TargetPlatform.Linux: - Utilities.Run("make", null, null, Path.Combine(projectGenDir, "compiler", "linux-" + configuration), Utilities.RunOptions.None); + Utilities.Run("make", null, null, Path.Combine(projectGenDir, "compiler", "linux-" + configuration), Utilities.RunOptions.ConsoleLogOutput); break; case TargetPlatform.Mac: - Utilities.Run("xcodebuild", "-project PhysXSDK.xcodeproj -alltargets -configuration " + configuration, null, Path.Combine(projectGenDir, "compiler", preset), Utilities.RunOptions.None); + Utilities.Run("xcodebuild", "-project PhysXSDK.xcodeproj -alltargets -configuration " + configuration, null, Path.Combine(projectGenDir, "compiler", preset), Utilities.RunOptions.ConsoleLogOutput); break; default: throw new InvalidPlatformException(BuildPlatform); } @@ -321,7 +321,7 @@ namespace Flax.Deps.Dependencies { case TargetPlatform.Mac: case TargetPlatform.Android: - Utilities.Run("strip", "\"" + filename + "\"", null, dstBinaries, Utilities.RunOptions.None); + Utilities.Run("strip", "\"" + filename + "\"", null, dstBinaries, Utilities.RunOptions.ConsoleLogOutput); break; } break; diff --git a/Source/Tools/Flax.Build/Deps/Dependencies/freetype.cs b/Source/Tools/Flax.Build/Deps/Dependencies/freetype.cs index 165317180..d2d31a613 100644 --- a/Source/Tools/Flax.Build/Deps/Dependencies/freetype.cs +++ b/Source/Tools/Flax.Build/Deps/Dependencies/freetype.cs @@ -229,7 +229,7 @@ namespace Flax.Deps.Dependencies // Build for Android SetupDirectory(buildDir, true); RunCmake(buildDir, TargetPlatform.Android, TargetArchitecture.ARM64, ".. -DFT_WITH_BZIP2=OFF -DFT_WITH_ZLIB=OFF -DFT_WITH_PNG=OFF -DCMAKE_BUILD_TYPE=Release"); - Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.None); + Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.ConsoleLogOutput); var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.ARM64); Utilities.FileCopy(Path.Combine(buildDir, libraryFileName), Path.Combine(depsFolder, libraryFileName)); break; @@ -239,7 +239,7 @@ namespace Flax.Deps.Dependencies // Build for Switch SetupDirectory(buildDir, true); RunCmake(buildDir, platform, TargetArchitecture.ARM64, ".. -DCMAKE_BUILD_TYPE=Release"); - Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.None); + Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.ConsoleLogOutput); var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.ARM64); Utilities.FileCopy(Path.Combine(buildDir, libraryFileName), Path.Combine(depsFolder, libraryFileName)); break; @@ -251,7 +251,7 @@ namespace Flax.Deps.Dependencies { SetupDirectory(buildDir, true); RunCmake(buildDir, platform, architecture, ".. -DCMAKE_BUILD_TYPE=Release"); - Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.None); + Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.ConsoleLogOutput); var depsFolder = GetThirdPartyFolder(options, platform, architecture); Utilities.FileCopy(Path.Combine(buildDir, libraryFileName), Path.Combine(depsFolder, libraryFileName)); } @@ -268,7 +268,7 @@ namespace Flax.Deps.Dependencies // Build for iOS SetupDirectory(buildDir, true); RunCmake(buildDir, platform, TargetArchitecture.ARM64, ".. -DIOS_PLATFORM=OS -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_BUILD_TYPE=Release -DFT_WITH_BZIP2=OFF -DFT_WITH_ZLIB=OFF -DFT_WITH_PNG=OFF"); - Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.None); + Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.ConsoleLogOutput); var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.ARM64); Utilities.FileCopy(Path.Combine(buildDir, libraryFileName), Path.Combine(depsFolder, libraryFileName)); break; diff --git a/Source/Tools/Flax.Build/Deps/Dependencies/glslang.cs b/Source/Tools/Flax.Build/Deps/Dependencies/glslang.cs index f88ded6a1..46863ec08 100644 --- a/Source/Tools/Flax.Build/Deps/Dependencies/glslang.cs +++ b/Source/Tools/Flax.Build/Deps/Dependencies/glslang.cs @@ -53,7 +53,7 @@ namespace Flax.Deps.Dependencies CloneGitRepoFast(root, "https://github.com/FlaxEngine/glslang.git"); // Setup the external sources - Utilities.Run("python", "update_glslang_sources.py", null, root, Utilities.RunOptions.None); + Utilities.Run("python", "update_glslang_sources.py", null, root, Utilities.RunOptions.ConsoleLogOutput); foreach (var platform in options.Platforms) { @@ -77,7 +77,7 @@ namespace Flax.Deps.Dependencies // Build for Win64 File.Delete(Path.Combine(buildDir, "CMakeCache.txt")); RunCmake(buildDir, platform, TargetArchitecture.x64, cmakeArgs); - Utilities.Run("cmake", string.Format("--build . --config {0} --target install", configuration), null, buildDir, Utilities.RunOptions.None); + Utilities.Run("cmake", string.Format("--build . --config {0} --target install", configuration), null, buildDir, Utilities.RunOptions.ConsoleLogOutput); Deploy.VCEnvironment.BuildSolution(solutionPath, configuration, "x64"); var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.x64); foreach (var file in outputFiles) @@ -103,14 +103,14 @@ namespace Flax.Deps.Dependencies // Build for Linux RunCmake(root, platform, TargetArchitecture.x64, cmakeArgs); - Utilities.Run("cmake", string.Format("--build . --config {0} --target install", configuration), null, buildDir, Utilities.RunOptions.None); - Utilities.Run("make", null, null, root, Utilities.RunOptions.None); + Utilities.Run("cmake", string.Format("--build . --config {0} --target install", configuration), null, buildDir, Utilities.RunOptions.ConsoleLogOutput); + Utilities.Run("make", null, null, root, Utilities.RunOptions.ConsoleLogOutput); var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.x64); foreach (var file in outputFiles) { var dst = Path.Combine(depsFolder, Path.GetFileName(file)); Utilities.FileCopy(file, dst); - //Utilities.Run("strip", string.Format("-s \"{0}\"", dst), null, null, Utilities.RunOptions.None); + //Utilities.Run("strip", string.Format("-s \"{0}\"", dst), null, null, Utilities.RunOptions.ConsoleLogOutput); } break; } @@ -133,14 +133,14 @@ namespace Flax.Deps.Dependencies foreach (var architecture in new []{ TargetArchitecture.x64, TargetArchitecture.ARM64 }) { RunCmake(root, platform, architecture, cmakeArgs); - Utilities.Run("cmake", string.Format("--build . --config {0} --target install", configuration), null, buildDir, Utilities.RunOptions.None); - Utilities.Run("make", null, null, root, Utilities.RunOptions.None); + Utilities.Run("cmake", string.Format("--build . --config {0} --target install", configuration), null, buildDir, Utilities.RunOptions.ConsoleLogOutput); + Utilities.Run("make", null, null, root, Utilities.RunOptions.ConsoleLogOutput); var depsFolder = GetThirdPartyFolder(options, platform, architecture); foreach (var file in outputFiles) { var dst = Path.Combine(depsFolder, Path.GetFileName(file)); Utilities.FileCopy(file, dst); - Utilities.Run("strip", string.Format("\"{0}\"", dst), null, null, Utilities.RunOptions.None); + Utilities.Run("strip", string.Format("\"{0}\"", dst), null, null, Utilities.RunOptions.ConsoleLogOutput); } } break; diff --git a/Source/Tools/Flax.Build/Deps/Dependencies/ogg.cs b/Source/Tools/Flax.Build/Deps/Dependencies/ogg.cs index fe6800001..eb02accef 100644 --- a/Source/Tools/Flax.Build/Deps/Dependencies/ogg.cs +++ b/Source/Tools/Flax.Build/Deps/Dependencies/ogg.cs @@ -128,8 +128,8 @@ namespace Flax.Deps.Dependencies var toolchain = UnixToolchain.GetToolchainName(platform, TargetArchitecture.x64); Utilities.Run(Path.Combine(root, "configure"), string.Format("--host={0}", toolchain), null, root, Utilities.RunOptions.Default, envVars); SetupDirectory(buildDir, true); - Utilities.Run("cmake", "-G \"Unix Makefiles\" -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_BUILD_TYPE=Release ..", null, buildDir, Utilities.RunOptions.None, envVars); - Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.None, envVars); + Utilities.Run("cmake", "-G \"Unix Makefiles\" -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_BUILD_TYPE=Release ..", null, buildDir, Utilities.RunOptions.ConsoleLogOutput, envVars); + Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.ConsoleLogOutput, envVars); var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.x64); Utilities.FileCopy(Path.Combine(buildDir, libraryFileName), Path.Combine(depsFolder, libraryFileName)); @@ -196,7 +196,7 @@ namespace Flax.Deps.Dependencies // Build for Android SetupDirectory(buildDir, true); RunCmake(buildDir, platform, TargetArchitecture.ARM64, ".. -DCMAKE_BUILD_TYPE=Release"); - Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.None); + Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.ConsoleLogOutput); var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.ARM64); Utilities.FileCopy(Path.Combine(buildDir, libraryFileName), Path.Combine(depsFolder, libraryFileName)); break; @@ -209,7 +209,7 @@ namespace Flax.Deps.Dependencies // Build for Switch SetupDirectory(buildDir, true); RunCmake(buildDir, platform, TargetArchitecture.ARM64, ".. -DCMAKE_BUILD_TYPE=Release"); - Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.None); + Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.ConsoleLogOutput); var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.ARM64); Utilities.FileCopy(Path.Combine(buildDir, libraryFileName), Path.Combine(depsFolder, libraryFileName)); break; @@ -221,7 +221,7 @@ namespace Flax.Deps.Dependencies { SetupDirectory(buildDir, true); RunCmake(buildDir, platform, architecture, ".. -DCMAKE_BUILD_TYPE=Release"); - Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.None); + Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.ConsoleLogOutput); var depsFolder = GetThirdPartyFolder(options, platform, architecture); Utilities.FileCopy(Path.Combine(buildDir, libraryFileName), Path.Combine(depsFolder, libraryFileName)); } @@ -231,7 +231,7 @@ namespace Flax.Deps.Dependencies { SetupDirectory(buildDir, true); RunCmake(buildDir, platform, TargetArchitecture.ARM64, ".. -DCMAKE_BUILD_TYPE=Release"); - Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.None); + Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.ConsoleLogOutput); var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.ARM64); Utilities.FileCopy(Path.Combine(buildDir, libraryFileName), Path.Combine(depsFolder, libraryFileName)); break; diff --git a/Source/Tools/Flax.Build/Deps/Dependencies/vorbis.cs b/Source/Tools/Flax.Build/Deps/Dependencies/vorbis.cs index 75b2810be..c3a53ebd4 100644 --- a/Source/Tools/Flax.Build/Deps/Dependencies/vorbis.cs +++ b/Source/Tools/Flax.Build/Deps/Dependencies/vorbis.cs @@ -292,8 +292,8 @@ namespace Flax.Deps.Dependencies var toolchain = UnixToolchain.GetToolchainName(platform, TargetArchitecture.x64); Utilities.Run(Path.Combine(root, "configure"), string.Format("--host={0}", toolchain), null, root, Utilities.RunOptions.Default, envVars); SetupDirectory(buildDir, true); - Utilities.Run("cmake", "-G \"Unix Makefiles\" -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_BUILD_TYPE=Release ..", null, buildDir, Utilities.RunOptions.None, envVars); - Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.None, envVars); + Utilities.Run("cmake", "-G \"Unix Makefiles\" -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_BUILD_TYPE=Release ..", null, buildDir, Utilities.RunOptions.ConsoleLogOutput, envVars); + Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.ConsoleLogOutput, envVars); var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.x64); foreach (var file in binariesToCopyUnix) Utilities.FileCopy(Path.Combine(buildDir, file.SrcFolder, file.Filename), Path.Combine(depsFolder, file.Filename)); @@ -328,10 +328,10 @@ namespace Flax.Deps.Dependencies // Build for Android SetupDirectory(oggBuildDir, true); RunCmake(oggBuildDir, platform, TargetArchitecture.ARM64, ".. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=\"../install\""); - Utilities.Run("cmake", "--build . --target install", null, oggBuildDir, Utilities.RunOptions.None); + Utilities.Run("cmake", "--build . --target install", null, oggBuildDir, Utilities.RunOptions.ConsoleLogOutput); SetupDirectory(buildDir, true); RunCmake(buildDir, platform, TargetArchitecture.ARM64, string.Format(".. -DCMAKE_BUILD_TYPE=Release -DOGG_INCLUDE_DIR=\"{0}/install/include\" -DOGG_LIBRARY=\"{0}/install/lib\"", oggRoot)); - Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.None); + Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.ConsoleLogOutput); var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.ARM64); foreach (var file in binariesToCopyUnix) Utilities.FileCopy(Path.Combine(buildDir, file.SrcFolder, file.Filename), Path.Combine(depsFolder, file.Filename)); @@ -354,11 +354,11 @@ namespace Flax.Deps.Dependencies // Build for Switch SetupDirectory(oggBuildDir, true); RunCmake(oggBuildDir, platform, TargetArchitecture.ARM64, ".. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=\"../install\""); - Utilities.Run("cmake", "--build . --target install", null, oggBuildDir, Utilities.RunOptions.None); + Utilities.Run("cmake", "--build . --target install", null, oggBuildDir, Utilities.RunOptions.ConsoleLogOutput); Utilities.FileCopy(Path.Combine(GetBinariesFolder(options, platform), "ogg", "include", "ogg", "config_types.h"), Path.Combine(oggRoot, "install", "include", "ogg", "config_types.h")); SetupDirectory(buildDir, true); RunCmake(buildDir, platform, TargetArchitecture.ARM64, string.Format(".. -DCMAKE_BUILD_TYPE=Release -DOGG_INCLUDE_DIR=\"{0}/install/include\" -DOGG_LIBRARY=\"{0}/install/lib\"", oggRoot)); - Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.None); + Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.ConsoleLogOutput); var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.ARM64); foreach (var file in binariesToCopyUnix) Utilities.FileCopy(Path.Combine(buildDir, file.SrcFolder, file.Filename), Path.Combine(depsFolder, file.Filename)); @@ -380,10 +380,10 @@ namespace Flax.Deps.Dependencies { SetupDirectory(oggBuildDir, true); RunCmake(oggBuildDir, platform, architecture, ".. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=\"../install\""); - Utilities.Run("cmake", "--build . --target install", null, oggBuildDir, Utilities.RunOptions.None); + Utilities.Run("cmake", "--build . --target install", null, oggBuildDir, Utilities.RunOptions.ConsoleLogOutput); SetupDirectory(buildDir, true); RunCmake(buildDir, platform, architecture, string.Format(".. -DCMAKE_BUILD_TYPE=Release -DOGG_INCLUDE_DIR=\"{0}/install/include\" -DOGG_LIBRARY=\"{0}/install/lib\"", oggRoot)); - Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.None); + Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.ConsoleLogOutput); var depsFolder = GetThirdPartyFolder(options, platform, architecture); foreach (var file in binariesToCopyUnix) Utilities.FileCopy(Path.Combine(buildDir, file.SrcFolder, file.Filename), Path.Combine(depsFolder, file.Filename)); @@ -404,10 +404,10 @@ namespace Flax.Deps.Dependencies // Build for Mac SetupDirectory(oggBuildDir, true); RunCmake(oggBuildDir, platform, TargetArchitecture.ARM64, ".. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=\"../install\""); - Utilities.Run("cmake", "--build . --target install", null, oggBuildDir, Utilities.RunOptions.None); + Utilities.Run("cmake", "--build . --target install", null, oggBuildDir, Utilities.RunOptions.ConsoleLogOutput); SetupDirectory(buildDir, true); RunCmake(buildDir, platform, TargetArchitecture.ARM64, string.Format(".. -DCMAKE_BUILD_TYPE=Release -DOGG_INCLUDE_DIR=\"{0}/install/include\" -DOGG_LIBRARY=\"{0}/install/lib\"", oggRoot)); - Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.None); + Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.ConsoleLogOutput); var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.ARM64); foreach (var file in binariesToCopyUnix) Utilities.FileCopy(Path.Combine(buildDir, file.SrcFolder, file.Filename), Path.Combine(depsFolder, file.Filename)); diff --git a/Source/Tools/Flax.Build/Deps/Dependency.cs b/Source/Tools/Flax.Build/Deps/Dependency.cs index 46422179e..e9b646a6b 100644 --- a/Source/Tools/Flax.Build/Deps/Dependency.cs +++ b/Source/Tools/Flax.Build/Deps/Dependency.cs @@ -136,14 +136,14 @@ namespace Flax.Deps if (submodules) cmdLine += " --recurse-submodules"; - Utilities.Run("git", cmdLine, null, null, Utilities.RunOptions.None); + Utilities.Run("git", cmdLine, null, null, Utilities.RunOptions.ConsoleLogOutput); if (submodules) - Utilities.Run("git", "submodule update --init --recursive", null, null, Utilities.RunOptions.None); + Utilities.Run("git", "submodule update --init --recursive", null, null, Utilities.RunOptions.ConsoleLogOutput); } if (commit != null) { - Utilities.Run("git", string.Format("reset --hard {0}", commit), null, null, Utilities.RunOptions.None); + Utilities.Run("git", string.Format("reset --hard {0}", commit), null, null, Utilities.RunOptions.ConsoleLogOutput); } } @@ -164,9 +164,9 @@ namespace Flax.Deps if (submodules) cmdLine += " --recurse-submodules"; - Utilities.Run("git", cmdLine, null, null, Utilities.RunOptions.None); + Utilities.Run("git", cmdLine, null, null, Utilities.RunOptions.ConsoleLogOutput); if (submodules) - Utilities.Run("git", "submodule update --init --recursive", null, null, Utilities.RunOptions.None); + Utilities.Run("git", "submodule update --init --recursive", null, null, Utilities.RunOptions.ConsoleLogOutput); } } @@ -191,14 +191,14 @@ namespace Flax.Deps if (submodules) cmdLine += " --recurse-submodules"; - Utilities.Run("git", cmdLine, null, null, Utilities.RunOptions.None); + Utilities.Run("git", cmdLine, null, null, Utilities.RunOptions.ConsoleLogOutput); if (submodules) - Utilities.Run("git", "submodule update --init --recursive", null, null, Utilities.RunOptions.None); + Utilities.Run("git", "submodule update --init --recursive", null, null, Utilities.RunOptions.ConsoleLogOutput); } if (commit != null) { - Utilities.Run("git", string.Format("reset --hard {0}", commit), null, path, Utilities.RunOptions.None); + Utilities.Run("git", string.Format("reset --hard {0}", commit), null, path, Utilities.RunOptions.ConsoleLogOutput); } } @@ -218,13 +218,13 @@ namespace Flax.Deps if (submodules) cmdLine += " --recurse-submodules"; - Utilities.Run("git", cmdLine, null, path, Utilities.RunOptions.None); + Utilities.Run("git", cmdLine, null, path, Utilities.RunOptions.ConsoleLogOutput); if (submodules) - Utilities.Run("git", "submodule update --init --recursive", null, null, Utilities.RunOptions.None); + Utilities.Run("git", "submodule update --init --recursive", null, null, Utilities.RunOptions.ConsoleLogOutput); if (commit != null) { - Utilities.Run("git", string.Format("reset --hard {0}", commit), null, path, Utilities.RunOptions.None); + Utilities.Run("git", string.Format("reset --hard {0}", commit), null, path, Utilities.RunOptions.ConsoleLogOutput); } } @@ -234,7 +234,7 @@ namespace Flax.Deps /// The local path that contains git repository. public static void GitResetLocalChanges(string path) { - Utilities.Run("git", "reset --hard", null, path, Utilities.RunOptions.None); + Utilities.Run("git", "reset --hard", null, path, Utilities.RunOptions.ConsoleLogOutput); } /// @@ -313,7 +313,7 @@ namespace Flax.Deps if (customArgs != null) cmdLine += " " + customArgs; - Utilities.Run("cmake", cmdLine, null, path, Utilities.RunOptions.None, envVars); + Utilities.Run("cmake", cmdLine, null, path, Utilities.RunOptions.ConsoleLogOutput, envVars); } /// From 799fde1a2685ba443ebf70f5cb6bdbcf96fc4cf8 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 15 Dec 2023 14:33:09 +0100 Subject: [PATCH 3/9] =?UTF-8?q?Add=20=E2=80=98astc=E2=80=99=20encoder=20li?= =?UTF-8?q?b?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/Engine/Graphics/RenderTools.cpp | 13 +- .../Tools/TextureTool/TextureTool.Build.cs | 5 + .../TextureTool/TextureTool.DirectXTex.cpp | 4 + .../Tools/TextureTool/TextureTool.astc.cpp | 117 +++ .../Engine/Tools/TextureTool/TextureTool.cpp | 26 + Source/Engine/Tools/TextureTool/TextureTool.h | 4 + .../Tools/TextureTool/TextureTool.stb.cpp | 11 +- .../Binaries/ThirdParty/ARM64/libastcenc.a | 3 + .../Mac/Binaries/ThirdParty/x64/libastcenc.a | 3 + Source/ThirdParty/astc/LICENSE.txt | 175 ++++ Source/ThirdParty/astc/astc.Build.cs | 39 + Source/ThirdParty/astc/astcenc.h | 829 ++++++++++++++++++ .../Flax.Build/Deps/Dependencies/astc.cs | 65 ++ 13 files changed, 1290 insertions(+), 4 deletions(-) create mode 100644 Source/Engine/Tools/TextureTool/TextureTool.astc.cpp create mode 100644 Source/Platforms/Mac/Binaries/ThirdParty/ARM64/libastcenc.a create mode 100644 Source/Platforms/Mac/Binaries/ThirdParty/x64/libastcenc.a create mode 100644 Source/ThirdParty/astc/LICENSE.txt create mode 100644 Source/ThirdParty/astc/astc.Build.cs create mode 100644 Source/ThirdParty/astc/astcenc.h create mode 100644 Source/Tools/Flax.Build/Deps/Dependencies/astc.cs diff --git a/Source/Engine/Graphics/RenderTools.cpp b/Source/Engine/Graphics/RenderTools.cpp index 55f4df7d2..7ffecd62c 100644 --- a/Source/Engine/Graphics/RenderTools.cpp +++ b/Source/Engine/Graphics/RenderTools.cpp @@ -306,7 +306,6 @@ void RenderTools::ComputePitch(PixelFormat format, int32 width, int32 height, ui slicePitch = rowPitch * nbh; } break; - case PixelFormat::BC2_Typeless: case PixelFormat::BC2_UNorm: case PixelFormat::BC2_UNorm_sRGB: @@ -330,14 +329,22 @@ void RenderTools::ComputePitch(PixelFormat format, int32 width, int32 height, ui slicePitch = rowPitch * nbh; } break; - + case PixelFormat::ASTC_4x4_UNorm: + case PixelFormat::ASTC_4x4_UNorm_sRGB: + { + const int32 blockSize = 4; // TODO: use PixelFormatExtensions to get block size for a format and handle different astc + uint32 nbw = Math::Max(1, Math::DivideAndRoundUp(width, blockSize)); + uint32 nbh = Math::Max(1, Math::DivideAndRoundUp(height, blockSize)); + rowPitch = nbw * 16; + slicePitch = rowPitch * nbh; + } + break; case PixelFormat::R8G8_B8G8_UNorm: case PixelFormat::G8R8_G8B8_UNorm: ASSERT(PixelFormatExtensions::IsPacked(format)); rowPitch = ((width + 1) >> 1) * 4; slicePitch = rowPitch * height; break; - default: ASSERT(PixelFormatExtensions::IsValid(format)); ASSERT(!PixelFormatExtensions::IsCompressed(format) && !PixelFormatExtensions::IsPacked(format) && !PixelFormatExtensions::IsPlanar(format)); diff --git a/Source/Engine/Tools/TextureTool/TextureTool.Build.cs b/Source/Engine/Tools/TextureTool/TextureTool.Build.cs index f2e675038..005ca9c96 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.Build.cs +++ b/Source/Engine/Tools/TextureTool/TextureTool.Build.cs @@ -58,6 +58,11 @@ public class TextureTool : EngineModule options.PrivateDependencies.Add("bc7enc16"); } } + if (options.Target.IsEditor) + { + options.SourceFiles.Add(Path.Combine(FolderPath, "TextureTool.astc.cpp")); + options.PrivateDependencies.Add("astc"); + } options.PublicDefinitions.Add("COMPILE_WITH_TEXTURE_TOOL"); } diff --git a/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp b/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp index dc5b0be49..c8febf0f8 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp @@ -924,6 +924,10 @@ bool TextureTool::ConvertDirectXTex(TextureData& dst, const TextureData& src, co return true; } } + else if (PixelFormatExtensions::IsCompressedASTC(dstFormat)) + { + todo_astc_compression_on_windows; + } // Check if convert data else if (inImage->GetMetadata().format != dstFormatDxgi) { diff --git a/Source/Engine/Tools/TextureTool/TextureTool.astc.cpp b/Source/Engine/Tools/TextureTool/TextureTool.astc.cpp new file mode 100644 index 000000000..21f4f0679 --- /dev/null +++ b/Source/Engine/Tools/TextureTool/TextureTool.astc.cpp @@ -0,0 +1,117 @@ +// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. + +#if COMPILE_WITH_TEXTURE_TOOL && COMPILE_WITH_ASTC + +#include "TextureTool.h" +#include "Engine/Core/Log.h" +#include "Engine/Core/Math/Math.h" +#include "Engine/Core/Math/Color32.h" +#include "Engine/Graphics/Textures/TextureData.h" +#include "Engine/Graphics/PixelFormatExtensions.h" +#include + +bool TextureTool::ConvertAstc(TextureData& dst, const TextureData& src, const PixelFormat dstFormat) +{ + int32 blockSize, bytesPerBlock = 16; + // TODO: use block size from PixelFormatExtensions + switch (dstFormat) + { + case PixelFormat::ASTC_4x4_UNorm: + case PixelFormat::ASTC_4x4_UNorm_sRGB: + blockSize = 4; + break; + default: + LOG(Warning, "Cannot compress image. Unsupported format {0}", static_cast(dstFormat)); + return true; + } + + // Configure the compressor run + const bool isSRGB = PixelFormatExtensions::IsSRGB(dstFormat); + const bool isHDR = PixelFormatExtensions::IsHDR(src.Format); + astcenc_profile astcProfile = isHDR ? ASTCENC_PRF_HDR_RGB_LDR_A : (isSRGB ? ASTCENC_PRF_LDR_SRGB : ASTCENC_PRF_LDR); + float astcQuality = ASTCENC_PRE_MEDIUM; + unsigned int astcFlags = 0; // TODO: add custom flags support for converter to handle ASTCENC_FLG_MAP_NORMAL + astcenc_config astcConfig; + astcenc_error astcError = astcenc_config_init(astcProfile, blockSize, blockSize, 1, astcQuality, astcFlags, &astcConfig); + if (astcError != ASTCENC_SUCCESS) + { + LOG(Warning, "Cannot compress image. ASTC failed with error: {}", String(astcenc_get_error_string(astcError))); + return true; + } + astcenc_swizzle astcSwizzle = { ASTCENC_SWZ_R, ASTCENC_SWZ_G, ASTCENC_SWZ_B, ASTCENC_SWZ_A }; + + // Allocate working state given config and thread_count + astcenc_context* astcContext; + astcError = astcenc_context_alloc(&astcConfig, 1, &astcContext); + if (astcError != ASTCENC_SUCCESS) + { + LOG(Warning, "Cannot compress image. ASTC failed with error: {}", String(astcenc_get_error_string(astcError))); + return true; + } + + // When converting from non-sRGB to sRGB we need to change the color-space manually (otherwise image is dark) + TextureData const* textureData = &src; + TextureData converted; + if (PixelFormatExtensions::IsSRGB(src.Format) != isSRGB) + { + converted = src; + Function transform = [](Color& c) + { + c = Color::LinearToSrgb(c); + }; + if (!TextureTool::Transform(converted, transform)) + { + textureData = &converted; + } + } + + // Compress all array slices + for (int32 arrayIndex = 0; arrayIndex < textureData->Items.Count() && astcError == ASTCENC_SUCCESS; arrayIndex++) + { + const auto& srcSlice = textureData->Items[arrayIndex]; + auto& dstSlice = dst.Items[arrayIndex]; + auto mipLevels = srcSlice.Mips.Count(); + dstSlice.Mips.Resize(mipLevels, false); + + // Compress all mip levels + for (int32 mipIndex = 0; mipIndex < mipLevels && astcError == ASTCENC_SUCCESS; mipIndex++) + { + const auto& srcMip = srcSlice.Mips[mipIndex]; + // TODO: validate if source mip data is row and pitch aligned (astcenc_image operates on whole pixel count withotu a slack) + auto& dstMip = dstSlice.Mips[mipIndex]; + auto mipWidth = Math::Max(textureData->Width >> mipIndex, 1); + auto mipHeight = Math::Max(textureData->Height >> mipIndex, 1); + auto blocksWidth = Math::Max(Math::DivideAndRoundUp(mipWidth, blockSize), 1); + auto blocksHeight = Math::Max(Math::DivideAndRoundUp(mipHeight, blockSize), 1); + + // Allocate memory + dstMip.RowPitch = blocksWidth * bytesPerBlock; + dstMip.DepthPitch = dstMip.RowPitch * blocksHeight; + dstMip.Lines = blocksHeight; + dstMip.Data.Allocate(dstMip.DepthPitch); + + // Compress image + astcenc_image astcInput; + astcInput.dim_x = mipWidth; + astcInput.dim_y = mipHeight; + astcInput.dim_z = 1; + astcInput.data_type = isHDR ? ASTCENC_TYPE_F16 : ASTCENC_TYPE_U8; + void* srcData = (void*)srcMip.Data.Get(); + astcInput.data = &srcData; + astcError = astcenc_compress_image(astcContext, &astcInput, &astcSwizzle, dstMip.Data.Get(), dstMip.Data.Length(), 0); + if (astcError == ASTCENC_SUCCESS) + astcError = astcenc_compress_reset(astcContext); + } + } + + // Clean up + if (astcError != ASTCENC_SUCCESS) + { + LOG(Warning, "Cannot compress image. ASTC failed with error: {}", String(astcenc_get_error_string(astcError))); + return true; + } + astcenc_context_free(astcContext); + return astcError != ASTCENC_SUCCESS; +} + +#endif \ No newline at end of file diff --git a/Source/Engine/Tools/TextureTool/TextureTool.cpp b/Source/Engine/Tools/TextureTool/TextureTool.cpp index c64134e46..c1257df55 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.cpp @@ -727,4 +727,30 @@ bool TextureTool::GetImageType(const StringView& path, ImageType& type) return false; } +bool TextureTool::Transform(TextureData& texture, const Function& transformation) +{ + auto sampler = TextureTool::GetSampler(texture.Format); + if (!sampler) + return true; + for (auto& slice : texture.Items) + { + for (int32 mipIndex = 0; mipIndex < slice.Mips.Count(); mipIndex++) + { + auto& mip = slice.Mips[mipIndex]; + auto mipWidth = Math::Max(texture.Width >> mipIndex, 1); + auto mipHeight = Math::Max(texture.Height >> mipIndex, 1); + for (int32 y = 0; y < mipHeight; y++) + { + for (int32 x = 0; x < mipWidth; x++) + { + Color color = TextureTool::SamplePoint(sampler, x, y, mip.Data.Get(), mip.RowPitch); + transformation(color); + TextureTool::Store(sampler, x, y, mip.Data.Get(), mip.RowPitch, color); + } + } + } + } + return false; +} + #endif diff --git a/Source/Engine/Tools/TextureTool/TextureTool.h b/Source/Engine/Tools/TextureTool/TextureTool.h index 351167b3c..061fc2466 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.h +++ b/Source/Engine/Tools/TextureTool/TextureTool.h @@ -256,6 +256,7 @@ private: }; static bool GetImageType(const StringView& path, ImageType& type); + static bool Transform(TextureData& texture, const Function& transformation); #if COMPILE_WITH_DIRECTXTEX static bool ExportTextureDirectXTex(ImageType type, const StringView& path, const TextureData& textureData); @@ -272,6 +273,9 @@ private: static bool ResizeStb(PixelFormat format, TextureMipData& dstMip, const TextureMipData& srcMip, int32 dstMipWidth, int32 dstMipHeight); static bool ResizeStb(TextureData& dst, const TextureData& src, int32 dstWidth, int32 dstHeight); #endif +#if COMPILE_WITH_ASTC + static bool ConvertAstc(TextureData& dst, const TextureData& src, const PixelFormat dstFormat); +#endif }; #endif diff --git a/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp b/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp index 9fd7f554b..00d1536f9 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp @@ -562,7 +562,7 @@ bool TextureTool::ConvertStb(TextureData& dst, const TextureData& src, const Pix } #if USE_EDITOR - if (PixelFormatExtensions::IsCompressed(dstFormat)) + if (PixelFormatExtensions::IsCompressedBC(dstFormat)) { int32 bytesPerBlock; switch (dstFormat) @@ -663,6 +663,15 @@ bool TextureTool::ConvertStb(TextureData& dst, const TextureData& src, const Pix } } } + else if (PixelFormatExtensions::IsCompressedASTC(dstFormat)) + { +#if COMPILE_WITH_ASTC + if (ConvertAstc(dst, src, dstFormat)) +#endif + { + return true; + } + } else #endif { diff --git a/Source/Platforms/Mac/Binaries/ThirdParty/ARM64/libastcenc.a b/Source/Platforms/Mac/Binaries/ThirdParty/ARM64/libastcenc.a new file mode 100644 index 000000000..7d5b9c24c --- /dev/null +++ b/Source/Platforms/Mac/Binaries/ThirdParty/ARM64/libastcenc.a @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:43c102505dd86c26284896d3cb63f15feeec2f48b554a8b7e2b6dea7c0742e75 +size 2025552 diff --git a/Source/Platforms/Mac/Binaries/ThirdParty/x64/libastcenc.a b/Source/Platforms/Mac/Binaries/ThirdParty/x64/libastcenc.a new file mode 100644 index 000000000..f492c80cf --- /dev/null +++ b/Source/Platforms/Mac/Binaries/ThirdParty/x64/libastcenc.a @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8ef0defa218e369da6d680e7753be1831b8317fbc8b8ad5c709155c5a632fe74 +size 2106072 diff --git a/Source/ThirdParty/astc/LICENSE.txt b/Source/ThirdParty/astc/LICENSE.txt new file mode 100644 index 000000000..b82735a31 --- /dev/null +++ b/Source/ThirdParty/astc/LICENSE.txt @@ -0,0 +1,175 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. diff --git a/Source/ThirdParty/astc/astc.Build.cs b/Source/ThirdParty/astc/astc.Build.cs new file mode 100644 index 000000000..e885c9150 --- /dev/null +++ b/Source/ThirdParty/astc/astc.Build.cs @@ -0,0 +1,39 @@ +// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. + +using System.IO; +using Flax.Build; +using Flax.Build.NativeCpp; + +/// +/// https://github.com/ARM-software/astc-encoder +/// +public class astc : ThirdPartyModule +{ + /// + public override void Init() + { + base.Init(); + + LicenseType = LicenseTypes.Apache2; + LicenseFilePath = "LICENSE.txt"; + + // Merge third-party modules into engine binary + BinaryModuleName = "FlaxEngine"; + } + + /// + public override void Setup(BuildOptions options) + { + base.Setup(options); + + options.PublicDefinitions.Add("COMPILE_WITH_ASTC"); + var depsRoot = options.DepsFolder; + switch (options.Platform.Target) + { + case TargetPlatform.Mac: + options.OutputFiles.Add(Path.Combine(depsRoot, "libastcenc.a")); + break; + default: throw new InvalidPlatformException(options.Platform.Target); + } + } +} diff --git a/Source/ThirdParty/astc/astcenc.h b/Source/ThirdParty/astc/astcenc.h new file mode 100644 index 000000000..c6c8c14a2 --- /dev/null +++ b/Source/ThirdParty/astc/astcenc.h @@ -0,0 +1,829 @@ +// SPDX-License-Identifier: Apache-2.0 +// ---------------------------------------------------------------------------- +// Copyright 2020-2023 Arm Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// ---------------------------------------------------------------------------- + +/** + * @brief The core astcenc codec library interface. + * + * This interface is the entry point to the core astcenc codec. It aims to be easy to use for + * non-experts, but also to allow experts to have fine control over the compressor heuristics if + * needed. The core codec only handles compression and decompression, transferring all inputs and + * outputs via memory buffers. To catch obvious input/output buffer sizing issues, which can cause + * security and stability problems, all transfer buffers are explicitly sized. + * + * While the aim is that we keep this interface mostly stable, it should be viewed as a mutable + * interface tied to a specific source version. We are not trying to maintain backwards + * compatibility across codec versions. + * + * The API state management is based around an explicit context object, which is the context for all + * allocated memory resources needed to compress and decompress a single image. A context can be + * used to sequentially compress multiple images using the same configuration, allowing setup + * overheads to be amortized over multiple images, which is particularly important when images are + * small. + * + * Multi-threading can be used two ways. + * + * * An application wishing to process multiple images in parallel can allocate multiple + * contexts and assign each context to a thread. + * * An application wishing to process a single image in using multiple threads can configure + * contexts for multi-threaded use, and invoke astcenc_compress/decompress() once per thread + * for faster processing. The caller is responsible for creating the worker threads, and + * synchronizing between images. + * + * Extended instruction set support + * ================================ + * + * This library supports use of extended instruction sets, such as SSE4.1 and AVX2. These are + * enabled at compile time when building the library. There is no runtime checking in the core + * library that the instruction sets used are actually available. Checking compatibility is the + * responsibility of the calling code. + * + * Threading + * ========= + * + * In pseudo-code, the usage for manual user threading looks like this: + * + * // Configure the compressor run + * astcenc_config my_config; + * astcenc_config_init(..., &my_config); + * + * // Power users can tweak settings here ... + * + * // Allocate working state given config and thread_count + * astcenc_context* my_context; + * astcenc_context_alloc(&my_config, thread_count, &my_context); + * + * // Compress each image using these config settings + * foreach image: + * // For each thread in the thread pool + * for i in range(0, thread_count): + * astcenc_compress_image(my_context, &my_input, my_output, i); + * + * astcenc_compress_reset(my_context); + * + * // Clean up + * astcenc_context_free(my_context); + * + * Images + * ====== + * + * The codec supports compressing single images, which can be either 2D images or volumetric 3D + * images. Calling code is responsible for any handling of aggregate types, such as mipmap chains, + * texture arrays, or sliced 3D textures. + * + * Images are passed in as an astcenc_image structure. Inputs can be either 8-bit unorm, 16-bit + * half-float, or 32-bit float, as indicated by the data_type field. + * + * Images can be any dimension; there is no requirement to be a multiple of the ASTC block size. + * + * Data is always passed in as 4 color components, and accessed as an array of 2D image slices. Data + * within an image slice is always tightly packed without padding. Addressing looks like this: + * + * data[z_coord][y_coord * x_dim * 4 + x_coord * 4 ] // Red + * data[z_coord][y_coord * x_dim * 4 + x_coord * 4 + 1] // Green + * data[z_coord][y_coord * x_dim * 4 + x_coord * 4 + 2] // Blue + * data[z_coord][y_coord * x_dim * 4 + x_coord * 4 + 3] // Alpha + * + * Common compressor usage + * ======================= + * + * One of the most important things for coding image quality is to align the input data component + * count with the ASTC color endpoint mode. This avoids wasting bits encoding components you don't + * actually need in the endpoint colors. + * + * | Input data | Encoding swizzle | Sampling swizzle | + * | ------------ | ---------------- | ---------------- | + * | 1 component | RRR1 | .[rgb] | + * | 2 components | RRRG | .[rgb]a | + * | 3 components | RGB1 | .rgb | + * | 4 components | RGBA | .rgba | + * + * The 1 and 2 component modes recommend sampling from "g" to recover the luminance value as this + * provide best compatibility with other texture formats where the green component may be stored at + * higher precision than the others, such as RGB565. For ASTC any of the RGB components can be used; + * the luminance endpoint component will be returned for all three. + * + * When using the normal map compression mode ASTC will store normals as a two component X+Y map. + * Input images must contain unit-length normalized and should be passed in using a two component + * swizzle. The astcenc command line tool defaults to an RRRG swizzle, but some developers prefer + * to use GGGR for compatability with BC5n which will work just as well. The Z component can be + * recovered programmatically in shader code, using knowledge that the vector is unit length and + * that Z must be positive for a tangent-space normal map. + * + * Decompress-only usage + * ===================== + * + * For some use cases it is useful to have a cut-down context and/or library which supports + * decompression but not compression. + * + * A context can be made decompress-only using the ASTCENC_FLG_DECOMPRESS_ONLY flag when the context + * is allocated. These contexts have lower dynamic memory footprint than a full context. + * + * The entire library can be made decompress-only by building the files with the define + * ASTCENC_DECOMPRESS_ONLY set. In this build the context will be smaller, and the library will + * exclude the functionality which is only needed for compression. This reduces the binary size by + * ~180KB. For these builds contexts must be created with the ASTCENC_FLG_DECOMPRESS_ONLY flag. + * + * Note that context structures returned by a library built as decompress-only are incompatible with + * a library built with compression included, and visa versa, as they have different sizes and + * memory layout. + * + * Self-decompress-only usage + * ========================== + * + * ASTC is a complex format with a large search space. The parts of this search space that are + * searched is determined by heuristics that are, in part, tied to the quality level used when + * creating the context. + * + * A normal context is capable of decompressing any ASTC texture, including those generated by other + * compressors with unknown heuristics. This is the most flexible implementation, but forces the + * data tables used by the codec to include entries that are not needed during compression. This + * can slow down context creation by a significant amount, especially for the faster compression + * modes where few data table entries are actually used. To optimize this use case the context can + * be created with the ASTCENC_FLG_SELF_DECOMPRESS_ONLY flag. This tells the compressor that it will + * only be asked to decompress images that it compressed itself, allowing the data tables to + * exclude entries that are not needed by the current compression configuration. This reduces the + * size of the context data tables in memory and improves context creation performance. Note that, + * as of the 3.6 release, this flag no longer affects compression performance. + * + * Using this flag while attempting to decompress an valid image which was created by another + * compressor, or even another astcenc compressor version or configuration, may result in blocks + * returning as solid magenta or NaN value error blocks. + */ + +#ifndef ASTCENC_INCLUDED +#define ASTCENC_INCLUDED + +#include +#include + +#if defined(ASTCENC_DYNAMIC_LIBRARY) + #if defined(_MSC_VER) + #define ASTCENC_PUBLIC extern "C" __declspec(dllexport) + #else + #define ASTCENC_PUBLIC extern "C" __attribute__ ((visibility ("default"))) + #endif +#else + #define ASTCENC_PUBLIC +#endif + +/* ============================================================================ + Data declarations +============================================================================ */ + +/** + * @brief An opaque structure; see astcenc_internal.h for definition. + */ +struct astcenc_context; + +/** + * @brief A codec API error code. + */ +enum astcenc_error { + /** @brief The call was successful. */ + ASTCENC_SUCCESS = 0, + /** @brief The call failed due to low memory, or undersized I/O buffers. */ + ASTCENC_ERR_OUT_OF_MEM, + /** @brief The call failed due to the build using fast math. */ + ASTCENC_ERR_BAD_CPU_FLOAT, + /** @brief The call failed due to an out-of-spec parameter. */ + ASTCENC_ERR_BAD_PARAM, + /** @brief The call failed due to an out-of-spec block size. */ + ASTCENC_ERR_BAD_BLOCK_SIZE, + /** @brief The call failed due to an out-of-spec color profile. */ + ASTCENC_ERR_BAD_PROFILE, + /** @brief The call failed due to an out-of-spec quality value. */ + ASTCENC_ERR_BAD_QUALITY, + /** @brief The call failed due to an out-of-spec component swizzle. */ + ASTCENC_ERR_BAD_SWIZZLE, + /** @brief The call failed due to an out-of-spec flag set. */ + ASTCENC_ERR_BAD_FLAGS, + /** @brief The call failed due to the context not supporting the operation. */ + ASTCENC_ERR_BAD_CONTEXT, + /** @brief The call failed due to unimplemented functionality. */ + ASTCENC_ERR_NOT_IMPLEMENTED, +#if defined(ASTCENC_DIAGNOSTICS) + /** @brief The call failed due to an issue with diagnostic tracing. */ + ASTCENC_ERR_DTRACE_FAILURE, +#endif +}; + +/** + * @brief A codec color profile. + */ +enum astcenc_profile { + /** @brief The LDR sRGB color profile. */ + ASTCENC_PRF_LDR_SRGB = 0, + /** @brief The LDR linear color profile. */ + ASTCENC_PRF_LDR, + /** @brief The HDR RGB with LDR alpha color profile. */ + ASTCENC_PRF_HDR_RGB_LDR_A, + /** @brief The HDR RGBA color profile. */ + ASTCENC_PRF_HDR +}; + +/** @brief The fastest, lowest quality, search preset. */ +static const float ASTCENC_PRE_FASTEST = 0.0f; + +/** @brief The fast search preset. */ +static const float ASTCENC_PRE_FAST = 10.0f; + +/** @brief The medium quality search preset. */ +static const float ASTCENC_PRE_MEDIUM = 60.0f; + +/** @brief The thorough quality search preset. */ +static const float ASTCENC_PRE_THOROUGH = 98.0f; + +/** @brief The thorough quality search preset. */ +static const float ASTCENC_PRE_VERYTHOROUGH = 99.0f; + +/** @brief The exhaustive, highest quality, search preset. */ +static const float ASTCENC_PRE_EXHAUSTIVE = 100.0f; + +/** + * @brief A codec component swizzle selector. + */ +enum astcenc_swz +{ + /** @brief Select the red component. */ + ASTCENC_SWZ_R = 0, + /** @brief Select the green component. */ + ASTCENC_SWZ_G = 1, + /** @brief Select the blue component. */ + ASTCENC_SWZ_B = 2, + /** @brief Select the alpha component. */ + ASTCENC_SWZ_A = 3, + /** @brief Use a constant zero component. */ + ASTCENC_SWZ_0 = 4, + /** @brief Use a constant one component. */ + ASTCENC_SWZ_1 = 5, + /** @brief Use a reconstructed normal vector Z component. */ + ASTCENC_SWZ_Z = 6 +}; + +/** + * @brief A texel component swizzle. + */ +struct astcenc_swizzle +{ + /** @brief The red component selector. */ + astcenc_swz r; + /** @brief The green component selector. */ + astcenc_swz g; + /** @brief The blue component selector. */ + astcenc_swz b; + /** @brief The alpha component selector. */ + astcenc_swz a; +}; + +/** + * @brief A texel component data format. + */ +enum astcenc_type +{ + /** @brief Unorm 8-bit data per component. */ + ASTCENC_TYPE_U8 = 0, + /** @brief 16-bit float per component. */ + ASTCENC_TYPE_F16 = 1, + /** @brief 32-bit float per component. */ + ASTCENC_TYPE_F32 = 2 +}; + +/** + * @brief Enable normal map compression. + * + * Input data will be treated a two component normal map, storing X and Y, and the codec will + * optimize for angular error rather than simple linear PSNR. In this mode the input swizzle should + * be e.g. rrrg (the default ordering for ASTC normals on the command line) or gggr (the ordering + * used by BC5n). + */ +static const unsigned int ASTCENC_FLG_MAP_NORMAL = 1 << 0; + +/** + * @brief Enable alpha weighting. + * + * The input alpha value is used for transparency, so errors in the RGB components are weighted by + * the transparency level. This allows the codec to more accurately encode the alpha value in areas + * where the color value is less significant. + */ +static const unsigned int ASTCENC_FLG_USE_ALPHA_WEIGHT = 1 << 2; + +/** + * @brief Enable perceptual error metrics. + * + * This mode enables perceptual compression mode, which will optimize for perceptual error rather + * than best PSNR. Only some input modes support perceptual error metrics. + */ +static const unsigned int ASTCENC_FLG_USE_PERCEPTUAL = 1 << 3; + +/** + * @brief Create a decompression-only context. + * + * This mode disables support for compression. This enables context allocation to skip some + * transient buffer allocation, resulting in lower memory usage. + */ +static const unsigned int ASTCENC_FLG_DECOMPRESS_ONLY = 1 << 4; + +/** + * @brief Create a self-decompression context. + * + * This mode configures the compressor so that it is only guaranteed to be able to decompress images + * that were actually created using the current context. This is the common case for compression use + * cases, and setting this flag enables additional optimizations, but does mean that the context + * cannot reliably decompress arbitrary ASTC images. + */ +static const unsigned int ASTCENC_FLG_SELF_DECOMPRESS_ONLY = 1 << 5; + +/** + * @brief Enable RGBM map compression. + * + * Input data will be treated as HDR data that has been stored in an LDR RGBM-encoded wrapper + * format. Data must be preprocessed by the user to be in LDR RGBM format before calling the + * compression function, this flag is only used to control the use of RGBM-specific heuristics and + * error metrics. + * + * IMPORTANT: The ASTC format is prone to bad failure modes with unconstrained RGBM data; very small + * M values can round to zero due to quantization and result in black or white pixels. It is highly + * recommended that the minimum value of M used in the encoding is kept above a lower threshold (try + * 16 or 32). Applying this threshold reduces the number of very dark colors that can be + * represented, but is still higher precision than 8-bit LDR. + * + * When this flag is set the value of @c rgbm_m_scale in the context must be set to the RGBM scale + * factor used during reconstruction. This defaults to 5 when in RGBM mode. + * + * It is recommended that the value of @c cw_a_weight is set to twice the value of the multiplier + * scale, ensuring that the M value is accurately encoded. This defaults to 10 when in RGBM mode, + * matching the default scale factor. + */ +static const unsigned int ASTCENC_FLG_MAP_RGBM = 1 << 6; + +/** + * @brief The bit mask of all valid flags. + */ +static const unsigned int ASTCENC_ALL_FLAGS = + ASTCENC_FLG_MAP_NORMAL | + ASTCENC_FLG_MAP_RGBM | + ASTCENC_FLG_USE_ALPHA_WEIGHT | + ASTCENC_FLG_USE_PERCEPTUAL | + ASTCENC_FLG_DECOMPRESS_ONLY | + ASTCENC_FLG_SELF_DECOMPRESS_ONLY; + +/** + * @brief The config structure. + * + * This structure will initially be populated by a call to astcenc_config_init, but power users may + * modify it before calling astcenc_context_alloc. See astcenccli_toplevel_help.cpp for full user + * documentation of the power-user settings. + * + * Note for any settings which are associated with a specific color component, the value in the + * config applies to the component that exists after any compression data swizzle is applied. + */ +struct astcenc_config +{ + /** @brief The color profile. */ + astcenc_profile profile; + + /** @brief The set of set flags. */ + unsigned int flags; + + /** @brief The ASTC block size X dimension. */ + unsigned int block_x; + + /** @brief The ASTC block size Y dimension. */ + unsigned int block_y; + + /** @brief The ASTC block size Z dimension. */ + unsigned int block_z; + + /** @brief The red component weight scale for error weighting (-cw). */ + float cw_r_weight; + + /** @brief The green component weight scale for error weighting (-cw). */ + float cw_g_weight; + + /** @brief The blue component weight scale for error weighting (-cw). */ + float cw_b_weight; + + /** @brief The alpha component weight scale for error weighting (-cw). */ + float cw_a_weight; + + /** + * @brief The radius for any alpha-weight scaling (-a). + * + * It is recommended that this is set to 1 when using FLG_USE_ALPHA_WEIGHT on a texture that + * will be sampled using linear texture filtering to minimize color bleed out of transparent + * texels that are adjacent to non-transparent texels. + */ + unsigned int a_scale_radius; + + /** @brief The RGBM scale factor for the shared multiplier (-rgbm). */ + float rgbm_m_scale; + + /** + * @brief The maximum number of partitions searched (-partitioncountlimit). + * + * Valid values are between 1 and 4. + */ + unsigned int tune_partition_count_limit; + + /** + * @brief The maximum number of partitions searched (-2partitionindexlimit). + * + * Valid values are between 1 and 1024. + */ + unsigned int tune_2partition_index_limit; + + /** + * @brief The maximum number of partitions searched (-3partitionindexlimit). + * + * Valid values are between 1 and 1024. + */ + unsigned int tune_3partition_index_limit; + + /** + * @brief The maximum number of partitions searched (-4partitionindexlimit). + * + * Valid values are between 1 and 1024. + */ + unsigned int tune_4partition_index_limit; + + /** + * @brief The maximum centile for block modes searched (-blockmodelimit). + * + * Valid values are between 1 and 100. + */ + unsigned int tune_block_mode_limit; + + /** + * @brief The maximum iterative refinements applied (-refinementlimit). + * + * Valid values are between 1 and N; there is no technical upper limit + * but little benefit is expected after N=4. + */ + unsigned int tune_refinement_limit; + + /** + * @brief The number of trial candidates per mode search (-candidatelimit). + * + * Valid values are between 1 and TUNE_MAX_TRIAL_CANDIDATES. + */ + unsigned int tune_candidate_limit; + + /** + * @brief The number of trial partitionings per search (-2partitioncandidatelimit). + * + * Valid values are between 1 and TUNE_MAX_PARTITIONING_CANDIDATES. + */ + unsigned int tune_2partitioning_candidate_limit; + + /** + * @brief The number of trial partitionings per search (-3partitioncandidatelimit). + * + * Valid values are between 1 and TUNE_MAX_PARTITIONING_CANDIDATES. + */ + unsigned int tune_3partitioning_candidate_limit; + + /** + * @brief The number of trial partitionings per search (-4partitioncandidatelimit). + * + * Valid values are between 1 and TUNE_MAX_PARTITIONING_CANDIDATES. + */ + unsigned int tune_4partitioning_candidate_limit; + + /** + * @brief The dB threshold for stopping block search (-dblimit). + * + * This option is ineffective for HDR textures. + */ + float tune_db_limit; + + /** + * @brief The amount of MSE overshoot needed to early-out trials. + * + * The first early-out is for 1 partition, 1 plane trials, where we try a minimal encode using + * the high probability block modes. This can short-cut compression for simple blocks. + * + * The second early-out is for refinement trials, where we can exit refinement once quality is + * reached. + */ + float tune_mse_overshoot; + + /** + * @brief The threshold for skipping 3.1/4.1 trials (-2partitionlimitfactor). + * + * This option is further scaled for normal maps, so it skips less often. + */ + float tune_2partition_early_out_limit_factor; + + /** + * @brief The threshold for skipping 4.1 trials (-3partitionlimitfactor). + * + * This option is further scaled for normal maps, so it skips less often. + */ + float tune_3partition_early_out_limit_factor; + + /** + * @brief The threshold for skipping two weight planes (-2planelimitcorrelation). + * + * This option is ineffective for normal maps. + */ + float tune_2plane_early_out_limit_correlation; + + /** + * @brief The config enable for the mode0 fast-path search. + * + * If this is set to TUNE_MIN_TEXELS_MODE0 or higher then the early-out fast mode0 + * search is enabled. This option is ineffective for 3D block sizes. + */ + float tune_search_mode0_enable; + +#if defined(ASTCENC_DIAGNOSTICS) + /** + * @brief The path to save the diagnostic trace data to. + * + * This option is not part of the public API, and requires special builds + * of the library. + */ + const char* trace_file_path; +#endif +}; + +/** + * @brief An uncompressed 2D or 3D image. + * + * 3D image are passed in as an array of 2D slices. Each slice has identical + * size and color format. + */ +struct astcenc_image +{ + /** @brief The X dimension of the image, in texels. */ + unsigned int dim_x; + + /** @brief The Y dimension of the image, in texels. */ + unsigned int dim_y; + + /** @brief The Z dimension of the image, in texels. */ + unsigned int dim_z; + + /** @brief The data type per component. */ + astcenc_type data_type; + + /** @brief The array of 2D slices, of length @c dim_z. */ + void** data; +}; + +/** + * @brief A block encoding metadata query result. + * + * If the block is an error block or a constant color block or an error block all fields other than + * the profile, block dimensions, and error/constant indicator will be zero. + */ +struct astcenc_block_info +{ + /** @brief The block encoding color profile. */ + astcenc_profile profile; + + /** @brief The number of texels in the X dimension. */ + unsigned int block_x; + + /** @brief The number of texels in the Y dimension. */ + unsigned int block_y; + + /** @brief The number of texel in the Z dimension. */ + unsigned int block_z; + + /** @brief The number of texels in the block. */ + unsigned int texel_count; + + /** @brief True if this block is an error block. */ + bool is_error_block; + + /** @brief True if this block is a constant color block. */ + bool is_constant_block; + + /** @brief True if this block is an HDR block. */ + bool is_hdr_block; + + /** @brief True if this block uses two weight planes. */ + bool is_dual_plane_block; + + /** @brief The number of partitions if not constant color. */ + unsigned int partition_count; + + /** @brief The partition index if 2 - 4 partitions used. */ + unsigned int partition_index; + + /** @brief The component index of the second plane if dual plane. */ + unsigned int dual_plane_component; + + /** @brief The color endpoint encoding mode for each partition. */ + unsigned int color_endpoint_modes[4]; + + /** @brief The number of color endpoint quantization levels. */ + unsigned int color_level_count; + + /** @brief The number of weight quantization levels. */ + unsigned int weight_level_count; + + /** @brief The number of weights in the X dimension. */ + unsigned int weight_x; + + /** @brief The number of weights in the Y dimension. */ + unsigned int weight_y; + + /** @brief The number of weights in the Z dimension. */ + unsigned int weight_z; + + /** @brief The unpacked color endpoints for each partition. */ + float color_endpoints[4][2][4]; + + /** @brief The per-texel interpolation weights for the block. */ + float weight_values_plane1[216]; + + /** @brief The per-texel interpolation weights for the block. */ + float weight_values_plane2[216]; + + /** @brief The per-texel partition assignments for the block. */ + uint8_t partition_assignment[216]; +}; + +/** + * Populate a codec config based on default settings. + * + * Power users can edit the returned config struct to fine tune before allocating the context. + * + * @param profile Color profile. + * @param block_x ASTC block size X dimension. + * @param block_y ASTC block size Y dimension. + * @param block_z ASTC block size Z dimension. + * @param quality Search quality preset / effort level. Either an + * @c ASTCENC_PRE_* value, or a effort level between 0 + * and 100. Performance is not linear between 0 and 100. + + * @param flags A valid set of @c ASTCENC_FLG_* flag bits. + * @param[out] config Output config struct to populate. + * + * @return @c ASTCENC_SUCCESS on success, or an error if the inputs are invalid + * either individually, or in combination. + */ +ASTCENC_PUBLIC astcenc_error astcenc_config_init( + astcenc_profile profile, + unsigned int block_x, + unsigned int block_y, + unsigned int block_z, + float quality, + unsigned int flags, + astcenc_config* config); + +/** + * @brief Allocate a new codec context based on a config. + * + * This function allocates all of the memory resources and threads needed by the codec. This can be + * slow, so it is recommended that contexts are reused to serially compress or decompress multiple + * images to amortize setup cost. + * + * Contexts can be allocated to support only decompression using the @c ASTCENC_FLG_DECOMPRESS_ONLY + * flag when creating the configuration. The compression functions will fail if invoked. For a + * decompress-only library build the @c ASTCENC_FLG_DECOMPRESS_ONLY flag must be set when creating + * any context. + * + * @param[in] config Codec config. + * @param thread_count Thread count to configure for. + * @param[out] context Location to store an opaque context pointer. + * + * @return @c ASTCENC_SUCCESS on success, or an error if context creation failed. + */ +ASTCENC_PUBLIC astcenc_error astcenc_context_alloc( + const astcenc_config* config, + unsigned int thread_count, + astcenc_context** context); + +/** + * @brief Compress an image. + * + * A single context can only compress or decompress a single image at a time. + * + * For a context configured for multi-threading, any set of the N threads can call this function. + * Work will be dynamically scheduled across the threads available. Each thread must have a unique + * @c thread_index. + * + * @param context Codec context. + * @param[in,out] image An input image, in 2D slices. + * @param swizzle Compression data swizzle, applied before compression. + * @param[out] data_out Pointer to output data array. + * @param data_len Length of the output data array. + * @param thread_index Thread index [0..N-1] of calling thread. + * + * @return @c ASTCENC_SUCCESS on success, or an error if compression failed. + */ +ASTCENC_PUBLIC astcenc_error astcenc_compress_image( + astcenc_context* context, + astcenc_image* image, + const astcenc_swizzle* swizzle, + uint8_t* data_out, + size_t data_len, + unsigned int thread_index); + +/** + * @brief Reset the codec state for a new compression. + * + * The caller is responsible for synchronizing threads in the worker thread pool. This function must + * only be called when all threads have exited the @c astcenc_compress_image() function for image N, + * but before any thread enters it for image N + 1. + * + * Calling this is not required (but won't hurt), if the context is created for single threaded use. + * + * @param context Codec context. + * + * @return @c ASTCENC_SUCCESS on success, or an error if reset failed. + */ +ASTCENC_PUBLIC astcenc_error astcenc_compress_reset( + astcenc_context* context); + +/** + * @brief Decompress an image. + * + * @param context Codec context. + * @param[in] data Pointer to compressed data. + * @param data_len Length of the compressed data, in bytes. + * @param[in,out] image_out Output image. + * @param swizzle Decompression data swizzle, applied after decompression. + * @param thread_index Thread index [0..N-1] of calling thread. + * + * @return @c ASTCENC_SUCCESS on success, or an error if decompression failed. + */ +ASTCENC_PUBLIC astcenc_error astcenc_decompress_image( + astcenc_context* context, + const uint8_t* data, + size_t data_len, + astcenc_image* image_out, + const astcenc_swizzle* swizzle, + unsigned int thread_index); + +/** + * @brief Reset the codec state for a new decompression. + * + * The caller is responsible for synchronizing threads in the worker thread pool. This function must + * only be called when all threads have exited the @c astcenc_decompress_image() function for image + * N, but before any thread enters it for image N + 1. + * + * Calling this is not required (but won't hurt), if the context is created for single threaded use. + * + * @param context Codec context. + * + * @return @c ASTCENC_SUCCESS on success, or an error if reset failed. + */ +ASTCENC_PUBLIC astcenc_error astcenc_decompress_reset( + astcenc_context* context); + +/** + * Free the compressor context. + * + * @param context The codec context. + */ +ASTCENC_PUBLIC void astcenc_context_free( + astcenc_context* context); + +/** + * @brief Provide a high level summary of a block's encoding. + * + * This feature is primarily useful for codec developers but may be useful for developers building + * advanced content packaging pipelines. + * + * @param context Codec context. + * @param data One block of compressed ASTC data. + * @param info The output info structure to populate. + * + * @return @c ASTCENC_SUCCESS if the block was decoded, or an error otherwise. Note that this + * function will return success even if the block itself was an error block encoding, as the + * decode was correctly handled. + */ +ASTCENC_PUBLIC astcenc_error astcenc_get_block_info( + astcenc_context* context, + const uint8_t data[16], + astcenc_block_info* info); + +/** + * @brief Get a printable string for specific status code. + * + * @param status The status value. + * + * @return A human readable nul-terminated string. + */ +ASTCENC_PUBLIC const char* astcenc_get_error_string( + astcenc_error status); + +#endif diff --git a/Source/Tools/Flax.Build/Deps/Dependencies/astc.cs b/Source/Tools/Flax.Build/Deps/Dependencies/astc.cs new file mode 100644 index 000000000..adbc54438 --- /dev/null +++ b/Source/Tools/Flax.Build/Deps/Dependencies/astc.cs @@ -0,0 +1,65 @@ +// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. + +using System.IO; +using Flax.Build; + +namespace Flax.Deps.Dependencies +{ + /// + /// ASTC texture format compression lib. + /// + /// + class astc : Dependency + { + /// + public override TargetPlatform[] Platforms + { + get + { + switch (BuildPlatform) + { + case TargetPlatform.Mac: + return new[] + { + TargetPlatform.Mac, + }; + default: return new TargetPlatform[0]; + } + } + } + + /// + public override void Build(BuildOptions options) + { + var root = options.IntermediateFolder; + var buildDir = Path.Combine(root, "build"); + + // Get the source + var commit = "aeece2f609db959d1c5e43e4f00bd177ea130575"; // 4.6.1 + CloneGitRepo(root, "https://github.com/ARM-software/astc-encoder.git", commit); + + foreach (var platform in options.Platforms) + { + switch (platform) + { + case TargetPlatform.Mac: + foreach (var architecture in new []{ TargetArchitecture.x64, TargetArchitecture.ARM64 }) + { + var isa = architecture == TargetArchitecture.ARM64 ? "-DASTCENC_ISA_NEON=ON" : "-DASTCENC_ISA_SSE2=ON"; + var lib = architecture == TargetArchitecture.ARM64 ? "libastcenc-neon-static.a" : "libastcenc-sse2-static.a"; + SetupDirectory(buildDir, true); + RunCmake(buildDir, platform, architecture, ".. -DCMAKE_BUILD_TYPE=Release -DASTCENC_UNIVERSAL_BUILD=OFF -DASTCENC_UNIVERSAL_BINARY=OFF " + isa); + Utilities.Run("cmake", "--build .", null, buildDir, Utilities.RunOptions.ConsoleLogOutput); + var depsFolder = GetThirdPartyFolder(options, platform, architecture); + Utilities.FileCopy(Path.Combine(buildDir, "Source", lib), Path.Combine(depsFolder, "libastcenc.a")); + } + break; + } + } + + // Copy header and license + Utilities.FileCopy(Path.Combine(root, "LICENSE.txt"), Path.Combine(options.ThirdPartyFolder, "astc/LICENSE.txt")); + Utilities.FileCopy(Path.Combine(root, "Source/astcenc.h"), Path.Combine(options.ThirdPartyFolder, "astc/astcenc.h")); + } + } +} From ed6220005f87dbdb57e355fcb1e65cff1c3ebbe4 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 15 Dec 2023 15:33:09 +0100 Subject: [PATCH 4/9] Fixes for astc compression usage --- .../Tools/TextureTool/TextureTool.astc.cpp | 27 ++++++++++++++----- .../Tools/TextureTool/TextureTool.stb.cpp | 2 +- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/Source/Engine/Tools/TextureTool/TextureTool.astc.cpp b/Source/Engine/Tools/TextureTool/TextureTool.astc.cpp index 21f4f0679..a175d679b 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.astc.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.astc.cpp @@ -39,6 +39,11 @@ bool TextureTool::ConvertAstc(TextureData& dst, const TextureData& src, const Pi return true; } astcenc_swizzle astcSwizzle = { ASTCENC_SWZ_R, ASTCENC_SWZ_G, ASTCENC_SWZ_B, ASTCENC_SWZ_A }; + if (!PixelFormatExtensions::HasAlpha(src.Format)) + { + // No alpha channel in use so fill with 1 + astcSwizzle.a = ASTCENC_SWZ_1; + } // Allocate working state given config and thread_count astcenc_context* astcContext; @@ -48,21 +53,30 @@ bool TextureTool::ConvertAstc(TextureData& dst, const TextureData& src, const Pi LOG(Warning, "Cannot compress image. ASTC failed with error: {}", String(astcenc_get_error_string(astcError))); return true; } - - // When converting from non-sRGB to sRGB we need to change the color-space manually (otherwise image is dark) TextureData const* textureData = &src; TextureData converted; + + // Encoder uses full 4-component RGBA input image so convert it if needed + if (PixelFormatExtensions::ComputeComponentsCount(src.Format) != 4) + { + if (textureData != &src) + converted = src; + const PixelFormat tempFormat = isHDR ? PixelFormat::R16G16B16A16_Float : (PixelFormatExtensions::IsSRGB(src.Format) ? PixelFormat::R8G8B8A8_UNorm_sRGB : PixelFormat::R8G8B8A8_UNorm); + if (!TextureTool::Convert(converted, *textureData, tempFormat)) + textureData = &converted; + } + + // When converting from non-sRGB to sRGB we need to change the color-space manually (otherwise image is dark) if (PixelFormatExtensions::IsSRGB(src.Format) != isSRGB) { - converted = src; + if (textureData != &src) + converted = src; Function transform = [](Color& c) { c = Color::LinearToSrgb(c); }; if (!TextureTool::Transform(converted, transform)) - { textureData = &converted; - } } // Compress all array slices @@ -77,12 +91,13 @@ bool TextureTool::ConvertAstc(TextureData& dst, const TextureData& src, const Pi for (int32 mipIndex = 0; mipIndex < mipLevels && astcError == ASTCENC_SUCCESS; mipIndex++) { const auto& srcMip = srcSlice.Mips[mipIndex]; - // TODO: validate if source mip data is row and pitch aligned (astcenc_image operates on whole pixel count withotu a slack) auto& dstMip = dstSlice.Mips[mipIndex]; auto mipWidth = Math::Max(textureData->Width >> mipIndex, 1); auto mipHeight = Math::Max(textureData->Height >> mipIndex, 1); auto blocksWidth = Math::Max(Math::DivideAndRoundUp(mipWidth, blockSize), 1); auto blocksHeight = Math::Max(Math::DivideAndRoundUp(mipHeight, blockSize), 1); + ASSERT(srcMip.RowPitch == mipWidth * PixelFormatExtensions::SizeInBytes(textureData->Format)); + ASSERT(srcMip.Lines == mipHeight); // Allocate memory dstMip.RowPitch = blocksWidth * bytesPerBlock; diff --git a/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp b/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp index 00d1536f9..ce10a7c61 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp @@ -666,7 +666,7 @@ bool TextureTool::ConvertStb(TextureData& dst, const TextureData& src, const Pix else if (PixelFormatExtensions::IsCompressedASTC(dstFormat)) { #if COMPILE_WITH_ASTC - if (ConvertAstc(dst, src, dstFormat)) + if (ConvertAstc(dst, *textureData, dstFormat)) #endif { return true; From 5958b2f4eafdf25cf65a3137e53aa42ef7c0bbb3 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 18 Dec 2023 09:55:17 +0100 Subject: [PATCH 5/9] Remove unused 'PixelFormatExtensions::ComputeScanlineCount' --- .../Engine/Graphics/PixelFormatExtensions.cpp | 33 ------------------- .../Engine/Graphics/PixelFormatExtensions.h | 8 ----- 2 files changed, 41 deletions(-) diff --git a/Source/Engine/Graphics/PixelFormatExtensions.cpp b/Source/Engine/Graphics/PixelFormatExtensions.cpp index 00aa76f5f..fafda87bf 100644 --- a/Source/Engine/Graphics/PixelFormatExtensions.cpp +++ b/Source/Engine/Graphics/PixelFormatExtensions.cpp @@ -537,39 +537,6 @@ bool PixelFormatExtensions::IsInteger(const PixelFormat format) } } -int32 PixelFormatExtensions::ComputeScanlineCount(const PixelFormat format, int32 height) -{ - switch (format) - { - case PixelFormat::BC1_Typeless: - case PixelFormat::BC1_UNorm: - case PixelFormat::BC1_UNorm_sRGB: - case PixelFormat::BC2_Typeless: - case PixelFormat::BC2_UNorm: - case PixelFormat::BC2_UNorm_sRGB: - case PixelFormat::BC3_Typeless: - case PixelFormat::BC3_UNorm: - case PixelFormat::BC3_UNorm_sRGB: - case PixelFormat::BC4_Typeless: - case PixelFormat::BC4_UNorm: - case PixelFormat::BC4_SNorm: - case PixelFormat::BC5_Typeless: - case PixelFormat::BC5_UNorm: - case PixelFormat::BC5_SNorm: - case PixelFormat::BC6H_Typeless: - case PixelFormat::BC6H_Uf16: - case PixelFormat::BC6H_Sf16: - case PixelFormat::BC7_Typeless: - case PixelFormat::BC7_UNorm: - case PixelFormat::BC7_UNorm_sRGB: - case PixelFormat::ASTC_4x4_UNorm: - case PixelFormat::ASTC_4x4_UNorm_sRGB: - return Math::Max(1, (height + 3) / 4); - default: - return height; - } -} - int32 PixelFormatExtensions::ComputeComponentsCount(const PixelFormat format) { switch (format) diff --git a/Source/Engine/Graphics/PixelFormatExtensions.h b/Source/Engine/Graphics/PixelFormatExtensions.h index 8739cbadc..7b793cdfd 100644 --- a/Source/Engine/Graphics/PixelFormatExtensions.h +++ b/Source/Engine/Graphics/PixelFormatExtensions.h @@ -165,14 +165,6 @@ public: /// True if given format contains integer data type (signed or unsigned), otherwise false. API_FUNCTION() static bool IsInteger(PixelFormat format); - /// - /// Computes the scanline count (number of scanlines). - /// - /// The . - /// The height. - /// The scanline count. - API_FUNCTION() static int32 ComputeScanlineCount(PixelFormat format, int32 height); - /// /// Computes the format components count (number of R, G, B, A channels). /// From c6c53baff2417b6dfc16de68664502b7840b90d7 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 18 Dec 2023 09:59:29 +0100 Subject: [PATCH 6/9] Improvements for astc format --- Source/Engine/Graphics/PixelFormatExtensions.cpp | 2 ++ Source/Engine/Graphics/RenderTools.cpp | 4 ++-- .../Engine/Tools/TextureTool/TextureTool.astc.cpp | 15 +++------------ 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/Source/Engine/Graphics/PixelFormatExtensions.cpp b/Source/Engine/Graphics/PixelFormatExtensions.cpp index fafda87bf..4431870ee 100644 --- a/Source/Engine/Graphics/PixelFormatExtensions.cpp +++ b/Source/Engine/Graphics/PixelFormatExtensions.cpp @@ -666,6 +666,8 @@ int32 PixelFormatExtensions::ComputeBlockSize(PixelFormat format) case PixelFormat::BC7_Typeless: case PixelFormat::BC7_UNorm: case PixelFormat::BC7_UNorm_sRGB: + case PixelFormat::ASTC_4x4_UNorm: + case PixelFormat::ASTC_4x4_UNorm_sRGB: return 4; default: return 1; diff --git a/Source/Engine/Graphics/RenderTools.cpp b/Source/Engine/Graphics/RenderTools.cpp index 7ffecd62c..5fc6c7d65 100644 --- a/Source/Engine/Graphics/RenderTools.cpp +++ b/Source/Engine/Graphics/RenderTools.cpp @@ -332,10 +332,10 @@ void RenderTools::ComputePitch(PixelFormat format, int32 width, int32 height, ui case PixelFormat::ASTC_4x4_UNorm: case PixelFormat::ASTC_4x4_UNorm_sRGB: { - const int32 blockSize = 4; // TODO: use PixelFormatExtensions to get block size for a format and handle different astc + const int32 blockSize = PixelFormatExtensions::ComputeBlockSize(format); uint32 nbw = Math::Max(1, Math::DivideAndRoundUp(width, blockSize)); uint32 nbh = Math::Max(1, Math::DivideAndRoundUp(height, blockSize)); - rowPitch = nbw * 16; + rowPitch = nbw * 16; // All ASTC blocks use 128 bits slicePitch = rowPitch * nbh; } break; diff --git a/Source/Engine/Tools/TextureTool/TextureTool.astc.cpp b/Source/Engine/Tools/TextureTool/TextureTool.astc.cpp index a175d679b..3dcd8bb72 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.astc.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.astc.cpp @@ -12,18 +12,9 @@ bool TextureTool::ConvertAstc(TextureData& dst, const TextureData& src, const PixelFormat dstFormat) { - int32 blockSize, bytesPerBlock = 16; - // TODO: use block size from PixelFormatExtensions - switch (dstFormat) - { - case PixelFormat::ASTC_4x4_UNorm: - case PixelFormat::ASTC_4x4_UNorm_sRGB: - blockSize = 4; - break; - default: - LOG(Warning, "Cannot compress image. Unsupported format {0}", static_cast(dstFormat)); - return true; - } + ASSERT(PixelFormatExtensions::IsCompressedASTC(dstFormat)); + const int32 blockSize = PixelFormatExtensions::ComputeBlockSize(dstFormat); + const int32 bytesPerBlock = 16; // All ASTC blocks use 128 bits // Configure the compressor run const bool isSRGB = PixelFormatExtensions::IsSRGB(dstFormat); From e4df1fc7566cf87ddffa5ea682edd90fd61913a9 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 18 Dec 2023 11:07:11 +0100 Subject: [PATCH 7/9] Add support for storing custom platform tools data in Game Cooker cache --- Flax.flaxproj | 2 +- Source/Editor/Cooker/PlatformTools.h | 52 +++++++++++++++++ Source/Editor/Cooker/Steps/CookAssetsStep.cpp | 56 ++++++++++++------- Source/Editor/Cooker/Steps/CookAssetsStep.h | 19 +++---- 4 files changed, 97 insertions(+), 32 deletions(-) diff --git a/Flax.flaxproj b/Flax.flaxproj index 81a63a1fc..8b643ed8d 100644 --- a/Flax.flaxproj +++ b/Flax.flaxproj @@ -4,7 +4,7 @@ "Major": 1, "Minor": 7, "Revision": 1, - "Build": 6406 + "Build": 6407 }, "Company": "Flax", "Copyright": "Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.", diff --git a/Source/Editor/Cooker/PlatformTools.h b/Source/Editor/Cooker/PlatformTools.h index 533dad805..d7953cfd9 100644 --- a/Source/Editor/Cooker/PlatformTools.h +++ b/Source/Editor/Cooker/PlatformTools.h @@ -8,6 +8,37 @@ class TextureBase; +/// +/// The game cooker cache interface. +/// +class FLAXENGINE_API IBuildCache +{ +public: + /// + /// Removes all cached entries for assets that contain a given asset type. This forces rebuild for them. + /// + virtual void InvalidateCachePerType(const StringView& typeName) = 0; + + /// + /// Removes all cached entries for assets that contain a given asset type. This forces rebuild for them. + /// + template + FORCE_INLINE void InvalidateCachePerType() + { + InvalidateCachePerType(T::TypeName); + } + + /// + /// Removes all cached entries for assets that contain a shader. This forces rebuild for them. + /// + void InvalidateCacheShaders(); + + /// + /// Removes all cached entries for assets that contain a texture. This forces rebuild for them. + /// + void InvalidateCacheTextures(); +}; + /// /// The platform support tools base interface. /// @@ -76,6 +107,27 @@ public: virtual bool IsNativeCodeFile(CookingData& data, const String& file); public: + /// + /// Loads the build cache. Allows to invalidate any cached asset types based on the build settings for incremental builds (eg. invalidate textures/shaders). + /// + /// The cooking data. + /// The build cache interface. + /// The loaded cache data. Can be empty when starting a fresh build. + virtual void LoadCache(CookingData& data, IBuildCache* cache, const Span& bytes) + { + } + + /// + /// Saves the build cache. Allows to store any build settings to be used for cache invalidation on incremental builds. + /// + /// The cooking data. + /// The build cache interface. + /// Data to cache, will be restored during next incremental build. + virtual Array SaveCache(CookingData& data, IBuildCache* cache) + { + return Array(); + } + /// /// Called when game building starts. /// diff --git a/Source/Editor/Cooker/Steps/CookAssetsStep.cpp b/Source/Editor/Cooker/Steps/CookAssetsStep.cpp index 8fd87bcfd..366a4faef 100644 --- a/Source/Editor/Cooker/Steps/CookAssetsStep.cpp +++ b/Source/Editor/Cooker/Steps/CookAssetsStep.cpp @@ -35,6 +35,7 @@ #include "Engine/Engine/Base/GameBase.h" #include "Engine/Engine/Globals.h" #include "Engine/Tools/TextureTool/TextureTool.h" +#include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Scripting/Enums.h" #if PLATFORM_TOOLS_WINDOWS #include "Engine/Platform/Windows/WindowsPlatformSettings.h" @@ -49,6 +50,20 @@ Dictionary CookAssetsStep::AssetProcessors; +void IBuildCache::InvalidateCacheShaders() +{ + InvalidateCachePerType(); + InvalidateCachePerType(); + InvalidateCachePerType(); +} + +void IBuildCache::InvalidateCacheTextures() +{ + InvalidateCachePerType(); + InvalidateCachePerType(); + InvalidateCachePerType(); +} + bool CookAssetsStep::CacheEntry::IsValid(bool withDependencies) { AssetInfo assetInfo; @@ -113,15 +128,13 @@ void CookAssetsStep::CacheData::InvalidateCachePerType(const StringView& typeNam void CookAssetsStep::CacheData::Load(CookingData& data) { + PROFILE_CPU(); HeaderFilePath = data.CacheDirectory / String::Format(TEXT("CookedHeader_{0}.bin"), FLAXENGINE_VERSION_BUILD); CacheFolder = data.CacheDirectory / TEXT("Cooked"); Entries.Clear(); if (!FileSystem::DirectoryExists(CacheFolder)) - { FileSystem::CreateDirectory(CacheFolder); - } - if (!FileSystem::FileExists(HeaderFilePath)) { LOG(Warning, "Missing incremental build cooking assets cache."); @@ -143,9 +156,7 @@ void CookAssetsStep::CacheData::Load(CookingData& data) return; LOG(Info, "Loading incremental build cooking cache (entries count: {0})", entriesCount); - file->ReadBytes(&Settings, sizeof(Settings)); - Entries.EnsureCapacity(Math::RoundUpToPowerOf2(static_cast(entriesCount * 3.0f))); Array> fileDependencies; @@ -179,6 +190,9 @@ void CookAssetsStep::CacheData::Load(CookingData& data) e.FileDependencies = fileDependencies; } + Array platformCache; + file->Read(platformCache); + int32 checkChar; file->ReadInt32(&checkChar); if (checkChar != 13) @@ -187,6 +201,9 @@ void CookAssetsStep::CacheData::Load(CookingData& data) Entries.Clear(); } + // Per-platform custom data loading (eg. to invalidate textures/shaders options) + data.Tools->LoadCache(data, this, ToSpan(platformCache)); + const auto buildSettings = BuildSettings::Get(); const auto gameSettings = GameSettings::Get(); @@ -200,12 +217,12 @@ void CookAssetsStep::CacheData::Load(CookingData& data) if (MATERIAL_GRAPH_VERSION != Settings.Global.MaterialGraphVersion) { LOG(Info, "{0} option has been modified.", TEXT("MaterialGraphVersion")); - InvalidateCachePerType(Material::TypeName); + InvalidateCachePerType(); } if (PARTICLE_GPU_GRAPH_VERSION != Settings.Global.ParticleGraphVersion) { LOG(Info, "{0} option has been modified.", TEXT("ParticleGraphVersion")); - InvalidateCachePerType(ParticleEmitter::TypeName); + InvalidateCachePerType(); } if (buildSettings->ShadersNoOptimize != Settings.Global.ShadersNoOptimize) { @@ -262,24 +279,24 @@ void CookAssetsStep::CacheData::Load(CookingData& data) #endif if (invalidateShaders) { - InvalidateCachePerType(Shader::TypeName); - InvalidateCachePerType(Material::TypeName); - InvalidateCachePerType(ParticleEmitter::TypeName); + InvalidateCachePerType(); + InvalidateCachePerType(); + InvalidateCachePerType(); } // Invalidate textures if streaming settings gets modified if (Settings.Global.StreamingSettingsAssetId != gameSettings->Streaming || (Entries.ContainsKey(gameSettings->Streaming) && !Entries[gameSettings->Streaming].IsValid())) { - InvalidateCachePerType(Texture::TypeName); - InvalidateCachePerType(CubeTexture::TypeName); - InvalidateCachePerType(SpriteAtlas::TypeName); + InvalidateCachePerType(); + InvalidateCachePerType(); + InvalidateCachePerType(); } } -void CookAssetsStep::CacheData::Save() +void CookAssetsStep::CacheData::Save(CookingData& data) { + PROFILE_CPU(); LOG(Info, "Saving incremental build cooking cache (entries count: {0})", Entries.Count()); - auto file = FileWriteStream::Open(HeaderFilePath); if (file == nullptr) return; @@ -302,6 +319,7 @@ void CookAssetsStep::CacheData::Save() file->Write(f.Second); } } + file->Write(data.Tools->SaveCache(data, this)); file->WriteInt32(13); } @@ -961,6 +979,7 @@ public: const int32 count = addedEntries.Count(); if (count == 0) return false; + PROFILE_CPU(); // Get assets init data and load all chunks Array assetsData; @@ -1143,7 +1162,7 @@ bool CookAssetsStep::Perform(CookingData& data) // Cook asset if (Process(data, cache, assetRef.Get())) { - cache.Save(); + cache.Save(data); return true; } data.Stats.CookedAssets++; @@ -1151,12 +1170,12 @@ bool CookAssetsStep::Perform(CookingData& data) // Auto save build cache after every few cooked assets (reduces next build time if cooking fails later) if (data.Stats.CookedAssets % 50 == 0) { - cache.Save(); + cache.Save(data); } } // Save build cache header - cache.Save(); + cache.Save(data); // Create build game header { @@ -1173,7 +1192,6 @@ bool CookAssetsStep::Perform(CookingData& data) } stream->WriteInt32(('x' + 'D') * 131); // think about it as '131 times xD' - stream->WriteInt32(FLAXENGINE_VERSION_BUILD); Array bytes; diff --git a/Source/Editor/Cooker/Steps/CookAssetsStep.h b/Source/Editor/Cooker/Steps/CookAssetsStep.h index c552e532c..ae6bf7a6f 100644 --- a/Source/Editor/Cooker/Steps/CookAssetsStep.h +++ b/Source/Editor/Cooker/Steps/CookAssetsStep.h @@ -3,6 +3,7 @@ #pragma once #include "Editor/Cooker/GameCooker.h" +#include "Editor/Cooker/PlatformTools.h" #include "Engine/Core/Types/Pair.h" #include "Engine/Core/Types/DateTime.h" #include "Engine/Core/Collections/Dictionary.h" @@ -56,7 +57,7 @@ public: /// /// Assets cooking cache data (incremental building feature). /// - struct FLAXENGINE_API CacheData + struct FLAXENGINE_API CacheData : public IBuildCache { /// /// The cache header file path. @@ -136,16 +137,6 @@ public: /// The added entry reference. CacheEntry& CreateEntry(const Asset* asset, String& cachedFilePath); - /// - /// Removes all cached entries for assets that contain a shader. This forces rebuild for them. - /// - void InvalidateShaders(); - - /// - /// Removes all cached entries for assets that contain a texture. This forces rebuild for them. - /// - void InvalidateCachePerType(const StringView& typeName); - /// /// Loads the cache for the given cooking data. /// @@ -155,7 +146,11 @@ public: /// /// Saves this cache (header file). /// - void Save(); + /// The data. + void Save(CookingData& data); + + using IBuildCache::InvalidateCachePerType; + void InvalidateCachePerType(const StringView& typeName) override; }; struct FLAXENGINE_API AssetCookData From 53a2ebbd17e21d1ab44beebacfd2dfe84b19ad5f Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 20 Dec 2023 15:12:12 +0100 Subject: [PATCH 8/9] Add more ASTC texture formats with larger block sizes --- .../Engine/Graphics/PixelFormatExtensions.cpp | 76 ++++++++++++++----- Source/Engine/Graphics/RenderTools.cpp | 6 ++ .../Engine/Graphics/Textures/GPUTexture.cpp | 9 ++- .../Vulkan/RenderToolsVulkan.cpp | 8 +- .../Tools/TextureTool/TextureTool.astc.cpp | 6 +- 5 files changed, 80 insertions(+), 25 deletions(-) diff --git a/Source/Engine/Graphics/PixelFormatExtensions.cpp b/Source/Engine/Graphics/PixelFormatExtensions.cpp index 4431870ee..2f3aa3931 100644 --- a/Source/Engine/Graphics/PixelFormatExtensions.cpp +++ b/Source/Engine/Graphics/PixelFormatExtensions.cpp @@ -29,6 +29,21 @@ void PixelFormatExtensions::Init() PixelFormat::R8_Typeless, PixelFormat::R8_UInt, PixelFormat::R8_UNorm, + PixelFormat::BC2_Typeless, + PixelFormat::BC2_UNorm, + PixelFormat::BC2_UNorm_sRGB, + PixelFormat::BC3_Typeless, + PixelFormat::BC3_UNorm, + PixelFormat::BC3_UNorm_sRGB, + PixelFormat::BC5_SNorm, + PixelFormat::BC5_Typeless, + PixelFormat::BC5_UNorm, + PixelFormat::BC6H_Sf16, + PixelFormat::BC6H_Typeless, + PixelFormat::BC6H_Uf16, + PixelFormat::BC7_Typeless, + PixelFormat::BC7_UNorm, + PixelFormat::BC7_UNorm_sRGB, PixelFormat::ASTC_4x4_UNorm, PixelFormat::ASTC_4x4_UNorm_sRGB, }; @@ -134,25 +149,6 @@ void PixelFormatExtensions::Init() PixelFormat::BC4_UNorm, }; InitFormat(formats8, 4); - - PixelFormat formats9[] = { - PixelFormat::BC2_Typeless, - PixelFormat::BC2_UNorm, - PixelFormat::BC2_UNorm_sRGB, - PixelFormat::BC3_Typeless, - PixelFormat::BC3_UNorm, - PixelFormat::BC3_UNorm_sRGB, - PixelFormat::BC5_SNorm, - PixelFormat::BC5_Typeless, - PixelFormat::BC5_UNorm, - PixelFormat::BC6H_Sf16, - PixelFormat::BC6H_Typeless, - PixelFormat::BC6H_Uf16, - PixelFormat::BC7_Typeless, - PixelFormat::BC7_UNorm, - PixelFormat::BC7_UNorm_sRGB, - }; - InitFormat(formats9, 8); } int32 PixelFormatExtensions::SizeInBits(PixelFormat format) @@ -315,6 +311,12 @@ bool PixelFormatExtensions::IsCompressed(const PixelFormat format) case PixelFormat::BC7_UNorm_sRGB: case PixelFormat::ASTC_4x4_UNorm: case PixelFormat::ASTC_4x4_UNorm_sRGB: + case PixelFormat::ASTC_6x6_UNorm: + case PixelFormat::ASTC_6x6_UNorm_sRGB: + case PixelFormat::ASTC_8x8_UNorm: + case PixelFormat::ASTC_8x8_UNorm_sRGB: + case PixelFormat::ASTC_10x10_UNorm: + case PixelFormat::ASTC_10x10_UNorm_sRGB: return true; default: return false; @@ -358,6 +360,12 @@ bool PixelFormatExtensions::IsCompressedASTC(PixelFormat format) { case PixelFormat::ASTC_4x4_UNorm: case PixelFormat::ASTC_4x4_UNorm_sRGB: + case PixelFormat::ASTC_6x6_UNorm: + case PixelFormat::ASTC_6x6_UNorm_sRGB: + case PixelFormat::ASTC_8x8_UNorm: + case PixelFormat::ASTC_8x8_UNorm_sRGB: + case PixelFormat::ASTC_10x10_UNorm: + case PixelFormat::ASTC_10x10_UNorm_sRGB: return true; default: return false; @@ -391,6 +399,9 @@ bool PixelFormatExtensions::IsSRGB(const PixelFormat format) case PixelFormat::B8G8R8X8_UNorm_sRGB: case PixelFormat::BC7_UNorm_sRGB: case PixelFormat::ASTC_4x4_UNorm_sRGB: + case PixelFormat::ASTC_6x6_UNorm_sRGB: + case PixelFormat::ASTC_8x8_UNorm_sRGB: + case PixelFormat::ASTC_10x10_UNorm_sRGB: return true; default: return false; @@ -580,6 +591,12 @@ int32 PixelFormatExtensions::ComputeComponentsCount(const PixelFormat format) case PixelFormat::B8G8R8X8_UNorm_sRGB: case PixelFormat::ASTC_4x4_UNorm: case PixelFormat::ASTC_4x4_UNorm_sRGB: + case PixelFormat::ASTC_6x6_UNorm: + case PixelFormat::ASTC_6x6_UNorm_sRGB: + case PixelFormat::ASTC_8x8_UNorm: + case PixelFormat::ASTC_8x8_UNorm_sRGB: + case PixelFormat::ASTC_10x10_UNorm: + case PixelFormat::ASTC_10x10_UNorm_sRGB: return 4; case PixelFormat::R32G32B32_Typeless: case PixelFormat::R32G32B32_Float: @@ -669,6 +686,15 @@ int32 PixelFormatExtensions::ComputeBlockSize(PixelFormat format) case PixelFormat::ASTC_4x4_UNorm: case PixelFormat::ASTC_4x4_UNorm_sRGB: return 4; + case PixelFormat::ASTC_6x6_UNorm: + case PixelFormat::ASTC_6x6_UNorm_sRGB: + return 6; + case PixelFormat::ASTC_8x8_UNorm: + case PixelFormat::ASTC_8x8_UNorm_sRGB: + return 8; + case PixelFormat::ASTC_10x10_UNorm: + case PixelFormat::ASTC_10x10_UNorm_sRGB: + return 10; default: return 1; } @@ -694,6 +720,12 @@ PixelFormat PixelFormatExtensions::TosRGB(const PixelFormat format) return PixelFormat::BC7_UNorm_sRGB; case PixelFormat::ASTC_4x4_UNorm: return PixelFormat::ASTC_4x4_UNorm_sRGB; + case PixelFormat::ASTC_6x6_UNorm: + return PixelFormat::ASTC_6x6_UNorm_sRGB; + case PixelFormat::ASTC_8x8_UNorm: + return PixelFormat::ASTC_8x8_UNorm_sRGB; + case PixelFormat::ASTC_10x10_UNorm: + return PixelFormat::ASTC_10x10_UNorm_sRGB; default: return format; } @@ -719,6 +751,12 @@ PixelFormat PixelFormatExtensions::ToNonsRGB(const PixelFormat format) return PixelFormat::BC7_UNorm; case PixelFormat::ASTC_4x4_UNorm_sRGB: return PixelFormat::ASTC_4x4_UNorm; + case PixelFormat::ASTC_6x6_UNorm_sRGB: + return PixelFormat::ASTC_6x6_UNorm; + case PixelFormat::ASTC_8x8_UNorm_sRGB: + return PixelFormat::ASTC_8x8_UNorm; + case PixelFormat::ASTC_10x10_UNorm_sRGB: + return PixelFormat::ASTC_10x10_UNorm; default: return format; } diff --git a/Source/Engine/Graphics/RenderTools.cpp b/Source/Engine/Graphics/RenderTools.cpp index 5fc6c7d65..66e17896d 100644 --- a/Source/Engine/Graphics/RenderTools.cpp +++ b/Source/Engine/Graphics/RenderTools.cpp @@ -331,6 +331,12 @@ void RenderTools::ComputePitch(PixelFormat format, int32 width, int32 height, ui break; case PixelFormat::ASTC_4x4_UNorm: case PixelFormat::ASTC_4x4_UNorm_sRGB: + case PixelFormat::ASTC_6x6_UNorm: + case PixelFormat::ASTC_6x6_UNorm_sRGB: + case PixelFormat::ASTC_8x8_UNorm: + case PixelFormat::ASTC_8x8_UNorm_sRGB: + case PixelFormat::ASTC_10x10_UNorm: + case PixelFormat::ASTC_10x10_UNorm_sRGB: { const int32 blockSize = PixelFormatExtensions::ComputeBlockSize(format); uint32 nbw = Math::Max(1, Math::DivideAndRoundUp(width, blockSize)); diff --git a/Source/Engine/Graphics/Textures/GPUTexture.cpp b/Source/Engine/Graphics/Textures/GPUTexture.cpp index 403f545ba..4d43e20ec 100644 --- a/Source/Engine/Graphics/Textures/GPUTexture.cpp +++ b/Source/Engine/Graphics/Textures/GPUTexture.cpp @@ -337,14 +337,12 @@ int32 GPUTexture::ComputeBufferOffset(int32 subresource, int32 rowAlign, int32 s int32 GPUTexture::ComputeBufferTotalSize(int32 rowAlign, int32 sliceAlign) const { int32 result = 0; - for (int32 mipLevel = 0; mipLevel < MipLevels(); mipLevel++) { const int32 slicePitch = ComputeSlicePitch(mipLevel, rowAlign); const int32 depth = CalculateMipSize(Depth(), mipLevel); result += Math::AlignUp(slicePitch * depth, sliceAlign); } - return result * ArraySize(); } @@ -355,8 +353,11 @@ int32 GPUTexture::ComputeSlicePitch(int32 mipLevel, int32 rowAlign) const int32 GPUTexture::ComputeRowPitch(int32 mipLevel, int32 rowAlign) const { - const int32 formatSize = PixelFormatExtensions::SizeInBytes(Format()); - return Math::AlignUp(CalculateMipSize(Width(), mipLevel) * formatSize, rowAlign); + int32 mipWidth = CalculateMipSize(Width(), mipLevel); + int32 mipHeight = CalculateMipSize(Height(), mipLevel); + uint32 rowPitch, slicePitch; + RenderTools::ComputePitch(Format(), mipWidth, mipHeight, rowPitch, slicePitch); + return Math::AlignUp(rowPitch, rowAlign); } bool GPUTexture::Init(const GPUTextureDescription& desc) diff --git a/Source/Engine/GraphicsDevice/Vulkan/RenderToolsVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/RenderToolsVulkan.cpp index 3a5a91e5e..f9c9237f6 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/RenderToolsVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/RenderToolsVulkan.cpp @@ -6,7 +6,7 @@ #include "Engine/Core/Types/StringBuilder.h" #include "Engine/Core/Log.h" -VkFormat RenderToolsVulkan::PixelFormatToVkFormat[102] = +VkFormat RenderToolsVulkan::PixelFormatToVkFormat[108] = { VK_FORMAT_UNDEFINED, VK_FORMAT_R32G32B32A32_SFLOAT, @@ -110,6 +110,12 @@ VkFormat RenderToolsVulkan::PixelFormatToVkFormat[102] = VK_FORMAT_BC7_SRGB_BLOCK, VK_FORMAT_ASTC_4x4_UNORM_BLOCK, VK_FORMAT_ASTC_4x4_SRGB_BLOCK, + VK_FORMAT_ASTC_6x6_UNORM_BLOCK, + VK_FORMAT_ASTC_6x6_SRGB_BLOCK, + VK_FORMAT_ASTC_8x8_UNORM_BLOCK, + VK_FORMAT_ASTC_8x8_SRGB_BLOCK, + VK_FORMAT_ASTC_10x10_UNORM_BLOCK, + VK_FORMAT_ASTC_10x10_SRGB_BLOCK, }; VkBlendFactor RenderToolsVulkan::BlendToVkBlendFactor[20] = diff --git a/Source/Engine/Tools/TextureTool/TextureTool.astc.cpp b/Source/Engine/Tools/TextureTool/TextureTool.astc.cpp index 3dcd8bb72..3eceb837e 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.astc.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.astc.cpp @@ -8,6 +8,7 @@ #include "Engine/Core/Math/Color32.h" #include "Engine/Graphics/Textures/TextureData.h" #include "Engine/Graphics/PixelFormatExtensions.h" +#include "Engine/Graphics/RenderTools.h" #include bool TextureTool::ConvertAstc(TextureData& dst, const TextureData& src, const PixelFormat dstFormat) @@ -87,7 +88,10 @@ bool TextureTool::ConvertAstc(TextureData& dst, const TextureData& src, const Pi auto mipHeight = Math::Max(textureData->Height >> mipIndex, 1); auto blocksWidth = Math::Max(Math::DivideAndRoundUp(mipWidth, blockSize), 1); auto blocksHeight = Math::Max(Math::DivideAndRoundUp(mipHeight, blockSize), 1); - ASSERT(srcMip.RowPitch == mipWidth * PixelFormatExtensions::SizeInBytes(textureData->Format)); + uint32 mipRowPitch, mipSlicePitch; + RenderTools::ComputePitch(textureData->Format, mipWidth, mipHeight, mipRowPitch, mipSlicePitch); + ASSERT(srcMip.RowPitch == mipRowPitch); + ASSERT(srcMip.DepthPitch == mipSlicePitch); ASSERT(srcMip.Lines == mipHeight); // Allocate memory From b2f9b9e14d7cab024b7d78b1fac60ef37e39325e Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 20 Dec 2023 15:12:48 +0100 Subject: [PATCH 9/9] Add texture quality option for iOS --- .../Cooker/Platform/iOS/iOSPlatformTools.cpp | 119 +++++++++++------- .../Cooker/Platform/iOS/iOSPlatformTools.h | 2 + Source/Engine/Graphics/PixelFormat.h | 32 ++++- .../Engine/Platform/iOS/iOSPlatformSettings.h | 22 ++++ 4 files changed, 131 insertions(+), 44 deletions(-) diff --git a/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.cpp b/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.cpp index 85a7f99fa..4d50401bd 100644 --- a/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.cpp +++ b/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.cpp @@ -24,6 +24,11 @@ IMPLEMENT_SETTINGS_GETTER(iOSPlatformSettings, iOSPlatform); namespace { + struct iOSPlatformCache + { + iOSPlatformSettings::TextureQuality TexturesQuality; + }; + String GetAppName() { const auto gameSettings = GameSettings::Get(); @@ -60,6 +65,22 @@ namespace result = result.TrimTrailing(); return result; } + + PixelFormat GetQualityTextureFormat(bool sRGB) + { + const auto platformSettings = iOSPlatformSettings::Get(); + switch (platformSettings->TexturesQuality) + { + case iOSPlatformSettings::TextureQuality::ASTC_High: + return sRGB ? PixelFormat::ASTC_4x4_UNorm_sRGB : PixelFormat::ASTC_4x4_UNorm; + case iOSPlatformSettings::TextureQuality::ASTC_Medium: + return sRGB ? PixelFormat::ASTC_6x6_UNorm_sRGB : PixelFormat::ASTC_6x6_UNorm; + case iOSPlatformSettings::TextureQuality::ASTC_Low: + return sRGB ? PixelFormat::ASTC_8x8_UNorm_sRGB : PixelFormat::ASTC_8x8_UNorm; + default: + CRASH; + } + } } const Char* iOSPlatformTools::GetDisplayName() const @@ -89,51 +110,37 @@ DotNetAOTModes iOSPlatformTools::UseAOT() const PixelFormat iOSPlatformTools::GetTextureFormat(CookingData& data, TextureBase* texture, PixelFormat format) { - // TODO: add ETC compression support for iOS - // TODO: add ASTC compression support for iOS - - if (PixelFormatExtensions::IsCompressedBC(format)) + switch (format) { - switch (format) - { - case PixelFormat::BC1_Typeless: - case PixelFormat::BC2_Typeless: - case PixelFormat::BC3_Typeless: - return PixelFormat::R8G8B8A8_Typeless; - case PixelFormat::BC1_UNorm: - case PixelFormat::BC2_UNorm: - case PixelFormat::BC3_UNorm: - return PixelFormat::R8G8B8A8_UNorm; - case PixelFormat::BC1_UNorm_sRGB: - case PixelFormat::BC2_UNorm_sRGB: - case PixelFormat::BC3_UNorm_sRGB: - return PixelFormat::R8G8B8A8_UNorm_sRGB; - case PixelFormat::BC4_Typeless: - return PixelFormat::R8_Typeless; - case PixelFormat::BC4_UNorm: - return PixelFormat::R8_UNorm; - case PixelFormat::BC4_SNorm: - return PixelFormat::R8_SNorm; - case PixelFormat::BC5_Typeless: - return PixelFormat::R16G16_Typeless; - case PixelFormat::BC5_UNorm: - return PixelFormat::R16G16_UNorm; - case PixelFormat::BC5_SNorm: - return PixelFormat::R16G16_SNorm; - case PixelFormat::BC7_Typeless: - case PixelFormat::BC6H_Typeless: - return PixelFormat::R16G16B16A16_Typeless; - case PixelFormat::BC7_UNorm: - case PixelFormat::BC6H_Uf16: - case PixelFormat::BC6H_Sf16: - return PixelFormat::R16G16B16A16_Float; - case PixelFormat::BC7_UNorm_sRGB: - return PixelFormat::R16G16B16A16_UNorm; - default: - return format; - } + case PixelFormat::BC1_Typeless: + case PixelFormat::BC2_Typeless: + case PixelFormat::BC3_Typeless: + case PixelFormat::BC4_Typeless: + case PixelFormat::BC5_Typeless: + case PixelFormat::BC1_UNorm: + case PixelFormat::BC2_UNorm: + case PixelFormat::BC3_UNorm: + case PixelFormat::BC4_UNorm: + case PixelFormat::BC5_UNorm: + return GetQualityTextureFormat(false); + case PixelFormat::BC1_UNorm_sRGB: + case PixelFormat::BC2_UNorm_sRGB: + case PixelFormat::BC3_UNorm_sRGB: + case PixelFormat::BC7_UNorm_sRGB: + return GetQualityTextureFormat(true); + case PixelFormat::BC4_SNorm: + return PixelFormat::R8_SNorm; + case PixelFormat::BC5_SNorm: + return PixelFormat::R16G16_SNorm; + case PixelFormat::BC6H_Typeless: + case PixelFormat::BC6H_Uf16: + case PixelFormat::BC6H_Sf16: + case PixelFormat::BC7_Typeless: + case PixelFormat::BC7_UNorm: + return PixelFormat::R16G16B16A16_Typeless; // TODO: ASTC HDR + default: + return format; } - return format; } @@ -143,6 +150,32 @@ bool iOSPlatformTools::IsNativeCodeFile(CookingData& data, const String& file) return extension.IsEmpty() || extension == TEXT("dylib"); } +void iOSPlatformTools::LoadCache(CookingData& data, IBuildCache* cache, const Span& bytes) +{ + const auto platformSettings = iOSPlatformSettings::Get(); + bool invalidTextures = true; + if (bytes.Length() == sizeof(iOSPlatformCache)) + { + auto* platformCache = (iOSPlatformCache*)bytes.Get(); + invalidTextures = platformCache->TexturesQuality != platformSettings->TexturesQuality; + } + if (invalidTextures) + { + LOG(Info, "{0} option has been modified.", TEXT("TexturesQuality")); + cache->InvalidateCacheTextures(); + } +} + +Array iOSPlatformTools::SaveCache(CookingData& data, IBuildCache* cache) +{ + const auto platformSettings = iOSPlatformSettings::Get(); + iOSPlatformCache platformCache; + platformCache.TexturesQuality = platformSettings->TexturesQuality; + Array result; + result.Add((const byte*)&platformCache, sizeof(platformCache)); + return result; +} + void iOSPlatformTools::OnBuildStarted(CookingData& data) { // Adjust the cooking output folders for packaging app diff --git a/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.h b/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.h index 854961923..0bc7018b8 100644 --- a/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.h +++ b/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.h @@ -19,6 +19,8 @@ public: ArchitectureType GetArchitecture() const override; DotNetAOTModes UseAOT() const override; PixelFormat GetTextureFormat(CookingData& data, TextureBase* texture, PixelFormat format) override; + void LoadCache(CookingData& data, IBuildCache* cache, const Span& bytes) override; + Array SaveCache(CookingData& data, IBuildCache* cache) override; bool IsNativeCodeFile(CookingData& data, const String& file) override; void OnBuildStarted(CookingData& data) override; bool OnPostProcess(CookingData& data) override; diff --git a/Source/Engine/Graphics/PixelFormat.h b/Source/Engine/Graphics/PixelFormat.h index f6793e543..908864c58 100644 --- a/Source/Engine/Graphics/PixelFormat.h +++ b/Source/Engine/Graphics/PixelFormat.h @@ -519,10 +519,40 @@ API_ENUM() enum class PixelFormat : uint32 ASTC_4x4_UNorm = 100, /// - /// A four-component ASTC (4x4 pixel block in 128 bits) block-compression format that supports RGBA channels. + /// A four-component ASTC (4x4 pixel block in 128 bits) block-compression format that supports RGBA channels. Data in sRGB color space. /// ASTC_4x4_UNorm_sRGB = 101, + /// + /// A four-component ASTC (6x6 pixel block in 128 bits) block-compression format that supports RGBA channels. + /// + ASTC_6x6_UNorm = 102, + + /// + /// A four-component ASTC (6x6 pixel block in 128 bits) block-compression format that supports RGBA channels. Data in sRGB color space. + /// + ASTC_6x6_UNorm_sRGB = 103, + + /// + /// A four-component ASTC (8x8 pixel block in 128 bits) block-compression format that supports RGBA channels. + /// + ASTC_8x8_UNorm = 104, + + /// + /// A four-component ASTC (8x8 pixel block in 128 bits) block-compression format that supports RGBA channels. Data in sRGB color space. + /// + ASTC_8x8_UNorm_sRGB = 105, + + /// + /// A four-component ASTC (10x10 pixel block in 128 bits) block-compression format that supports RGBA channels. + /// + ASTC_10x10_UNorm = 106, + + /// + /// A four-component ASTC (10x10 pixel block in 128 bits) block-compression format that supports RGBA channels. Data in sRGB color space. + /// + ASTC_10x10_UNorm_sRGB = 107, + /// /// The maximum format value (for internal use only). /// diff --git a/Source/Engine/Platform/iOS/iOSPlatformSettings.h b/Source/Engine/Platform/iOS/iOSPlatformSettings.h index 9eed39f41..4016f2767 100644 --- a/Source/Engine/Platform/iOS/iOSPlatformSettings.h +++ b/Source/Engine/Platform/iOS/iOSPlatformSettings.h @@ -46,6 +46,22 @@ API_CLASS(Sealed, Namespace="FlaxEditor.Content.Settings") class FLAXENGINE_API All = Portrait | PortraitUpsideDown | LandscapeLeft | LandscapeRight }; + /// + /// The output textures quality (compression). + /// + API_ENUM() enum class TextureQuality + { + // ASTC 4x4 block compression. + API_ENUM(Attributes="EditorDisplay(null, \"ASTC High\")") + ASTC_High = 0, + // ASTC 6x6 block compression. + API_ENUM(Attributes="EditorDisplay(null, \"ASTC Medium\")") + ASTC_Medium = 1, + // ASTC 8x8 block compression. + API_ENUM(Attributes="EditorDisplay(null, \"ASTC Low\")") + ASTC_Low = 2, + }; + /// /// The app developer name - App Store Team ID. For example: 'VG6K6HT8B'. /// @@ -64,6 +80,12 @@ API_CLASS(Sealed, Namespace="FlaxEditor.Content.Settings") class FLAXENGINE_API API_FIELD(Attributes="EditorOrder(50), EditorDisplay(\"General\")") ExportMethods ExportMethod = ExportMethods::Development; + /// + /// The output textures quality (compression). + /// + API_FIELD(Attributes="EditorOrder(100), EditorDisplay(\"General\")") + TextureQuality TexturesQuality = TextureQuality::ASTC_Medium; + /// /// The UI interface orientation modes supported on iPhone devices. ///