From 97b37b3ce468f8f674ff88e1600670a65cc66f5f Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 16 Jun 2025 18:00:26 +0200 Subject: [PATCH 1/5] Add `PRAGMA_DISABLE_OPTIMIZATION`/`PRAGMA_ENABLE_OPTIMIZATION` --- Source/Engine/Core/Compiler.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source/Engine/Core/Compiler.h b/Source/Engine/Core/Compiler.h index fb731930e..a45a4628a 100644 --- a/Source/Engine/Core/Compiler.h +++ b/Source/Engine/Core/Compiler.h @@ -26,6 +26,8 @@ _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") #define PRAGMA_ENABLE_DEPRECATION_WARNINGS \ _Pragma("clang diagnostic pop") +#define PRAGMA_DISABLE_OPTIMIZATION +#define PRAGMA_ENABLE_OPTIMIZATION #pragma clang diagnostic ignored "-Wswitch" #pragma clang diagnostic ignored "-Wmacro-redefined" @@ -54,6 +56,8 @@ #define OFFSET_OF(X, Y) __builtin_offsetof(X, Y) #define PRAGMA_DISABLE_DEPRECATION_WARNINGS #define PRAGMA_ENABLE_DEPRECATION_WARNINGS +#define PRAGMA_DISABLE_OPTIMIZATION +#define PRAGMA_ENABLE_OPTIMIZATION #elif defined(_MSC_VER) @@ -86,6 +90,8 @@ __pragma(warning(disable: 4996)) #define PRAGMA_ENABLE_DEPRECATION_WARNINGS \ __pragma (warning(pop)) +#define PRAGMA_DISABLE_OPTIMIZATION __pragma(optimize("", off)) +#define PRAGMA_ENABLE_OPTIMIZATION __pragma(optimize("", on)) #pragma warning(disable: 4251) From 6a82eb114dcf222ad5093b97d6c5004f7eb7cc67 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 16 Jun 2025 19:05:44 +0200 Subject: [PATCH 2/5] Fix `BitArray` bit indexing --- Source/Engine/Core/Collections/BitArray.h | 13 ++++----- Source/Engine/Tests/TestCollections.cpp | 32 ++++++++++++++++++++--- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/Source/Engine/Core/Collections/BitArray.h b/Source/Engine/Core/Collections/BitArray.h index 8206f2164..6589fa9a1 100644 --- a/Source/Engine/Core/Collections/BitArray.h +++ b/Source/Engine/Core/Collections/BitArray.h @@ -16,6 +16,7 @@ API_CLASS(InBuild) class BitArray public: using ItemType = uint64; using AllocationData = typename AllocationType::template Data; + static constexpr int32 ItemBitCount = 64; private: int32 _count; @@ -209,8 +210,8 @@ public: bool Get(const int32 index) const { ASSERT(index >= 0 && index < _count); - const ItemType offset = index / sizeof(ItemType); - const ItemType bitMask = (ItemType)(int32)(1 << (index & ((int32)sizeof(ItemType) - 1))); + const ItemType offset = index / ItemBitCount; + const ItemType bitMask = (ItemType)(1 << (index & (ItemBitCount - 1))); const ItemType item = ((ItemType*)_allocation.Get())[offset]; return (item & bitMask) != 0; } @@ -223,13 +224,13 @@ public: void Set(const int32 index, const bool value) { ASSERT(index >= 0 && index < _count); - const ItemType offset = index / sizeof(ItemType); - const ItemType bitMask = (ItemType)(int32)(1 << (index & ((int32)sizeof(ItemType) - 1))); + const ItemType offset = index / ItemBitCount; + const ItemType bitMask = (ItemType)(1 << (index & (ItemBitCount - 1))); ItemType& item = ((ItemType*)_allocation.Get())[offset]; if (value) - item |= bitMask; + item |= bitMask; // Set the bit else - item &= ~bitMask; // Clear the bit + item &= ~bitMask; // Unset the bit } public: diff --git a/Source/Engine/Tests/TestCollections.cpp b/Source/Engine/Tests/TestCollections.cpp index fd0f3328d..b477140cf 100644 --- a/Source/Engine/Tests/TestCollections.cpp +++ b/Source/Engine/Tests/TestCollections.cpp @@ -78,6 +78,32 @@ TEST_CASE("Array") TEST_CASE("BitArray") { + SECTION("Test Access") + { + BitArray<> a1; + CHECK(a1.Count() == 0); + for (int32 i = 0; i < 310; i++) + { + a1.Add(false); + } + CHECK(a1.Count() == 310); + a1.Resize(300); + CHECK(a1.Count() == 300); + CHECK(a1.Capacity() >= 300); + a1.SetAll(true); + a1.SetAll(false); + for (int32 i = 0; i < 300; i++) + { + a1.Set(i, true); + for (int32 j = 0; j < 300; j++) + { + bool expected = j == i; + CHECK(a1.Get(j) == expected); + } + a1.Set(i, false); + } + } + SECTION("Test Allocators") { BitArray<> a1; @@ -142,7 +168,7 @@ TEST_CASE("BitArray") // Generate some random data for testing BitArray<> testData; - testData.Resize(32); + testData.Resize(128); RandomStream rand(101); for (int32 i = 0; i < testData.Count(); i++) testData.Set(i, rand.GetBool()); @@ -151,8 +177,8 @@ TEST_CASE("BitArray") { const BitArray<> a1(testData); const BitArray> a2(testData); - const BitArray> a3(testData); - const BitArray> a4(testData); + const BitArray> a3(testData); + const BitArray> a4(testData); CHECK(a1 == testData); CHECK(a2 == testData); CHECK(a3 == testData); From b92c18cf250a7cdc26c75d6867b128975a3871f2 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 16 Jun 2025 19:10:35 +0200 Subject: [PATCH 3/5] Fix missing/incorrect toolchain exception to log only once --- Source/Tools/Flax.Build/Build/Platform.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/Tools/Flax.Build/Build/Platform.cs b/Source/Tools/Flax.Build/Build/Platform.cs index 6304cdc4a..59572d669 100644 --- a/Source/Tools/Flax.Build/Build/Platform.cs +++ b/Source/Tools/Flax.Build/Build/Platform.cs @@ -17,6 +17,7 @@ namespace Flax.Build private static Platform _buildPlatform; private static Platform[] _platforms; private Dictionary _toolchains; + private uint _failedArchitectures = 0; /// /// Gets the current target platform that build tool runs on. @@ -251,7 +252,8 @@ namespace Flax.Build public Toolchain TryGetToolchain(TargetArchitecture targetArchitecture) { Toolchain result = null; - if (HasRequiredSDKsInstalled) + uint failedMask = 1u << (int)targetArchitecture; // Skip retrying if it already failed once on this arch + if (HasRequiredSDKsInstalled && (_failedArchitectures & failedMask) != failedMask) { try { @@ -259,6 +261,7 @@ namespace Flax.Build } catch (Exception ex) { + _failedArchitectures |= failedMask; Log.Exception(ex); } } From 5a23060e05623f08a2d67391502e623ac7d40a66 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 16 Jun 2025 22:35:50 +0200 Subject: [PATCH 4/5] Add `GPUTexture.UploadData` for changing texture contents via `TextureData` container --- Source/Engine/Graphics/Textures/GPUTexture.cpp | 17 +++++++++++++++++ Source/Engine/Graphics/Textures/GPUTexture.h | 12 ++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Graphics/Textures/GPUTexture.cpp b/Source/Engine/Graphics/Textures/GPUTexture.cpp index 127cf2f5b..59b025b70 100644 --- a/Source/Engine/Graphics/Textures/GPUTexture.cpp +++ b/Source/Engine/Graphics/Textures/GPUTexture.cpp @@ -630,6 +630,23 @@ GPUTask* GPUTexture::UploadMipMapAsync(const BytesContainer& data, int32 mipInde return task; } +bool GPUTexture::UploadData(TextureData& data, bool copyData) +{ + if (!IsAllocated()) + return true; + if (data.Width != Width() || data.Height != Height() || data.Depth != Depth() || data.GetArraySize() != ArraySize() || data.Format != Format()) + return true; + for (int32 arrayIndex = 0; arrayIndex < ArraySize(); arrayIndex++) + { + for (int32 mipLevel = 0; mipLevel < MipLevels(); mipLevel++) + { + TextureMipData* mip = data.GetData(arrayIndex, mipLevel); + UploadMipMapAsync(mip->Data, mipLevel, mip->RowPitch, mip->DepthPitch, copyData); + } + } + return false; +} + class TextureDownloadDataTask : public ThreadPoolTask { private: diff --git a/Source/Engine/Graphics/Textures/GPUTexture.h b/Source/Engine/Graphics/Textures/GPUTexture.h index 977723f26..85ac4ae0b 100644 --- a/Source/Engine/Graphics/Textures/GPUTexture.h +++ b/Source/Engine/Graphics/Textures/GPUTexture.h @@ -499,7 +499,7 @@ public: /// /// Uploads mip map data to the GPU. Creates async GPU task. /// - /// Data to upload (it must be valid for the next a few frames due to GPU latency and async works executing) + /// Data to upload, it must match texture dimensions. It must be valid for the next couple of frames due to GPU async task latency or use data copy. /// Mip level index. /// If true, the data will be copied to the async execution task instead of using the input pointer provided. /// Created async task or null if cannot. @@ -508,7 +508,7 @@ public: /// /// Uploads mip map data to the GPU. Creates async GPU task. /// - /// Data to upload (it must be valid for the next a few frames due to GPU latency and async works executing) + /// Data to upload, it must match texture dimensions. It must be valid for the next couple of frames due to GPU async task latency or use data copy. /// Mip level index. /// The data row pitch. /// The data slice pitch. @@ -516,6 +516,14 @@ public: /// Created async task or null if cannot. GPUTask* UploadMipMapAsync(const BytesContainer& data, int32 mipIndex, int32 rowPitch, int32 slicePitch, bool copyData = false); + /// + /// Uploads texture data to the GPU. Actual data copy to the GPU memory is performed via async task. + /// + /// Data to upload, it must match texture dimensions. It must be valid for the next couple of frames due to GPU async task latency or use data copy. + /// If true, the data will be copied to the async execution task instead of using the input pointer provided. + /// True if cannot upload data, otherwise false. + API_FUNCTION() bool UploadData(TextureData& data, bool copyData = false); + /// /// Downloads the texture data to be accessible from CPU. For frequent access, use staging textures, otherwise current thread will be stalled to wait for the GPU frame to copy data into staging buffer. /// From eb6010cba74286c52f3eb255fc13f67bf82b8271 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 16 Jun 2025 23:20:20 +0200 Subject: [PATCH 5/5] Fix `BitArray` again --- Source/Engine/Core/Collections/BitArray.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Source/Engine/Core/Collections/BitArray.h b/Source/Engine/Core/Collections/BitArray.h index 6589fa9a1..28a71351b 100644 --- a/Source/Engine/Core/Collections/BitArray.h +++ b/Source/Engine/Core/Collections/BitArray.h @@ -16,7 +16,6 @@ API_CLASS(InBuild) class BitArray public: using ItemType = uint64; using AllocationData = typename AllocationType::template Data; - static constexpr int32 ItemBitCount = 64; private: int32 _count; @@ -210,8 +209,8 @@ public: bool Get(const int32 index) const { ASSERT(index >= 0 && index < _count); - const ItemType offset = index / ItemBitCount; - const ItemType bitMask = (ItemType)(1 << (index & (ItemBitCount - 1))); + const ItemType offset = index / 64; + const ItemType bitMask = 1ull << (index & 63ull); const ItemType item = ((ItemType*)_allocation.Get())[offset]; return (item & bitMask) != 0; } @@ -224,8 +223,8 @@ public: void Set(const int32 index, const bool value) { ASSERT(index >= 0 && index < _count); - const ItemType offset = index / ItemBitCount; - const ItemType bitMask = (ItemType)(1 << (index & (ItemBitCount - 1))); + const ItemType offset = index / 64; + const ItemType bitMask = 1ull << (index & 63ull); ItemType& item = ((ItemType*)_allocation.Get())[offset]; if (value) item |= bitMask; // Set the bit