get rid of timestamp comparison for shaders, compare actual data
# Conflicts: # Source/Engine/Graphics/Materials/MaterialShader.h # Source/Engine/Tests/Tests.Build.cs
This commit is contained in:
@@ -26,6 +26,8 @@
|
||||
#if USE_EDITOR
|
||||
#define COMPILE_WITH_ASSETS_IMPORTER 1 // Hack to use shaders importing in this module
|
||||
#include "Engine/ContentImporters/AssetsImportingManager.h"
|
||||
#include "Engine/Content/Storage/ContentStorageManager.h"
|
||||
#include "Engine/Utilities/Encryption.h"
|
||||
#include "Engine/Platform/FileSystemWatcher.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
@@ -495,6 +497,37 @@ String ShadersCompilation::CompactShaderPath(StringView path)
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
bool ShadersCompilation::IsShaderSourceAssetUpToDate(const StringView& sourcePath, const StringView& assetPath)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
StringAnsi source;
|
||||
if (File::ReadAllText(sourcePath, source))
|
||||
return false;
|
||||
if (!source.HasChars() || source[source.Length() - 1] != '\n')
|
||||
source.Append('\n');
|
||||
|
||||
const auto storage = ContentStorageManager::GetStorage(assetPath);
|
||||
AssetInitData data;
|
||||
if (!storage
|
||||
|| storage->GetEntriesCount() != 1
|
||||
|| storage->GetEntry(0).TypeName != Shader::TypeName
|
||||
|| storage->LoadAssetHeader(0, data)
|
||||
|| data.SerializedVersion != Shader::SerializedVersion)
|
||||
return false;
|
||||
|
||||
FlaxChunk* sourceChunk = data.Header.Chunks[SHADER_FILE_CHUNK_SOURCE];
|
||||
if (!sourceChunk || storage->LoadAssetChunk(sourceChunk) || !sourceChunk->Data.IsValid())
|
||||
return false;
|
||||
|
||||
BytesContainer embeddedSource;
|
||||
embeddedSource.Copy(sourceChunk->Data);
|
||||
if (embeddedSource.Length() != source.Length() + 1)
|
||||
return false;
|
||||
Encryption::DecryptBytes(embeddedSource.Get(), embeddedSource.Length());
|
||||
embeddedSource.Get()[embeddedSource.Length() - 1] = 0;
|
||||
return Platform::MemoryCompare(embeddedSource.Get(), source.Get(), source.Length()) == 0;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
Array<FileSystemWatcher*> ShadersSourcesWatchers;
|
||||
@@ -511,6 +544,13 @@ namespace
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ImportShaderIfChanged(const StringView& sourcePath, const StringView& assetPath, Guid& assetId)
|
||||
{
|
||||
if (ShadersCompilation::IsShaderSourceAssetUpToDate(sourcePath, assetPath))
|
||||
return false;
|
||||
return AssetsImportingManager::Import(sourcePath, assetPath, assetId);
|
||||
}
|
||||
|
||||
void OnWatcherShadersEvent(const String& path, FileSystemAction action)
|
||||
{
|
||||
if (action == FileSystemAction::Delete || !path.EndsWith(TEXT(".shader")))
|
||||
@@ -533,7 +573,7 @@ namespace
|
||||
const String name = StringUtils::GetPathWithoutExtension(localPath);
|
||||
const String outputPath = shadersAssetsPath / name + ASSET_FILES_EXTENSION_WITH_DOT;
|
||||
Guid id = GetShaderAssetId(name);
|
||||
AssetsImportingManager::ImportIfEdited(path, outputPath, id);
|
||||
ImportShaderIfChanged(path, outputPath, id);
|
||||
}
|
||||
|
||||
void RegisterShaderWatchers(const ProjectInfo* project, HashSet<const ProjectInfo*>& projects)
|
||||
@@ -562,7 +602,7 @@ namespace
|
||||
const String name = StringUtils::GetPathWithoutExtension(localPath);
|
||||
const String outputPath = shadersAssetsPath / name + ASSET_FILES_EXTENSION_WITH_DOT;
|
||||
Guid id = GetShaderAssetId(name);
|
||||
AssetsImportingManager::ImportIfEdited(path, outputPath, id);
|
||||
ImportShaderIfChanged(path, outputPath, id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,16 @@ public:
|
||||
// Compacts the full shader file path into portable format with project name prefix such as './<ProjectName>/ShaderFile.hlsl'.
|
||||
static String CompactShaderPath(StringView path);
|
||||
|
||||
#if USE_EDITOR
|
||||
/// <summary>
|
||||
/// Checks whether a shader asset embeds the current source file contents.
|
||||
/// </summary>
|
||||
/// <param name="sourcePath">The shader source file path.</param>
|
||||
/// <param name="assetPath">The shader asset file path.</param>
|
||||
/// <returns>True when the embedded source matches, otherwise false.</returns>
|
||||
static bool IsShaderSourceAssetUpToDate(const StringView& sourcePath, const StringView& assetPath);
|
||||
#endif
|
||||
|
||||
private:
|
||||
static ShaderCompiler* RequestCompiler(ShaderProfile profile, PlatformType platform);
|
||||
static void FreeCompiler(ShaderCompiler* compiler);
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "Engine/Core/ScopeExit.h"
|
||||
#include "Engine/Core/Types/DataContainer.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/ShadersCompilation/ShadersCompilation.h"
|
||||
#include <ThirdParty/catch2/catch.hpp>
|
||||
|
||||
#if COMPILE_WITH_SHADER_COMPILER && USE_EDITOR
|
||||
|
||||
TEST_CASE("Shader source asset synchronization ignores timestamps")
|
||||
{
|
||||
const String sourcePath = Globals::StartupFolder / TEXT("Source/Shaders/VolumetricFog.shader");
|
||||
const String assetPath = Globals::EngineContentFolder / TEXT("Shaders/VolumetricFog.flax");
|
||||
REQUIRE(FileSystem::FileExists(sourcePath));
|
||||
REQUIRE(FileSystem::FileExists(assetPath));
|
||||
CHECK(ShadersCompilation::IsShaderSourceAssetUpToDate(sourcePath, assetPath));
|
||||
|
||||
const String tempRoot = Globals::TemporaryFolder / (TEXT("ShaderSourceSync-") + Guid::New().ToString(Guid::FormatType::N));
|
||||
REQUIRE(!FileSystem::CreateDirectory(tempRoot));
|
||||
SCOPE_EXIT
|
||||
{
|
||||
FileSystem::DeleteDirectory(tempRoot, true);
|
||||
};
|
||||
|
||||
DataContainer<byte> assetData;
|
||||
StringAnsi modifiedSource;
|
||||
REQUIRE(!File::ReadAllBytes(assetPath, assetData));
|
||||
REQUIRE(!File::ReadAllText(sourcePath, modifiedSource));
|
||||
modifiedSource.Append("// Deliberately different source\n");
|
||||
|
||||
const String tempSourcePath = tempRoot / TEXT("VolumetricFog.shader");
|
||||
const String tempAssetPath = tempRoot / TEXT("VolumetricFog.flax");
|
||||
REQUIRE(!File::WriteAllBytes(tempSourcePath, modifiedSource.Get(), modifiedSource.Length()));
|
||||
REQUIRE(!File::WriteAllBytes(tempAssetPath, assetData.Get(), assetData.Length()));
|
||||
CHECK_FALSE(FileSystem::GetFileLastEditTime(tempSourcePath) > FileSystem::GetFileLastEditTime(tempAssetPath));
|
||||
CHECK_FALSE(ShadersCompilation::IsShaderSourceAssetUpToDate(tempSourcePath, tempAssetPath));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -21,6 +21,7 @@ public class Tests : EngineModule
|
||||
base.Setup(options);
|
||||
|
||||
options.PrivateDependencies.Add("ModelTool");
|
||||
options.PrivateDependencies.Add("ShadersCompilation");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
Reference in New Issue
Block a user