diff --git a/Source/Editor/Tools/Foliage/FoliageTools.cpp b/Source/Editor/Tools/Foliage/FoliageTools.cpp index 8602f9802..2a68912c7 100644 --- a/Source/Editor/Tools/Foliage/FoliageTools.cpp +++ b/Source/Editor/Tools/Foliage/FoliageTools.cpp @@ -36,17 +36,13 @@ struct GeometryTriangle void GetRandomPoint(Vector3& result) const { - // Sample parallelogram float x = Random::Rand(); float y = Random::Rand(); - - // Flip if we're outside the triangle if (x + y > 1.0f) { x = 1.0f - x; y = 1.0f - y; } - result = Vertex + x * Vector1 + y * Vector2; } }; @@ -234,15 +230,13 @@ void FoliageTools::Paint(Foliage* foliage, Span foliageTypesIndices, cons continue; } - // This is the total set of instances disregarding parameters like slope, height or layer - const float desiredInstanceCountFloat = triangle.Area * foliageType.PaintDensity * densityScale / (1000.0f * 1000.0f); + // Calculate amount of foliage instances to place + const float targetInstanceCountEst = triangle.Area * foliageType.PaintDensity * densityScale / (1000.0f * 1000.0f); + const int32 targetInstanceCount = targetInstanceCountEst > 1.0f ? Math::RoundToInt(targetInstanceCountEst) : Random::Rand() < targetInstanceCountEst ? 1 : 0; - // Allow a single instance with a random chance, if the brush is smaller than the density - const int32 desiredInstanceCount = desiredInstanceCountFloat > 1.0f ? Math::RoundToInt(desiredInstanceCountFloat) : Random::Rand() < desiredInstanceCountFloat ? 1 : 0; - - // Try to new instances + // Try to add new instances FoliagePlacement placement; - for (int32 j = 0; j < desiredInstanceCount; j++) + for (int32 j = 0; j < targetInstanceCount; j++) { triangle.GetRandomPoint(placement.Location); diff --git a/Source/Editor/Viewport/Previews/AudioClipPreview.cs b/Source/Editor/Viewport/Previews/AudioClipPreview.cs index 08d08d24e..2dfda0e9a 100644 --- a/Source/Editor/Viewport/Previews/AudioClipPreview.cs +++ b/Source/Editor/Viewport/Previews/AudioClipPreview.cs @@ -152,20 +152,16 @@ namespace FlaxEditor.Viewport.Previews var clipX = clipWidth * clipIndex; var clipRight = Mathf.Min(width, clipX + clipWidth); - // Render each channel separately so outer loop is the sound wave channel index + // Render every audio channel separately for (uint channelIndex = 0; channelIndex < info.NumChannels; channelIndex++) { uint currentSample = channelIndex; float yCenter = Y + ((2 * channelIndex) + 1) * height / (2.0f * info.NumChannels); - - // Loop through each pixel (in x direction) for (float pixelX = clipX; pixelX < clipRight; pixelX++) { - // Reset the sample sum and num samples in pixel for each pixel float samplesSum = 0; int samplesInPixel = 0; - // Loop through all pixels in this x-frame and sum all audio data uint samplesEnd = Math.Min(currentSample + samplesPerIndex, info.NumSamples); for (uint sampleIndex = currentSample; sampleIndex < samplesEnd; sampleIndex += samplesPerIndexDiff) { @@ -173,16 +169,14 @@ namespace FlaxEditor.Viewport.Previews samplesInPixel++; } currentSample = samplesEnd; + if (samplesInPixel > 0) { - float averageSampleValue = samplesSum / samplesInPixel; - float averageSampleValueScaled = averageSampleValue * sampleYScale; - - // Don't try to draw anything if the audio data was too quiet - if (averageSampleValueScaled > 0.1f) + float sampleValueAvg = samplesSum / samplesInPixel; + float sampleValueAvgScaled = sampleValueAvg * sampleYScale; + if (sampleValueAvgScaled > 0.1f) { - // Draw vertical line mirrored around x-axis for channel equal to average sample value height - Render2D.DrawLine(new Vector2(pixelX, yCenter - averageSampleValueScaled), new Vector2(pixelX, yCenter + averageSampleValueScaled), color); + Render2D.DrawLine(new Vector2(pixelX, yCenter - sampleValueAvgScaled), new Vector2(pixelX, yCenter + sampleValueAvgScaled), color); } } } diff --git a/Source/Engine/Animations/InverseKinematics.cpp b/Source/Engine/Animations/InverseKinematics.cpp index 40985d040..9176da968 100644 --- a/Source/Engine/Animations/InverseKinematics.cpp +++ b/Source/Engine/Animations/InverseKinematics.cpp @@ -17,7 +17,7 @@ void InverseKinematics::SolveTwoBoneIK(Transform& rootNode, Transform& jointNode Vector3 jointPos = jointNode.Translation; Vector3 desiredDelta = target - rootNode.Translation; float desiredLength = desiredDelta.Length(); - float maxLimbLength = lowerLimbLength + upperLimbLength; + float limbLengthLimit = lowerLimbLength + upperLimbLength; Vector3 desiredDir; if (desiredLength < ZeroTolerance) @@ -56,17 +56,17 @@ void InverseKinematics::SolveTwoBoneIK(Transform& rootNode, Transform& jointNode if (allowStretching) { - const float startStretchRatio = 1.0f; - const float scaleRange = maxStretchScale - startStretchRatio; - if (scaleRange > ZeroTolerance && maxLimbLength > ZeroTolerance) + const float initialStretchRatio = 1.0f; + const float range = maxStretchScale - initialStretchRatio; + if (range > ZeroTolerance && limbLengthLimit > ZeroTolerance) { - const float reachRatio = desiredLength / maxLimbLength; - const float scalingFactor = (maxStretchScale - 1.0f) * Math::Saturate((reachRatio - startStretchRatio) / scaleRange); + const float reachRatio = desiredLength / limbLengthLimit; + const float scalingFactor = (maxStretchScale - 1.0f) * Math::Saturate((reachRatio - initialStretchRatio) / range); if (scalingFactor > ZeroTolerance) { lowerLimbLength *= 1.0f + scalingFactor; upperLimbLength *= 1.0f + scalingFactor; - maxLimbLength *= 1.0f + scalingFactor; + limbLengthLimit *= 1.0f + scalingFactor; } } } @@ -74,9 +74,9 @@ void InverseKinematics::SolveTwoBoneIK(Transform& rootNode, Transform& jointNode Vector3 resultEndPos = target; Vector3 resultJointPos = jointPos; - if (desiredLength >= maxLimbLength) + if (desiredLength >= limbLengthLimit) { - resultEndPos = rootNode.Translation + maxLimbLength * desiredDir; + resultEndPos = rootNode.Translation + limbLengthLimit * desiredDir; resultJointPos = rootNode.Translation + upperLimbLength * desiredDir; } else diff --git a/Source/Engine/Content/Utilities/IESLoader.cpp b/Source/Engine/Content/Utilities/IESLoader.cpp index 35f81a9c4..ae35f5bc5 100644 --- a/Source/Engine/Content/Utilities/IESLoader.cpp +++ b/Source/Engine/Content/Utilities/IESLoader.cpp @@ -2,19 +2,13 @@ #include "Engine/Core/Log.h" #include "Engine/Core/RandomStream.h" -#include "Engine/Core/Enums.h" #include "Engine/Core/Math/Packed.h" #include "IESLoader.h" -/// -/// IES profile format version -/// -DECLARE_ENUM_4(IESVersion, EIESV_1986, EIESV_1991, EIESV_1995, EIESV_2002); +#define MAX_LINE 200 -static void JumpOverWhiteSpace(const uint8*& bufferPos) +static void SkipWhiteSpace(const uint8*& bufferPos) { - // Space and return - while (*bufferPos) { if (*bufferPos == 13 && *(bufferPos + 1) == 10) @@ -22,15 +16,13 @@ static void JumpOverWhiteSpace(const uint8*& bufferPos) bufferPos += 2; continue; } - if (*bufferPos == 10) { - // No valid MSDOS return file - CRASH; + bufferPos++; + continue; } - else if (*bufferPos <= ' ') + if (*bufferPos <= ' ') { - // Tab, space, invisible characters bufferPos++; continue; } @@ -39,14 +31,12 @@ static void JumpOverWhiteSpace(const uint8*& bufferPos) } } -static void GetLineContent(const uint8*& bufferPos, char Line[256], bool bStopOnWhitespace) +static void ReadLine(const uint8*& bufferPos, char line[MAX_LINE], bool skipUntilWhitespace) { - JumpOverWhiteSpace(bufferPos); - - char* linePtr = Line; + SkipWhiteSpace(bufferPos); + char* linePtr = line; uint32 i; - for (i = 0; i < 255; i++) { if (*bufferPos == 0) @@ -60,12 +50,11 @@ static void GetLineContent(const uint8*& bufferPos, char Line[256], bool bStopOn } if (*bufferPos == 10) { - // No valid MSDOS return file - CRASH; + bufferPos++; + continue; } - else if (bStopOnWhitespace && (*bufferPos <= ' ')) + if (skipUntilWhitespace && *bufferPos <= ' ') { - // Tab, space, invisible characters bufferPos++; break; } @@ -73,387 +62,231 @@ static void GetLineContent(const uint8*& bufferPos, char Line[256], bool bStopOn *linePtr++ = *bufferPos++; } - Line[i] = 0; + line[i] = 0; } -static bool GetFloat(const uint8*& bufferPos, float& ret) +static bool ReadFloat(const uint8*& bufferPos, float& ret) { - char line[256]; - - GetLineContent(bufferPos, line, true); - + char line[MAX_LINE]; + ReadLine(bufferPos, line, true); ret = static_cast(atof(line)); return true; } -static bool GetInt(const uint8*& bufferPos, int32& ret) +static bool ReadLine(const uint8*& bufferPos, int32& ret) { - char line[256]; - - GetLineContent(bufferPos, line, true); - + char line[MAX_LINE]; + ReadLine(bufferPos, line, true); ret = atoi(line); return true; } -IESLoader::IESLoader() - : _brightness(0) - , _cachedIntegral(-1) -{ -} - -#define LOG_IES_IMPORT_ERROR(error) LOG(Warning, "Cannot import IES profile. {0}", error) -#define PARSE_FLOAT(x) float x; if (!GetFloat(bufferPos, x)) { LOG_IES_IMPORT_ERROR(error); return true; } -#define PARSE_INT(x) int32 x; if (!GetInt(bufferPos, x)) { LOG_IES_IMPORT_ERROR(error); return true; } +#define PARSE_FLOAT(x) float x; if (!ReadFloat(bufferPos, x)) { return true; } +#define PARSE_INT(x) int32 x; if (!ReadLine(bufferPos, x)) { return true; } bool IESLoader::Load(const byte* buffer) { - // File format as described here: + // Referenced IES file format: // http://www.ltblight.com/English.lproj/LTBLhelp/pages/iesformat.html const uint8* bufferPos = buffer; - const Char* error = nullptr; - - IESVersion version = IESVersion::EIESV_1986; + const char* version; { - error = TEXT("VersionError"); - - char line1[256]; - - GetLineContent(bufferPos, line1, false); - - if (StringUtils::CompareIgnoreCase(line1, "IESNA:LM-63-1995") == 0) + char line[MAX_LINE]; + ReadLine(bufferPos, line, false); + if (StringUtils::CompareIgnoreCase(line, "IESNA:LM-63-1995") == 0) { - version = IESVersion::EIESV_1995; + version = "EIESV_1995"; } - else if (StringUtils::CompareIgnoreCase(line1, "IESNA91") == 0) + else if (StringUtils::CompareIgnoreCase(line, "IESNA91") == 0) { - version = IESVersion::EIESV_1991; + version = "EIESV_1991"; } - else if (StringUtils::CompareIgnoreCase(line1, "IESNA:LM-63-2002") == 0) + else if (StringUtils::CompareIgnoreCase(line, "IESNA:LM-63-2002") == 0) { - version = IESVersion::EIESV_2002; + version = "EIESV_2002"; } else { - // EIESV_1986 + version = "EIESV_1986"; } } - error = TEXT("HeaderError"); - while (*bufferPos) { - char line[256]; - - GetLineContent(bufferPos, line, false); - - if (strcmp(line, "TILT=NONE") == 0) + char line[MAX_LINE]; + ReadLine(bufferPos, line, false); + if (StringUtils::Compare(line, "TILT=NONE") == 0) { - // At the moment we don't support only profiles with TILT=NONE break; } - if (strncmp(line, "TILT=", 5) == 0) + if (StringUtils::Compare(line, "TILT=", 5) == 0) { - // "TILT=NONE", "TILT=INCLUDE", and "TILT={filename}" - // not supported yet, seems rare - LOG(Warning, "Cannot import IES profile. {0}", String(error)); return true; } } - error = TEXT("HeaderParameterError"); + PARSE_INT(lights); + PARSE_FLOAT(lumensPerLight); + PARSE_FLOAT(candalaScale); + PARSE_INT(vAnglesCount); + PARSE_INT(hAnglesCount); + PARSE_INT(photometricType); + PARSE_INT(unitType); + PARSE_FLOAT(width); + PARSE_FLOAT(length); + PARSE_FLOAT(height); + PARSE_FLOAT(ballastWeight); + PARSE_FLOAT(dummy); + PARSE_FLOAT(watts); - PARSE_INT(LightCount); - - if (LightCount < 1) + if (lights < 1) { - error = TEXT("Light count needs to be positive."); - LOG(Warning, "Cannot import IES profile. {0}", error); return true; } - // if there is any file with that - do we need to parse it differently? - ASSERT(LightCount >= 1); - - PARSE_FLOAT(LumensPerLamp); - - _brightness = LumensPerLamp / LightCount; - - PARSE_FLOAT(CandalaMult); - - if (CandalaMult < 0) + if (candalaScale < 0 || vAnglesCount < 0 || hAnglesCount < 0) { - error = TEXT("CandalaMult is negative"); - LOG_IES_IMPORT_ERROR(error); return true; } - PARSE_INT(VAnglesNum); - PARSE_INT(HAnglesNum); - - if (VAnglesNum < 0) - { - error = TEXT("VAnglesNum is not valid"); - LOG_IES_IMPORT_ERROR(error); - return true; - } - - if (HAnglesNum < 0) - { - error = TEXT("HAnglesNum is not valid"); - LOG_IES_IMPORT_ERROR(error); - return true; - } - - PARSE_INT(PhotometricType); - - // 1:feet, 2:meter - PARSE_INT(UnitType); - - PARSE_FLOAT(Width); - PARSE_FLOAT(Length); - PARSE_FLOAT(Height); - - PARSE_FLOAT(BallastFactor); - PARSE_FLOAT(FutureUse); - - PARSE_FLOAT(InputWatts); - - LOG(Info, "IES profile version: {0}, VAngles: {1}, HAngles: {2}", ::ToString(version), VAnglesNum, HAnglesNum); - - error = TEXT("ContentError"); + _brightness = lumensPerLight / lights; { - float minSoFar = MIN_float; - - _vAngles.SetCapacity(VAnglesNum, false); - for (int32 y = 0; y < VAnglesNum; y++) + float minValue = MIN_float; + _vAngles.SetCapacity(vAnglesCount, false); + for (int32 y = 0; y < vAnglesCount; y++) { - PARSE_FLOAT(Value); - - if (Value < minSoFar) - { - // binary search later relies on that - error = TEXT("V Values are not in increasing order"); - LOG_IES_IMPORT_ERROR(error); + PARSE_FLOAT(value); + if (value < minValue) return true; - } - - minSoFar = Value; - _vAngles.Add(Value); + minValue = value; + _vAngles.Add(value); } } { - float minSoFar = MIN_float; - - _hAngles.SetCapacity(HAnglesNum, false); - for (int32 x = 0; x < HAnglesNum; x++) + float minValue = MIN_float; + _hAngles.SetCapacity(hAnglesCount, false); + for (int32 x = 0; x < hAnglesCount; x++) { - PARSE_FLOAT(Value); - - if (Value < minSoFar) - { - // binary search later relies on that - error = TEXT("H Values are not in increasing order"); - LOG_IES_IMPORT_ERROR(error); + PARSE_FLOAT(value); + if (value < minValue) return true; - } - - minSoFar = Value; - _hAngles.Add(Value); + minValue = value; + _hAngles.Add(value); } } - _candalaValues.SetCapacity(HAnglesNum * VAnglesNum, false); - for (int32 y = 0; y < HAnglesNum; y++) + _candalaValues.SetCapacity(hAnglesCount * vAnglesCount, false); + for (int32 y = 0; y < hAnglesCount; y++) { - for (int32 x = 0; x < VAnglesNum; x++) + for (int32 x = 0; x < vAnglesCount; x++) { - PARSE_FLOAT(Value); - - _candalaValues.Add(Value * CandalaMult); + PARSE_FLOAT(value); + _candalaValues.Add(value * candalaScale); } } - error = TEXT("Unexpected content after candala values."); - - JumpOverWhiteSpace(bufferPos); - + SkipWhiteSpace(bufferPos); if (*bufferPos) { - // some files are terminated with "END" - char Line[256]; - - GetLineContent(bufferPos, Line, true); - - if (strcmp(Line, "END") == 0) + char line[MAX_LINE]; + ReadLine(bufferPos, line, true); + if (StringUtils::Compare(line, "END") == 0) { - JumpOverWhiteSpace(bufferPos); + SkipWhiteSpace(bufferPos); } } - if (*bufferPos) { - error = TEXT("Unexpected content after END."); - LOG_IES_IMPORT_ERROR(error); return true; } if (_brightness <= 0) { - // Some samples have -1, then the brightness comes from the samples - // Brightness = ComputeFullIntegral(); - - // Use some reasonable value _brightness = 1000; } return false; } + #undef PARSE_FLOAT #undef PARSE_INT -float IESLoader::ExtractInR16F(Array& output) +float IESLoader::ExtractInR16(Array& output) { - uint32 width = GetWidth(); - uint32 height = GetHeight(); + const uint32 width = GetWidth(); + const uint32 height = GetHeight(); - ASSERT(output.IsEmpty()); + output.Clear(); output.Resize(width * height * sizeof(Half), false); Half* out = reinterpret_cast(output.Get()); - float invWidth = 1.0f / width; - float maxValue = ComputeMax(); - float invMaxValue = 1.0f / maxValue; + const float invWidth = 1.0f / (float)width; + float maxValue = _candalaValues[0]; + for (int32 i = 1; i < _candalaValues.Count(); i++) + maxValue = Math::Max(maxValue, _candalaValues[i]); + const float invMaxValue = 1.0f / maxValue; + const uint32 hAnglesCount = static_cast(_hAngles.Count()); for (uint32 y = 0; y < height; y++) { for (uint32 x = 0; x < width; x++) { - // 0..1 - float fraction = x * invWidth; - - // TODO: distort for better quality? eg. Fraction = Square(Fraction); - - float value = invMaxValue * Interpolate1D(fraction * 180.0f); - - *out++ = ConvertFloatToHalf(value); + const float vAngle = (float)x * invWidth * 180.0f; + const float v = ComputeFilterPos(vAngle, _vAngles); + float result = 0.0f; + for (uint32 i = 0; i < hAnglesCount; i++) + result += InterpolateBilinear(static_cast(i), v); + *out++ = ConvertFloatToHalf(invMaxValue * result / (float)hAnglesCount); } } - float integral = ComputeFullIntegral(); + float integral; + { + // Calculate integral using Monte Carlo + const int32 count = 500000; + const RandomStream randomStream(0x1234); + double sum = 0; + for (uint32 i = 0; i < count; i++) + { + const Vector3 v = randomStream.GetUnitVector(); + const float hAngle = Math::Acos(v.Z) / PI * 180; + const float vAngle = Math::Atan2(v.Y, v.X) / PI * 180 + 180; + sum += InterpolateBilinear(ComputeFilterPos(hAngle, _hAngles), ComputeFilterPos(vAngle, _vAngles)); + } + integral = static_cast(sum / count); + } return maxValue / integral; } -float IESLoader::InterpolatePoint(int32 X, int32 Y) const +float IESLoader::InterpolatePoint(int32 x, int32 y) const { - int32 HAnglesNum = _hAngles.Count(); - int32 VAnglesNum = _vAngles.Count(); - - ASSERT(X >= 0); - ASSERT(Y >= 0); - - X %= HAnglesNum; - Y %= VAnglesNum; - - ASSERT(X < HAnglesNum); - ASSERT(Y < VAnglesNum); - - return _candalaValues[Y + VAnglesNum * X]; + x %= _hAngles.Count(); + y %= _vAngles.Count(); + return _candalaValues[y + _vAngles.Count() * x]; } -float IESLoader::InterpolateBilinear(float fX, float fY) const +float IESLoader::InterpolateBilinear(float x, float y) const { - int32 X = static_cast(fX); - int32 Y = static_cast(fY); + const int32 xInt = static_cast(x); + const int32 yInt = static_cast(y); - float fracX = fX - X; - float fracY = fY - Y; + const float xFrac = x - xInt; + const float yFrac = y - yInt; - float p00 = InterpolatePoint(X + 0, Y + 0); - float p10 = InterpolatePoint(X + 1, Y + 0); - float p01 = InterpolatePoint(X + 0, Y + 1); - float p11 = InterpolatePoint(X + 1, Y + 1); + const float p00 = InterpolatePoint(xInt + 0, yInt + 0); + const float p10 = InterpolatePoint(xInt + 1, yInt + 0); + const float p01 = InterpolatePoint(xInt + 0, yInt + 1); + const float p11 = InterpolatePoint(xInt + 1, yInt + 1); - float p0 = Math::Lerp(p00, p01, fracY); - float p1 = Math::Lerp(p10, p11, fracY); + const float p0 = Math::Lerp(p00, p01, yFrac); + const float p1 = Math::Lerp(p10, p11, yFrac); - return Math::Lerp(p0, p1, fracX); -} - -float IESLoader::Interpolate2D(float HAngle, float VAngle) const -{ - float u = ComputeFilterPos(HAngle, _hAngles); - float v = ComputeFilterPos(VAngle, _vAngles); - - return InterpolateBilinear(u, v); -} - -float IESLoader::Interpolate1D(float VAngle) const -{ - float v = ComputeFilterPos(VAngle, _vAngles); - - float ret = 0.0f; - - uint32 HAnglesNum = static_cast(_hAngles.Count()); - - for (uint32 i = 0; i < HAnglesNum; i++) - { - ret += InterpolateBilinear(static_cast(i), v); - } - - return ret / HAnglesNum; -} - -float IESLoader::ComputeMax() const -{ - float result = 0.0f; - - for (int32 i = 0; i < _candalaValues.Count(); i++) - result = Math::Max(result, _candalaValues[i]); - - return result; -} - -float IESLoader::ComputeFullIntegral() -{ - // Compute only if needed - if (_cachedIntegral < 0) - { - // Monte carlo integration - // If quality is a problem we can improve on this algorithm or increase SampleCount - - // Larger number costs more time but improves quality - const int32 SamplesCount = 1000000; - - RandomStream randomStream(0x1234); - - double sum = 0; - for (uint32 i = 0; i < SamplesCount; i++) - { - Vector3 v = randomStream.GetUnitVector(); - - // http://en.wikipedia.org/wiki/Spherical_coordinate_system - - // 0..180 - float HAngle = Math::Acos(v.Z) / PI * 180; - // 0..360 - float VAngle = Math::Atan2(v.Y, v.X) / PI * 180 + 180; - - ASSERT(HAngle >= 0 && HAngle <= 180); - ASSERT(VAngle >= 0 && VAngle <= 360); - - sum += Interpolate2D(HAngle, VAngle); - } - - _cachedIntegral = static_cast(sum / SamplesCount); - } - - return _cachedIntegral; + return Math::Lerp(p0, p1, xFrac); } float IESLoader::ComputeFilterPos(float value, const Array& sortedValues) @@ -476,9 +309,9 @@ float IESLoader::ComputeFilterPos(float value, const Array& sortedValues) // Binary search while (startPos < endPos) { - uint32 testPos = (startPos + endPos + 1) / 2; + const uint32 testPos = (startPos + endPos + 1) / 2; - float testValue = sortedValues[testPos]; + const float testValue = sortedValues[testPos]; if (value >= testValue) { @@ -496,15 +329,15 @@ float IESLoader::ComputeFilterPos(float value, const Array& sortedValues) } } - float leftValue = sortedValues[startPos]; + const float leftValue = sortedValues[startPos]; float fraction = 0.0f; if (startPos + 1 < static_cast(sortedValues.Count())) { // If not at right border - float rightValue = sortedValues[startPos + 1]; - float deltaValue = rightValue - leftValue; + const float rightValue = sortedValues[startPos + 1]; + const float deltaValue = rightValue - leftValue; if (deltaValue > 0.0001f) { diff --git a/Source/Engine/Content/Utilities/IESLoader.h b/Source/Engine/Content/Utilities/IESLoader.h index 62a6b128a..f5c79f145 100644 --- a/Source/Engine/Content/Utilities/IESLoader.h +++ b/Source/Engine/Content/Utilities/IESLoader.h @@ -6,16 +6,13 @@ #include "Engine/Core/Collections/Array.h" /// -/// To load the IES file image format. IES files exist for many real world lights. The file stores how much light is emitted in a specific direction. -/// The data is usually measured but tools to paint IES files exist. +/// Utility for loading IES files and extract light emission information. /// class IESLoader { private: - float _brightness; - float _cachedIntegral; - + float _brightness = 0; Array _hAngles; Array _vAngles; Array _candalaValues; @@ -23,108 +20,39 @@ private: public: /// - /// Init + /// Loads the IES file. /// - IESLoader(); - -public: - - /// - /// Load IES file - /// - /// Buffer with data - /// True if cannot load, otherwise false - FORCE_INLINE bool Load(const Array& buffer) - { - return Load(buffer.Get()); - } - - /// - /// Load IES file - /// - /// Buffer with data - /// True if cannot load, otherwise false + /// The buffer with data. + /// True if cannot load, otherwise false. bool Load(const byte* buffer); + /// + /// Extracts IES profile data to R16 format (float). + /// + /// The result data container. + /// Thr multiplier as the texture is normalized. + float ExtractInR16(Array& output); + public: - /// - /// Gets width - /// - /// Width in pixels - FORCE_INLINE uint32 GetWidth() const + uint32 GetWidth() const { - // We use constant size return 256; } - /// - /// Gets height - /// - /// Height in pixels - FORCE_INLINE uint32 GetHeight() const + uint32 GetHeight() const { - // We use constant size return 1; } - /// - /// Gets IES profile brightness value in lumens (always > 0) - /// - /// Brightness (in lumens) - FORCE_INLINE float GetBrightness() const + float GetBrightness() const { return _brightness; } -public: +private: - /// - /// Extracts IES profile data to R16F format - /// - /// Result data container - /// Multiplier as the texture is normalized - float ExtractInR16F(Array& output); - -public: - - float InterpolatePoint(int32 X, int32 Y) const; - float InterpolateBilinear(float fX, float fY) const; - - /// - /// Compute the Candala value for a given direction - /// - /// HAngle (in degrees e.g. 0..180) - /// VAngle (in degrees e.g. 0..180) - /// Sampled value - float Interpolate2D(float HAngle, float VAngle) const; - - /// - /// Compute the Candala value for a given direction (integrates over HAngle) - /// - /// VAngle (in degrees e.g. 0..180) - /// Sampled value - float Interpolate1D(float VAngle) const; - -public: - - /// - /// Calculates maximum value - /// - /// Maximum value - float ComputeMax() const; - - /// - /// Integrate over the unit sphere - /// - /// Integral value - float ComputeFullIntegral(); - - /// - /// Computes filtering position for given value in sorted set of values - /// - /// Value to find - /// Value to use - /// Filter position + float InterpolatePoint(int32 x, int32 y) const; + float InterpolateBilinear(float x, float y) const; static float ComputeFilterPos(float value, const Array& sortedValues); }; diff --git a/Source/Engine/ContentImporters/ImportTexture.cpp b/Source/Engine/ContentImporters/ImportTexture.cpp index f63624c61..3fd0c92ce 100644 --- a/Source/Engine/ContentImporters/ImportTexture.cpp +++ b/Source/Engine/ContentImporters/ImportTexture.cpp @@ -528,14 +528,14 @@ CreateAssetResult ImportTexture::ImportIES(class CreateAssetContext& context) // Load IES profile data IESLoader loader; - if (loader.Load(fileData)) + if (loader.Load(fileData.Get())) { return CreateAssetResult::Error; } // Extract texture data Array rawData; - const float multiplier = loader.ExtractInR16F(rawData); + const float multiplier = loader.ExtractInR16(rawData); // Fill texture header TextureHeader textureHeader; diff --git a/Source/Engine/Core/Math/Color.cpp b/Source/Engine/Core/Math/Color.cpp index 9ec561b25..86e7719e4 100644 --- a/Source/Engine/Core/Math/Color.cpp +++ b/Source/Engine/Core/Math/Color.cpp @@ -70,23 +70,21 @@ Color Color::FromHex(const String& hexString, bool& isValid) return FromBytes(r, g, b, a); } -Color Color::FromHSV(const Vector3& hsv) +Color Color::FromHSV(float hue, float saturation, float value, float alpha) { - const float Hue = hsv.X; - const float Saturation = hsv.Y; - const float Value = hsv.Z; + const float hDiv60 = hue / 60.0f; + const float hDiv60Floor = Math::Floor(hDiv60); + const float hDiv60Fraction = hDiv60 - hDiv60Floor; - const float HDiv60 = Hue / 60.0f; - const float HDiv60_Floor = floorf(HDiv60); - const float HDiv60_Fraction = HDiv60 - HDiv60_Floor; - - const float RGBValues[4] = { - Value, - Value * (1.0f - Saturation), - Value * (1.0f - HDiv60_Fraction * Saturation), - Value * (1.0f - (1.0f - HDiv60_Fraction) * Saturation), + const float rgbValues[4] = + { + value, + value * (1.0f - saturation), + value * (1.0f - hDiv60Fraction * saturation), + value * (1.0f - (1.0f - hDiv60Fraction) * saturation), }; - const uint32 RGBSwizzle[6][3] = { + const int32 rgbSwizzle[6][3] + { { 0, 3, 1 }, { 2, 0, 1 }, { 1, 0, 3 }, @@ -94,12 +92,17 @@ Color Color::FromHSV(const Vector3& hsv) { 3, 1, 0 }, { 0, 1, 2 }, }; - const uint32 SwizzleIndex = (uint32)HDiv60_Floor % 6; + const int32 swizzleIndex = (int32)hDiv60Floor % 6; - return Color(RGBValues[RGBSwizzle[SwizzleIndex][0]], - RGBValues[RGBSwizzle[SwizzleIndex][1]], - RGBValues[RGBSwizzle[SwizzleIndex][2]], - 1.0f); + return Color(rgbValues[rgbSwizzle[swizzleIndex][0]], + rgbValues[rgbSwizzle[swizzleIndex][1]], + rgbValues[rgbSwizzle[swizzleIndex][2]], + alpha); +} + +Color Color::FromHSV(const Vector3& hsv, float alpha) +{ + return FromHSV(hsv.X, hsv.Y, hsv.Z, alpha); } Color Color::Random() diff --git a/Source/Engine/Core/Math/Color.cs b/Source/Engine/Core/Math/Color.cs index 69565bf11..44e6246ce 100644 --- a/Source/Engine/Core/Math/Color.cs +++ b/Source/Engine/Core/Math/Color.cs @@ -516,7 +516,7 @@ namespace FlaxEngine } /// - /// Creates RGB color from Hue[0-360], Saturation[0-1] and Value[0-1] paked to XYZ vector. + /// Creates RGB color from Hue[0-360], Saturation[0-1] and Value[0-1] packed to XYZ vector. /// /// The HSV color. /// The alpha value. Default is 1. diff --git a/Source/Engine/Core/Math/Color.h b/Source/Engine/Core/Math/Color.h index 84c68f411..30e40cc1d 100644 --- a/Source/Engine/Core/Math/Color.h +++ b/Source/Engine/Core/Math/Color.h @@ -152,12 +152,23 @@ public: static Color FromHex(const String& hexString, bool& isValid); + /// + /// Creates RGB color from Hue[0-360], Saturation[0-1] and Value[0-1]. + /// + /// The hue angle in degrees [0-360]. + /// The saturation normalized [0-1]. + /// The value normalized [0-1]. + /// The alpha value. Default is 1. + /// The RGB color. + static Color FromHSV(float hue, float saturation, float value, float alpha = 1.0f); + /// /// Creates RGB color from Hue[0-360], Saturation[0-1] and Value[0-1] packed to XYZ vector. /// /// The HSV color. + /// The alpha value. Default is 1. /// The RGB color. - static Color FromHSV(const Vector3& hsv); + static Color FromHSV(const Vector3& hsv, float alpha = 1.0f); /// /// Gets random color with opaque alpha. diff --git a/Source/Engine/Core/Math/Math.cpp b/Source/Engine/Core/Math/Math.cpp index bd08d8d0f..8fcde780e 100644 --- a/Source/Engine/Core/Math/Math.cpp +++ b/Source/Engine/Core/Math/Math.cpp @@ -3,6 +3,46 @@ #include "Math.h" #include "Vector3.h" +void Math::SinCos(float angle, float& sine, float& cosine) +{ + sine = sin(angle); + cosine = cos(angle); +} + +uint32 Math::FloorLog2(uint32 value) +{ + // References: + // http://codinggorilla.domemtech.com/?p=81 + // http://en.wikipedia.org/wiki/Binary_logarithm + + uint32 pos = 0; + if (value >= 1 << 16) + { + value >>= 16; + pos += 16; + } + if (value >= 1 << 8) + { + value >>= 8; + pos += 8; + } + if (value >= 1 << 4) + { + value >>= 4; + pos += 4; + } + if (value >= 1 << 2) + { + value >>= 2; + pos += 2; + } + if (value >= 1 << 1) + { + pos += 1; + } + return value == 0 ? 0 : pos; +} + Vector3 Math::RotateAboutAxis(const Vector3& normalizedRotationAxis, float angle, const Vector3& positionOnAxis, const Vector3& position) { // Project position onto the rotation axis and find the closest point on the axis to Position diff --git a/Source/Engine/Core/Math/Math.h b/Source/Engine/Core/Math/Math.h index 3035e213f..2925ec1ae 100644 --- a/Source/Engine/Core/Math/Math.h +++ b/Source/Engine/Core/Math/Math.h @@ -18,10 +18,10 @@ #define ZeroTolerance 1e-6f // Converts radians to degrees. -#define RadiansToDegrees (180.f / PI) +#define RadiansToDegrees (180.0f / PI) // Converts degrees to radians. -#define DegreesToRadians (PI / 180.f) +#define DegreesToRadians (PI / 180.0f) namespace Math { @@ -31,97 +31,14 @@ namespace Math /// The input angle (in radians). /// The output sine value. /// The output cosine value. - static void SinCos(float angle, float& sine, float& cosine) - { -#if 1 - // Map value to y in [-pi,pi], x = 2*pi*quotient + remainder - float quotient = PI_INV * 0.5f * angle; - if (angle >= 0.0f) - { - quotient = (float)(int)(quotient + 0.5f); - } - else - { - quotient = (float)(int)(quotient - 0.5f); - } - float y = angle - 2.0f * PI * quotient; - - // Map y to [-pi/2,pi/2] with sin(y) = sin(value) - float sign; - if (y > PI_OVER_2) - { - y = PI - y; - sign = -1.0f; - } - else if (y < -PI_OVER_2) - { - y = -PI - y; - sign = -1.0f; - } - else - { - sign = +1.0f; - } - - const float y2 = y * y; - - // 11-degree minimax approximation - sine = (((((-2.3889859e-08f * y2 + 2.7525562e-06f) * y2 - 0.00019840874f) * y2 + 0.0083333310f) * y2 - 0.16666667f) * y2 + 1.0f) * y; - - // 10-degree minimax approximation - const float p = ((((-2.6051615e-07f * y2 + 2.4760495e-05f) * y2 - 0.0013888378f) * y2 + 0.041666638f) * y2 - 0.5f) * y2 + 1.0f; - cosine = sign * p; -#else - sine = sin(angle); - cosine = cos(angle); -#endif - } + FLAXENGINE_API void SinCos(float angle, float& sine, float& cosine); /// /// Computes the base 2 logarithm for an integer value that is greater than 0. The result is rounded down to the nearest integer. /// /// The value to compute the log of. /// The Log2 of value. 0 if value is 0. - static uint32 FloorLog2(uint32 value) - { - // Reference implementation - // uint32 bit = 32; - // for (; bit > 0;) - // { - // bit--; - // if (value & (1 << bit)) - // break; - // } - // return bit; - - // Optimized version http://codinggorilla.domemtech.com/?p=81 or http://en.wikipedia.org/wiki/Binary_logarithm but modified to return 0 for a input value of 0 - uint32 pos = 0; - if (value >= 1 << 16) - { - value >>= 16; - pos += 16; - } - if (value >= 1 << 8) - { - value >>= 8; - pos += 8; - } - if (value >= 1 << 4) - { - value >>= 4; - pos += 4; - } - if (value >= 1 << 2) - { - value >>= 2; - pos += 2; - } - if (value >= 1 << 1) - { - pos += 1; - } - return value == 0 ? 0 : pos; - } + FLAXENGINE_API uint32 FloorLog2(uint32 value); static FORCE_INLINE float Trunc(float value) { @@ -712,68 +629,38 @@ namespace Math static float ClampAxis(float angle) { - // returns angle in the range (-360,360) angle = Mod(angle, 360.f); - - if (angle < 0.f) - { - // shift to [0,360) range - angle += 360.f; - } - + if (angle < 0.0f) + angle += 360.0f; return angle; } static float NormalizeAxis(float angle) { - // returns angle in the range [0,360) angle = ClampAxis(angle); - if (angle > 180.f) - { - // shift to (-180,180] angle -= 360.f; - } - return angle; } // Find the smallest angle between two headings (in radians). static float FindDeltaAngle(float a1, float a2) { - // Find the difference - float Delta = a2 - a1; - - // If change is larger than PI - if (Delta > PI) - { - // Flip to negative equivalent - Delta = Delta - PI * 2.0f; - } - else if (Delta < -PI) - { - // Otherwise, if change is smaller than -PI - // Flip to positive equivalent - Delta = Delta + PI * 2.0f; - } - - // Return delta in [-PI,PI] range - return Delta; + float delta = a2 - a1; + if (delta > PI) + delta = delta - PI * 2.0f; + else if (delta < -PI) + delta = delta + PI * 2.0f; + return delta; } // Given a heading which may be outside the +/- PI range, 'unwind' it back into that range static float UnwindRadians(float a) { while (a > PI) - { a -= (float)PI * 2.0f; - } - while (a < -PI) - { a += (float)PI * 2.0f; - } - return a; } @@ -781,15 +668,9 @@ namespace Math static float UnwindDegrees(float a) { while (a > 180.f) - { a -= 360.f; - } - while (a < -180.f) - { a += 360.f; - } - return a; } @@ -818,13 +699,9 @@ namespace Math static float SmoothStep(float a, float b, float x) { if (x < a) - { return 0.0f; - } if (x >= b) - { return 1.0f; - } const float fraction = (x - a) / (b - a); return fraction * fraction * (3.0f - 2.0f * fraction); } @@ -852,8 +729,8 @@ namespace Math template static FORCE_INLINE T InterpEaseIn(const T& a, const T& b, float alpha, float exponent) { - float const modifiedAlpha = Pow(alpha, exponent); - return Lerp(a, b, modifiedAlpha); + const float blend = Pow(alpha, exponent); + return Lerp(a, b, blend); } /// @@ -862,8 +739,8 @@ namespace Math template static FORCE_INLINE T InterpEaseOut(const T& a, const T& b, float alpha, float exponent) { - float const modifiedAlpha = 1.f - Pow(1.f - alpha, exponent); - return Lerp(a, b, modifiedAlpha); + const float blend = 1.f - Pow(1.f - alpha, exponent); + return Lerp(a, b, blend); } /// @@ -881,8 +758,8 @@ namespace Math template static FORCE_INLINE T InterpSinIn(const T& a, const T& b, float alpha) { - float const modifiedAlpha = -1.f * Cos(alpha * PI_HALF) + 1.f; - return Lerp(a, b, modifiedAlpha); + const float blend = -1.f * Cos(alpha * PI_HALF) + 1.f; + return Lerp(a, b, blend); } /// @@ -891,8 +768,8 @@ namespace Math template static FORCE_INLINE T InterpSinOut(const T& a, const T& b, float alpha) { - float const modifiedAlpha = Sin(alpha * PI_HALF); - return Lerp(a, b, modifiedAlpha); + const float blend = Sin(alpha * PI_HALF); + return Lerp(a, b, blend); } /// @@ -910,8 +787,8 @@ namespace Math template static FORCE_INLINE T InterpExpoIn(const T& a, const T& b, float alpha) { - float const modifiedAlpha = alpha == 0.f ? 0.f : Pow(2.f, 10.f * (alpha - 1.f)); - return Lerp(a, b, modifiedAlpha); + const float blend = alpha == 0.f ? 0.f : Pow(2.f, 10.f * (alpha - 1.f)); + return Lerp(a, b, blend); } /// @@ -920,8 +797,8 @@ namespace Math template static FORCE_INLINE T InterpExpoOut(const T& a, const T& b, float alpha) { - float const modifiedAlpha = alpha == 1.f ? 1.f : -Pow(2.f, -10.f * alpha) + 1.f; - return Lerp(a, b, modifiedAlpha); + const float blend = alpha == 1.f ? 1.f : -Pow(2.f, -10.f * alpha) + 1.f; + return Lerp(a, b, blend); } /// @@ -939,8 +816,8 @@ namespace Math template static FORCE_INLINE T InterpCircularIn(const T& a, const T& b, float alpha) { - float const modifiedAlpha = -1.f * (Sqrt(1.f - alpha * alpha) - 1.f); - return Lerp(a, b, modifiedAlpha); + const float blend = -1.f * (Sqrt(1.f - alpha * alpha) - 1.f); + return Lerp(a, b, blend); } /// @@ -950,8 +827,8 @@ namespace Math static FORCE_INLINE T InterpCircularOut(const T& a, const T& b, float alpha) { alpha -= 1.f; - float const modifiedAlpha = Sqrt(1.f - alpha * alpha); - return Lerp(a, b, modifiedAlpha); + const float blend = Sqrt(1.f - alpha * alpha); + return Lerp(a, b, blend); } /// diff --git a/Source/Engine/Core/Math/Packed.cpp b/Source/Engine/Core/Math/Packed.cpp index 47e5da45f..f611e29e6 100644 --- a/Source/Engine/Core/Math/Packed.cpp +++ b/Source/Engine/Core/Math/Packed.cpp @@ -63,6 +63,8 @@ Vector3 Float1010102::ToVector3() const FloatR11G11B10::FloatR11G11B10(float x, float y, float z) { + // Reference: https://github.com/microsoft/DirectXMath + uint32 iValue[4]; iValue[0] = *(uint32*)&x; iValue[1] = *(uint32*)&y; @@ -197,6 +199,8 @@ FloatR11G11B10::operator Vector3() const Vector3 FloatR11G11B10::ToVector3() const { + // Reference: https://github.com/microsoft/DirectXMath + uint32 result[4]; uint32 mantissa; uint32 exponent; diff --git a/Source/Engine/Core/Math/Quaternion.cpp b/Source/Engine/Core/Math/Quaternion.cpp index 7a9a51c79..60573ffb5 100644 --- a/Source/Engine/Core/Math/Quaternion.cpp +++ b/Source/Engine/Core/Math/Quaternion.cpp @@ -360,8 +360,8 @@ void Quaternion::FindBetween(const Vector3& from, const Vector3& to, Quaternion& if (w < 1.e-6f * normFromNormTo) { result = Math::Abs(from.X) > Math::Abs(from.Z) - ? Quaternion(-from.Y, from.X, 0.f, 0.f) - : Quaternion(0.f, -from.Z, from.Y, 0.f); + ? Quaternion(-from.Y, from.X, 0.0f, 0.0f) + : Quaternion(0.0f, -from.Z, from.Y, 0.0f); } else { diff --git a/Source/Engine/Core/Math/Vector3.cpp b/Source/Engine/Core/Math/Vector3.cpp index 58ca08aa3..378fcd91a 100644 --- a/Source/Engine/Core/Math/Vector3.cpp +++ b/Source/Engine/Core/Math/Vector3.cpp @@ -311,39 +311,32 @@ void Vector3::Unproject(const Vector3& vector, float x, float y, float width, fl void Vector3::CreateOrthonormalBasis(Vector3& xAxis, Vector3& yAxis, Vector3& zAxis) { - // Project the X and Y axes onto the plane perpendicular to the Z axis. xAxis -= (xAxis | zAxis) / (zAxis | zAxis) * zAxis; yAxis -= (yAxis | zAxis) / (zAxis | zAxis) * zAxis; - // If the X axis was parallel to the Z axis, choose a vector which is orthogonal to the Y and Z axes. if (xAxis.LengthSquared() < ZeroTolerance) - { xAxis = yAxis ^ zAxis; - } - - // If the Y axis was parallel to the Z axis, choose a vector which is orthogonal to the X and Z axes. if (yAxis.LengthSquared() < ZeroTolerance) - { yAxis = xAxis ^ zAxis; - } - // Normalize the basis vectors. xAxis.Normalize(); yAxis.Normalize(); zAxis.Normalize(); } -void Vector3::FindBestAxisVectors(Vector3& Axis1, Vector3& Axis2) const +void Vector3::FindBestAxisVectors(Vector3& firstAxis, Vector3& secondAxis) const { const float absX = Math::Abs(X); const float absY = Math::Abs(Y); const float absZ = Math::Abs(Z); + if (absZ > absX && absZ > absY) - Axis1 = Vector3(1, 0, 0); + firstAxis = Vector3(1, 0, 0); else - Axis1 = Vector3(0, 0, 1); - Axis1 = (Axis1 - *this * (Axis1 | *this)).GetNormalized(); - Axis2 = Axis1 ^ *this; + firstAxis = Vector3(0, 0, 1); + + firstAxis = (firstAxis - *this * (firstAxis | *this)).GetNormalized(); + secondAxis = firstAxis ^ *this; } float Vector3::TriangleArea(const Vector3& v0, const Vector3& v1, const Vector3& v2) diff --git a/Source/Engine/Core/Math/Vector3.h b/Source/Engine/Core/Math/Vector3.h index 09d14f5dd..3dafde389 100644 --- a/Source/Engine/Core/Math/Vector3.h +++ b/Source/Engine/Core/Math/Vector3.h @@ -866,9 +866,9 @@ public: /// /// Finds the best arbitrary axis vectors to represent U and V axes of a plane, by using this vector as the normal of the plane. /// - /// The reference to first axis. - /// The reference to second axis. - void FindBestAxisVectors(Vector3& Axis1, Vector3& Axis2) const; + /// The reference to first axis. + /// The reference to second axis. + void FindBestAxisVectors(Vector3& firstAxis, Vector3& secondAxis) const; static Vector3 Round(const Vector3& v) { diff --git a/Source/Engine/Core/RandomStream.h b/Source/Engine/Core/RandomStream.h index 2e88f2e2f..c3b4430a7 100644 --- a/Source/Engine/Core/RandomStream.h +++ b/Source/Engine/Core/RandomStream.h @@ -138,9 +138,9 @@ public: float l; do { - result.X = GetFraction() * 2.f - 1.f; - result.Y = GetFraction() * 2.f - 1.f; - result.Z = GetFraction() * 2.f - 1.f; + result.X = GetFraction() * 2.0f - 1.0f; + result.Y = GetFraction() * 2.0f - 1.0f; + result.Z = GetFraction() * 2.0f - 1.0f; l = result.LengthSquared(); } while (l > 1.0f || l < ZeroTolerance); return Vector3::Normalize(result); diff --git a/Source/Engine/Core/Types/DateTime.cpp b/Source/Engine/Core/Types/DateTime.cpp index 7b68c3747..a5166f5cc 100644 --- a/Source/Engine/Core/Types/DateTime.cpp +++ b/Source/Engine/Core/Types/DateTime.cpp @@ -6,8 +6,8 @@ #include "Engine/Platform/Platform.h" #include "Engine/Core/Math/Math.h" -const int32 DateTime::DaysPerMonth[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; -const int32 DateTime::DaysToMonth[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; +const int32 DateTime::CachedDaysPerMonth[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; +const int32 DateTime::CachedDaysToMonth[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; DateTime::DateTime(int32 year, int32 month, int32 day, int32 hour, int32 minute, int32 second, int32 millisecond) { @@ -17,7 +17,7 @@ DateTime::DateTime(int32 year, int32 month, int32 day, int32 hour, int32 minute, totalDays++; year--; month--; - totalDays += year * 365 + year / 4 - year / 100 + year / 400 + DaysToMonth[month] + day - 1; + totalDays += year * 365 + year / 4 - year / 100 + year / 400 + CachedDaysToMonth[month] + day - 1; Ticks = totalDays * Constants::TicksPerDay + hour * Constants::TicksPerHour + minute * Constants::TicksPerMinute @@ -27,7 +27,7 @@ DateTime::DateTime(int32 year, int32 month, int32 day, int32 hour, int32 minute, void DateTime::GetDate(int32& year, int32& month, int32& day) const { - // Based on FORTRAN code in: + // Based on: // Fliegel, H. F. and van Flandern, T. C., // Communications of the ACM, Vol. 11, No. 10 (October 1968). @@ -98,7 +98,7 @@ int32 DateTime::DaysInMonth(int32 year, int32 month) ASSERT_LOW_LAYER((month >= 1) && (month <= 12)); if (month == 2 && IsLeapYear(year)) return 29; - return DaysPerMonth[month]; + return CachedDaysPerMonth[month]; } int32 DateTime::DaysInYear(int32 year) diff --git a/Source/Engine/Core/Types/DateTime.h b/Source/Engine/Core/Types/DateTime.h index 03b71a433..e017d0fc7 100644 --- a/Source/Engine/Core/Types/DateTime.h +++ b/Source/Engine/Core/Types/DateTime.h @@ -23,8 +23,8 @@ API_STRUCT(InBuild, Namespace="System") struct FLAXENGINE_API DateTime { private: - static const int32 DaysPerMonth[]; - static const int32 DaysToMonth[]; + static const int32 CachedDaysPerMonth[]; + static const int32 CachedDaysToMonth[]; public: diff --git a/Source/Engine/Core/Types/String.h b/Source/Engine/Core/Types/String.h index da8bbc3ad..67c6326fb 100644 --- a/Source/Engine/Core/Types/String.h +++ b/Source/Engine/Core/Types/String.h @@ -417,27 +417,23 @@ public: int32 Replace(const T* searchText, const T* replacementText, StringSearchCase searchCase = StringSearchCase::CaseSensitive) { - int32 replacementCount = 0; - - if (HasChars() - && searchText != nullptr && *searchText != 0 - && replacementText != nullptr && (searchCase == StringSearchCase::IgnoreCase || StringUtils::Compare(searchText, replacementText) != 0)) + int32 replacedCount = 0; + if (HasChars() && searchText && *searchText && replacementText && (searchCase == StringSearchCase::IgnoreCase || StringUtils::Compare(searchText, replacementText) != 0)) { - const int32 numCharsToReplace = StringUtils::Length(searchText); - const int32 numCharsToInsert = StringUtils::Length(replacementText); - - if (numCharsToInsert == numCharsToReplace) + const int32 searchTextLength = StringUtils::Length(searchText); + const int32 replacementTextLength = StringUtils::Length(replacementText); + if (searchTextLength == replacementTextLength) { T* pos = (T*)(searchCase == StringSearchCase::IgnoreCase ? StringUtils::FindIgnoreCase(_data, searchText) : StringUtils::Find(_data, searchText)); while (pos != nullptr) { - replacementCount++; + replacedCount++; - for (int32 i = 0; i < numCharsToInsert; i++) + for (int32 i = 0; i < replacementTextLength; i++) pos[i] = replacementText[i]; - if (pos + numCharsToReplace - **this < Length()) - pos = (T*)(searchCase == StringSearchCase::IgnoreCase ? StringUtils::FindIgnoreCase(pos + numCharsToReplace, searchText) : StringUtils::Find(pos + numCharsToReplace, searchText)); + if (pos + searchTextLength - **this < Length()) + pos = (T*)(searchCase == StringSearchCase::IgnoreCase ? StringUtils::FindIgnoreCase(pos + searchTextLength, searchText) : StringUtils::Find(pos + searchTextLength, searchText)); else break; } @@ -448,14 +444,14 @@ public: T* searchPosition = (T*)(searchCase == StringSearchCase::IgnoreCase ? StringUtils::FindIgnoreCase(readPosition, searchText) : StringUtils::Find(readPosition, searchText)); while (searchPosition != nullptr) { - replacementCount++; - readPosition = searchPosition + numCharsToReplace; + replacedCount++; + readPosition = searchPosition + searchTextLength; searchPosition = (T*)(searchCase == StringSearchCase::IgnoreCase ? StringUtils::FindIgnoreCase(readPosition, searchText) : StringUtils::Find(readPosition, searchText)); } const auto oldLength = _length; const auto oldData = _data; - _length += replacementCount * (numCharsToInsert - numCharsToReplace); + _length += replacedCount * (replacementTextLength - searchTextLength); _data = (T*)Platform::Allocate((_length + 1) * sizeof(T), 16); T* writePosition = _data; @@ -467,10 +463,10 @@ public: Platform::MemoryCopy(writePosition, readPosition, writeOffset * sizeof(T)); writePosition += writeOffset; - Platform::MemoryCopy(writePosition, replacementText, numCharsToInsert * sizeof(T)); - writePosition += numCharsToInsert; + Platform::MemoryCopy(writePosition, replacementText, replacementTextLength * sizeof(T)); + writePosition += replacementTextLength; - readPosition = searchPosition + numCharsToReplace; + readPosition = searchPosition + searchTextLength; searchPosition = (T*)(searchCase == StringSearchCase::IgnoreCase ? StringUtils::FindIgnoreCase(readPosition, searchText) : StringUtils::Find(readPosition, searchText)); } @@ -482,7 +478,7 @@ public: } } - return replacementCount; + return replacedCount; } /// diff --git a/Source/Engine/Graphics/GPUResourceState.h b/Source/Engine/Graphics/GPUResourceState.h index 072b54cde..8e485ed68 100644 --- a/Source/Engine/Graphics/GPUResourceState.h +++ b/Source/Engine/Graphics/GPUResourceState.h @@ -47,7 +47,6 @@ public: ASSERT(_subresourceState.IsEmpty() && subresourceCount > 0); // Allocate space for per-subresource tracking structures - // Note: for resources with single subresource we don't use this table if (usePerSubresourceTracking && subresourceCount > 1) _subresourceState.Resize(subresourceCount, false); @@ -87,9 +86,8 @@ public: return state == _resourceState; } - // All subresources must be individually checked - const uint32 numSubresourceStates = _subresourceState.Count(); - for (uint32 i = 0; i < numSubresourceStates; i++) + // Check all subresources + for (int32 i = 0; i < _subresourceState.Count(); i++) { if (_subresourceState[i] != state) { @@ -116,10 +114,8 @@ public: _allSubresourcesSame = 1; _resourceState = state; - // State is now tracked per-resource, so _subresourceState should not be read #if BUILD_DEBUG - const uint32 numSubresourceStates = _subresourceState.Count(); - for (uint32 i = 0; i < numSubresourceStates; i++) + for (int32 i = 0; i < _subresourceState.Count(); i++) { _subresourceState[i] = InvalidState; } @@ -140,15 +136,13 @@ public: // If state was previously tracked on a per-resource level, then transition to per-subresource tracking if (_allSubresourcesSame) { - const int32 numSubresourceStates = _subresourceState.Count(); - for (int32 i = 0; i < numSubresourceStates; i++) + for (int32 i = 0; i < _subresourceState.Count(); i++) { _subresourceState[i] = _resourceState; } _allSubresourcesSame = 0; - // State is now tracked per-subresource, so _resourceState should not be read #if BUILD_DEBUG _resourceState = InvalidState; #endif diff --git a/Source/Engine/Graphics/Models/ModelData.Tool.cpp b/Source/Engine/Graphics/Models/ModelData.Tool.cpp index 814e0d4ba..d6149be25 100644 --- a/Source/Engine/Graphics/Models/ModelData.Tool.cpp +++ b/Source/Engine/Graphics/Models/ModelData.Tool.cpp @@ -94,7 +94,7 @@ bool MeshData::GenerateLightmapUVs() // Generate UVs std::vector vb; std::vector ib; - float outStretch = 0.f; + float outStretch = 0.0f; size_t outCharts = 0; std::vector facePartitioning; std::vector vertexRemapArray; diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp index ef9fbd6c9..1d983a036 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp @@ -144,23 +144,17 @@ void GPUContextDX12::SetResourceState(ResourceOwnerDX12* resource, D3D12_RESOURC auto& state = resource->State; if (subresourceIndex == D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES && !state.AreAllSubresourcesSame()) { - // Slow path. Want to transition the entire resource (with multiple subresources). But they aren't in the same state. - + // Slow path because we have to transition the entire resource with multiple subresources that aren't in the same state const uint32 subresourceCount = resource->GetSubresourcesCount(); for (uint32 i = 0; i < subresourceCount; i++) { const D3D12_RESOURCE_STATES before = state.GetSubresourceState(i); - - // We're not using IsTransitionNeeded() because we do want to transition even if 'after' is a subset of 'before' - // This is so that we can ensure all subresources are in the same state, simplifying future barriers if (before != after) { AddTransitionBarrier(resource, before, after, i); state.SetSubresourceState(i, after); } } - - // The entire resource should now be in the after state on this command list ASSERT(state.CheckResourceState(after)); state.SetResourceState(after); } diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.h b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.h index abaa229b6..aea22eae9 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.h @@ -172,12 +172,8 @@ public: { if (sampleCount <= 8) { - // 0 has better quality (a more even distribution) - // Higher quality levels might be useful for non box filtered AA or when using weighted samples. return 0; } - - // Not supported. return 0xffffffff; } @@ -187,7 +183,7 @@ public: #endif private: - + #if PLATFORM_XBOX_SCARLETT void updateFrameEvents(); #endif diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/ResourceOwnerDX12.h b/Source/Engine/GraphicsDevice/DirectX/DX12/ResourceOwnerDX12.h index 14e25bc85..82e52d7de 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/ResourceOwnerDX12.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/ResourceOwnerDX12.h @@ -33,14 +33,11 @@ public: /// Returns true if resource state transition is needed in order to use resource in given state. /// /// The current resource state. - /// the destination resource state. + /// the destination resource state. /// True if need to perform a transition, otherwise false. - static bool IsTransitionNeeded(D3D12_RESOURCE_STATES currentState, D3D12_RESOURCE_STATES targeState) + static bool IsTransitionNeeded(D3D12_RESOURCE_STATES currentState, D3D12_RESOURCE_STATES targetState) { - // If 'targeState' is a subset of 'before', then there's no need for a transition - // Note: COMMON is an oddball state that doesn't follow the RESOURE_STATE pattern of - // having exactly one bit set so we need to special case these - return currentState != targeState && ((currentState | targeState) != currentState || targeState == D3D12_RESOURCE_STATE_COMMON); + return currentState != targetState && ((currentState | targetState) != currentState || targetState == D3D12_RESOURCE_STATE_COMMON); } }; diff --git a/Source/Engine/GraphicsDevice/DirectX/GPUDeviceDX.h b/Source/Engine/GraphicsDevice/DirectX/GPUDeviceDX.h index 818dd0aeb..bd9250d38 100644 --- a/Source/Engine/GraphicsDevice/DirectX/GPUDeviceDX.h +++ b/Source/Engine/GraphicsDevice/DirectX/GPUDeviceDX.h @@ -267,43 +267,33 @@ protected: // [GPUDevice] bool Init() override { - // Cache adapter description const DXGI_ADAPTER_DESC& adapterDesc = _adapter->Description; const uint64 dedicatedVideoMemory = static_cast(adapterDesc.DedicatedVideoMemory); const uint64 dedicatedSystemMemory = static_cast(adapterDesc.DedicatedSystemMemory); const uint64 sharedSystemMemory = static_cast(adapterDesc.SharedSystemMemory); - // Total amount of system memory clamped to 8 GB - const uint64 totalPhysicalMemory = Math::Min(Platform::GetMemoryStats().TotalPhysicalMemory, 8Ull * 1024Ull * 1024Ull * 1024Ull); - - // Consider 50% of the shared memory but max 25% of total system memory - const uint64 consideredSharedSystemMemory = Math::Min(sharedSystemMemory / 2Ull, totalPhysicalMemory / 4Ull); - // Calculate total GPU memory + const uint64 totalPhysicalMemory = Math::Min(Platform::GetMemoryStats().TotalPhysicalMemory, 16Ull * 1024Ull * 1024Ull * 1024Ull); + const uint64 totalSystemMemory = Math::Min(sharedSystemMemory / 2Ull, totalPhysicalMemory / 4Ull); TotalGraphicsMemory = 0; if (_adapter->IsIntel()) { - // Use total memory for integrated cards - TotalGraphicsMemory = dedicatedVideoMemory + dedicatedSystemMemory + consideredSharedSystemMemory; + TotalGraphicsMemory = dedicatedVideoMemory + dedicatedSystemMemory + totalSystemMemory; } else if (dedicatedVideoMemory >= 200 * 1024 * 1024) { - // Use dedicated video memory, if it's more than 200 MB TotalGraphicsMemory = dedicatedVideoMemory; } else if (dedicatedSystemMemory >= 200 * 1024 * 1024) { - // Use dedicated system memory, if it's more than 200 MB TotalGraphicsMemory = dedicatedSystemMemory; } else if (sharedSystemMemory >= 400 * 1024 * 1024) { - // Use some shared system memory, if it's more than 400 MB - TotalGraphicsMemory = consideredSharedSystemMemory; + TotalGraphicsMemory = totalSystemMemory; } else { - // Otherwise consider 25% of total system memory for graphics TotalGraphicsMemory = totalPhysicalMemory / 4Ull; } diff --git a/Source/Engine/GraphicsDevice/Vulkan/Android/AndroidVulkanPlatform.cpp b/Source/Engine/GraphicsDevice/Vulkan/Android/AndroidVulkanPlatform.cpp index fceee64ed..5a5543100 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/Android/AndroidVulkanPlatform.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/Android/AndroidVulkanPlatform.cpp @@ -5,25 +5,25 @@ #include "AndroidVulkanPlatform.h" #include "../RenderToolsVulkan.h" -void AndroidVulkanPlatform::GetInstanceExtensions(Array& outExtensions) +void AndroidVulkanPlatform::GetInstanceExtensions(Array& extensions) { - outExtensions.Add(VK_KHR_SURFACE_EXTENSION_NAME); - outExtensions.Add(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME); + extensions.Add(VK_KHR_SURFACE_EXTENSION_NAME); + extensions.Add(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME); } -void AndroidVulkanPlatform::GetDeviceExtensions(Array& outExtensions) +void AndroidVulkanPlatform::GetDeviceExtensions(Array& extensions) { - outExtensions.Add(VK_KHR_SURFACE_EXTENSION_NAME); - outExtensions.Add(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME); + extensions.Add(VK_KHR_SURFACE_EXTENSION_NAME); + extensions.Add(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME); } -void AndroidVulkanPlatform::CreateSurface(void* windowHandle, VkInstance instance, VkSurfaceKHR* outSurface) +void AndroidVulkanPlatform::CreateSurface(void* windowHandle, VkInstance instance, VkSurfaceKHR* surface) { ASSERT(windowHandle); VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo; RenderToolsVulkan::ZeroStruct(surfaceCreateInfo, VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR); surfaceCreateInfo.window = (struct ANativeWindow*)windowHandle; - VALIDATE_VULKAN_RESULT(vkCreateAndroidSurfaceKHR(instance, &surfaceCreateInfo, nullptr, outSurface)); + VALIDATE_VULKAN_RESULT(vkCreateAndroidSurfaceKHR(instance, &surfaceCreateInfo, nullptr, surface)); } #endif diff --git a/Source/Engine/GraphicsDevice/Vulkan/Android/AndroidVulkanPlatform.h b/Source/Engine/GraphicsDevice/Vulkan/Android/AndroidVulkanPlatform.h index 542e63644..ae3ad35fc 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/Android/AndroidVulkanPlatform.h +++ b/Source/Engine/GraphicsDevice/Vulkan/Android/AndroidVulkanPlatform.h @@ -13,9 +13,9 @@ class AndroidVulkanPlatform : public VulkanPlatformBase { public: - static void GetInstanceExtensions(Array& outExtensions); - static void GetDeviceExtensions(Array& outExtensions); - static void CreateSurface(void* windowHandle, VkInstance instance, VkSurfaceKHR* outSurface); + static void GetInstanceExtensions(Array& extensions); + static void GetDeviceExtensions(Array& extensions); + static void CreateSurface(void* windowHandle, VkInstance instance, VkSurfaceKHR* surface); }; typedef AndroidVulkanPlatform VulkanPlatform; diff --git a/Source/Engine/GraphicsDevice/Vulkan/CmdBufferVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/CmdBufferVulkan.cpp index a143f7dd8..d06328fdf 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/CmdBufferVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/CmdBufferVulkan.cpp @@ -23,8 +23,8 @@ void CmdBufferVulkan::Begin() VkCommandBufferBeginInfo beginInfo; RenderToolsVulkan::ZeroStruct(beginInfo, VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO); beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - VALIDATE_VULKAN_RESULT(vkBeginCommandBuffer(_commandBufferHandle, &beginInfo)); - + VALIDATE_VULKAN_RESULT(vkBeginCommandBuffer(_commandBuffer, &beginInfo)); + // Acquire a descriptor pool set on if (_descriptorPoolSetContainer == nullptr) { @@ -68,14 +68,14 @@ void CmdBufferVulkan::BeginRenderPass(RenderPassVulkan* renderPass, FramebufferV info.clearValueCount = clearValueCount; info.pClearValues = clearValues; - vkCmdBeginRenderPass(_commandBufferHandle, &info, VK_SUBPASS_CONTENTS_INLINE); + vkCmdBeginRenderPass(_commandBuffer, &info, VK_SUBPASS_CONTENTS_INLINE); _state = State::IsInsideRenderPass; } void CmdBufferVulkan::EndRenderPass() { ASSERT(IsInsideRenderPass()); - vkCmdEndRenderPass(_commandBufferHandle); + vkCmdEndRenderPass(_commandBuffer); _state = State::IsInsideBegin; } @@ -132,7 +132,7 @@ void CmdBufferVulkan::RefreshFenceStatus() _submittedWaitSemaphores.Clear(); - vkResetCommandBuffer(_commandBufferHandle, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); + vkResetCommandBuffer(_commandBuffer, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); _fence->GetOwner()->ResetFence(_fence); _fenceSignaledCounter++; @@ -151,7 +151,7 @@ void CmdBufferVulkan::RefreshFenceStatus() CmdBufferVulkan::CmdBufferVulkan(GPUDeviceVulkan* device, CmdBufferPoolVulkan* pool) : _device(device) - , _commandBufferHandle(VK_NULL_HANDLE) + , _commandBuffer(VK_NULL_HANDLE) , _state(State::ReadyForBegin) , _fence(nullptr) , _fenceSignaledCounter(0) @@ -164,7 +164,7 @@ CmdBufferVulkan::CmdBufferVulkan(GPUDeviceVulkan* device, CmdBufferPoolVulkan* p createCmdBufInfo.commandBufferCount = 1; createCmdBufInfo.commandPool = _commandBufferPool->GetHandle(); - VALIDATE_VULKAN_RESULT(vkAllocateCommandBuffers(_device->Device, &createCmdBufInfo, &_commandBufferHandle)); + VALIDATE_VULKAN_RESULT(vkAllocateCommandBuffers(_device->Device, &createCmdBufInfo, &_commandBuffer)); _fence = _device->FenceManager.AllocateFence(); } @@ -183,13 +183,13 @@ CmdBufferVulkan::~CmdBufferVulkan() fenceManager.ReleaseFence(_fence); } - vkFreeCommandBuffers(_device->Device, _commandBufferPool->GetHandle(), 1, &_commandBufferHandle); + vkFreeCommandBuffers(_device->Device, _commandBufferPool->GetHandle(), 1, &_commandBuffer); } CmdBufferVulkan* CmdBufferPoolVulkan::Create() { - const auto cmdBuffer = New(Device, this); - CmdBuffers.Add(cmdBuffer); + const auto cmdBuffer = New(_device, this); + _cmdBuffers.Add(cmdBuffer); return cmdBuffer; } @@ -200,30 +200,30 @@ void CmdBufferPoolVulkan::Create(uint32 queueFamilyIndex) poolInfo.queueFamilyIndex = queueFamilyIndex; // TODO: use VK_COMMAND_POOL_CREATE_TRANSIENT_BIT? poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - VALIDATE_VULKAN_RESULT(vkCreateCommandPool(Device->Device, &poolInfo, nullptr, &Handle)); + VALIDATE_VULKAN_RESULT(vkCreateCommandPool(_device->Device, &poolInfo, nullptr, &_handle)); } CmdBufferPoolVulkan::CmdBufferPoolVulkan(GPUDeviceVulkan* device) - : Device(device) - , Handle(VK_NULL_HANDLE) + : _device(device) + , _handle(VK_NULL_HANDLE) { } CmdBufferPoolVulkan::~CmdBufferPoolVulkan() { - for (int32 i = 0; i < CmdBuffers.Count(); i++) + for (int32 i = 0; i < _cmdBuffers.Count(); i++) { - Delete(CmdBuffers[i]); + Delete(_cmdBuffers[i]); } - vkDestroyCommandPool(Device->Device, Handle, nullptr); + vkDestroyCommandPool(_device->Device, _handle, nullptr); } void CmdBufferPoolVulkan::RefreshFenceStatus(CmdBufferVulkan* skipCmdBuffer) { - for (int32 i = 0; i < CmdBuffers.Count(); i++) + for (int32 i = 0; i < _cmdBuffers.Count(); i++) { - auto cmdBuffer = CmdBuffers[i]; + auto cmdBuffer = _cmdBuffers[i]; if (cmdBuffer != skipCmdBuffer) { cmdBuffer->RefreshFenceStatus(); @@ -232,63 +232,63 @@ void CmdBufferPoolVulkan::RefreshFenceStatus(CmdBufferVulkan* skipCmdBuffer) } CmdBufferManagerVulkan::CmdBufferManagerVulkan(GPUDeviceVulkan* device, GPUContextVulkan* context) - : Device(device) - , Pool(device) - , Queue(context->GetQueue()) - , ActiveCmdBuffer(nullptr) + : _device(device) + , _pool(device) + , _queue(context->GetQueue()) + , _activeCmdBuffer(nullptr) { - Pool.Create(Queue->GetFamilyIndex()); + _pool.Create(_queue->GetFamilyIndex()); } void CmdBufferManagerVulkan::SubmitActiveCmdBuffer(SemaphoreVulkan* signalSemaphore) { - ASSERT(ActiveCmdBuffer); - if (!ActiveCmdBuffer->IsSubmitted() && ActiveCmdBuffer->HasBegun()) + ASSERT(_activeCmdBuffer); + if (!_activeCmdBuffer->IsSubmitted() && _activeCmdBuffer->HasBegun()) { - if (ActiveCmdBuffer->IsInsideRenderPass()) + if (_activeCmdBuffer->IsInsideRenderPass()) { - ActiveCmdBuffer->EndRenderPass(); + _activeCmdBuffer->EndRenderPass(); } // Pause all active queries - for (int32 i = 0; i < QueriesInProgress.Count(); i++) + for (int32 i = 0; i < _queriesInProgress.Count(); i++) { - QueriesInProgress[i]->Interrupt(ActiveCmdBuffer); + _queriesInProgress[i]->Interrupt(_activeCmdBuffer); } - ActiveCmdBuffer->End(); + _activeCmdBuffer->End(); if (signalSemaphore) { - Queue->Submit(ActiveCmdBuffer, signalSemaphore->GetHandle()); + _queue->Submit(_activeCmdBuffer, signalSemaphore->GetHandle()); } else { - Queue->Submit(ActiveCmdBuffer); + _queue->Submit(_activeCmdBuffer); } } - ActiveCmdBuffer = nullptr; + _activeCmdBuffer = nullptr; } void CmdBufferManagerVulkan::WaitForCmdBuffer(CmdBufferVulkan* cmdBuffer, float timeInSecondsToWait) { ASSERT(cmdBuffer->IsSubmitted()); - bool success = Device->FenceManager.WaitForFence(cmdBuffer->GetFence(), (uint64)(timeInSecondsToWait * 1e9)); - ASSERT(success); + const bool failed = _device->FenceManager.WaitForFence(cmdBuffer->GetFence(), (uint64)(timeInSecondsToWait * 1e9)); + ASSERT(!failed); cmdBuffer->RefreshFenceStatus(); } void CmdBufferManagerVulkan::PrepareForNewActiveCommandBuffer() { - for (int32 i = 0; i < Pool.CmdBuffers.Count(); i++) + for (int32 i = 0; i < _pool._cmdBuffers.Count(); i++) { - auto cmdBuffer = Pool.CmdBuffers[i]; + auto cmdBuffer = _pool._cmdBuffers[i]; cmdBuffer->RefreshFenceStatus(); if (cmdBuffer->GetState() == CmdBufferVulkan::State::ReadyForBegin) { - ActiveCmdBuffer = cmdBuffer; - ActiveCmdBuffer->Begin(); + _activeCmdBuffer = cmdBuffer; + _activeCmdBuffer->Begin(); return; } else @@ -298,24 +298,24 @@ void CmdBufferManagerVulkan::PrepareForNewActiveCommandBuffer() } // All cmd buffers are being executed still - ActiveCmdBuffer = Pool.Create(); - ActiveCmdBuffer->Begin(); + _activeCmdBuffer = _pool.Create(); + _activeCmdBuffer->Begin(); // Resume any paused queries with the new command buffer - for (int32 i = 0; i < QueriesInProgress.Count(); i++) + for (int32 i = 0; i < _queriesInProgress.Count(); i++) { - QueriesInProgress[i]->Resume(ActiveCmdBuffer); + _queriesInProgress[i]->Resume(_activeCmdBuffer); } } void CmdBufferManagerVulkan::OnQueryBegin(GPUTimerQueryVulkan* query) { - QueriesInProgress.Add(query); + _queriesInProgress.Add(query); } void CmdBufferManagerVulkan::OnQueryEnd(GPUTimerQueryVulkan* query) { - QueriesInProgress.Remove(query); + _queriesInProgress.Remove(query); } #endif diff --git a/Source/Engine/GraphicsDevice/Vulkan/CmdBufferVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/CmdBufferVulkan.h index 553e844e7..91469578b 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/CmdBufferVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/CmdBufferVulkan.h @@ -34,7 +34,7 @@ public: private: GPUDeviceVulkan* _device; - VkCommandBuffer _commandBufferHandle; + VkCommandBuffer _commandBuffer; State _state; Array _waitFlags; @@ -44,8 +44,6 @@ private: void MarkSemaphoresAsSubmitted() { _waitFlags.Clear(); - - // Move to pending delete list _submittedWaitSemaphores = _waitSemaphores; _waitSemaphores.Clear(); } @@ -55,12 +53,12 @@ private: int32 _eventsBegin = 0; #endif - // Last value passed after the fence got signaled - volatile uint64 _fenceSignaledCounter; - - // Last value when we submitted the cmd buffer; useful to track down if something waiting for the fence has actually been submitted + // The latest value when command buffer was submitted. volatile uint64 _submittedFenceCounter; + // The latest value passed after the fence was signaled. + volatile uint64 _fenceSignaledCounter; + CmdBufferPoolVulkan* _commandBufferPool; DescriptorPoolSetContainerVulkan* _descriptorPoolSetContainer = nullptr; @@ -73,17 +71,17 @@ public: public: - CmdBufferPoolVulkan* GetOwner() + CmdBufferPoolVulkan* GetOwner() const { return _commandBufferPool; } - State GetState() + State GetState() const { return _state; } - FenceVulkan* GetFence() + FenceVulkan* GetFence() const { return _fence; } @@ -115,7 +113,7 @@ public: inline VkCommandBuffer GetHandle() const { - return _commandBufferHandle; + return _commandBuffer; } inline volatile uint64 GetFenceSignaledCounter() const @@ -155,30 +153,28 @@ public: class CmdBufferPoolVulkan { + friend class CmdBufferManagerVulkan; private: - GPUDeviceVulkan* Device; - VkCommandPool Handle; + GPUDeviceVulkan* _device; + VkCommandPool _handle; + Array _cmdBuffers; CmdBufferVulkan* Create(); - Array CmdBuffers; - void Create(uint32 queueFamilyIndex); - friend class CmdBufferManagerVulkan; public: CmdBufferPoolVulkan(GPUDeviceVulkan* device); - ~CmdBufferPoolVulkan(); public: inline VkCommandPool GetHandle() const { - ASSERT(Handle != VK_NULL_HANDLE); - return Handle; + ASSERT(_handle != VK_NULL_HANDLE); + return _handle; } void RefreshFenceStatus(CmdBufferVulkan* skipCmdBuffer = nullptr); @@ -188,11 +184,11 @@ class CmdBufferManagerVulkan { private: - GPUDeviceVulkan* Device; - CmdBufferPoolVulkan Pool; - QueueVulkan* Queue; - CmdBufferVulkan* ActiveCmdBuffer; - Array QueriesInProgress; + GPUDeviceVulkan* _device; + CmdBufferPoolVulkan _pool; + QueueVulkan* _queue; + CmdBufferVulkan* _activeCmdBuffer; + Array _queriesInProgress; public: @@ -200,46 +196,46 @@ public: public: - inline VkCommandPool GetHandle() const + FORCE_INLINE VkCommandPool GetHandle() const { - return Pool.GetHandle(); + return _pool.GetHandle(); } - inline CmdBufferVulkan* GetActiveCmdBuffer() const + FORCE_INLINE CmdBufferVulkan* GetActiveCmdBuffer() const { - return ActiveCmdBuffer; + return _activeCmdBuffer; } - inline bool HasPendingActiveCmdBuffer() const + FORCE_INLINE bool HasPendingActiveCmdBuffer() const { - return ActiveCmdBuffer != nullptr; + return _activeCmdBuffer != nullptr; } - inline bool HasQueriesInProgress() const + FORCE_INLINE bool HasQueriesInProgress() const { - return QueriesInProgress.Count() != 0; + return _queriesInProgress.Count() != 0; } + CmdBufferVulkan* GetCmdBuffer() + { + if (!_activeCmdBuffer) + PrepareForNewActiveCommandBuffer(); + return _activeCmdBuffer; + } + +public: + void SubmitActiveCmdBuffer(SemaphoreVulkan* signalSemaphore = nullptr); void WaitForCmdBuffer(CmdBufferVulkan* cmdBuffer, float timeInSecondsToWait = 1.0f); - // Update the fences of all cmd buffers except SkipCmdBuffer void RefreshFenceStatus(CmdBufferVulkan* skipCmdBuffer = nullptr) { - Pool.RefreshFenceStatus(skipCmdBuffer); + _pool.RefreshFenceStatus(skipCmdBuffer); } void PrepareForNewActiveCommandBuffer(); - inline CmdBufferVulkan* GetCmdBuffer() - { - if (!ActiveCmdBuffer) - PrepareForNewActiveCommandBuffer(); - - return ActiveCmdBuffer; - } - void OnQueryBegin(GPUTimerQueryVulkan* query); void OnQueryEnd(GPUTimerQueryVulkan* query); }; diff --git a/Source/Engine/GraphicsDevice/Vulkan/DescriptorSetVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/DescriptorSetVulkan.cpp index 1a60dbbae..5b85dca1f 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/DescriptorSetVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/DescriptorSetVulkan.cpp @@ -82,61 +82,24 @@ void DescriptorSetLayoutVulkan::Compile() { ASSERT(_handles.IsEmpty()); - // Check if we obey limits + // Validate device limits for the engine const VkPhysicalDeviceLimits& limits = _device->PhysicalDeviceLimits; - - // Check for maxDescriptorSetSamplers - ASSERT(_layoutTypes[VK_DESCRIPTOR_TYPE_SAMPLER] - + _layoutTypes[VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER] - < limits.maxDescriptorSetSamplers); - - // Check for maxDescriptorSetUniformBuffers - ASSERT(_layoutTypes[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER] - + _layoutTypes[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC] - < limits.maxDescriptorSetUniformBuffers); - - // Check for maxDescriptorSetUniformBuffersDynamic - if (!_device->Adapter->IsAMD()) - { - ASSERT(_layoutTypes[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC] - < limits.maxDescriptorSetUniformBuffersDynamic); - } - - // Check for maxDescriptorSetStorageBuffers - ASSERT(_layoutTypes[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER] - + _layoutTypes[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC] - < limits.maxDescriptorSetStorageBuffers); - - // Check for maxDescriptorSetStorageBuffersDynamic - if (_layoutTypes[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC] > limits.maxDescriptorSetUniformBuffersDynamic) - { - // TODO: Downgrade to non-dynamic? - } - ASSERT(_layoutTypes[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC] - < limits.maxDescriptorSetStorageBuffersDynamic); - - // Check for maxDescriptorSetSampledImages - ASSERT(_layoutTypes[VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER] - + _layoutTypes[VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE] - + _layoutTypes[VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER] - < limits.maxDescriptorSetSampledImages); - - // Check for maxDescriptorSetStorageImages - ASSERT(_layoutTypes[VK_DESCRIPTOR_TYPE_STORAGE_IMAGE] - + _layoutTypes[VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER] - < limits.maxDescriptorSetStorageImages); + ASSERT(_layoutTypes[VK_DESCRIPTOR_TYPE_SAMPLER] + _layoutTypes[VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER] < limits.maxDescriptorSetSamplers); + ASSERT(_layoutTypes[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER]+ _layoutTypes[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC] < limits.maxDescriptorSetUniformBuffers); + ASSERT(_layoutTypes[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC] < limits.maxDescriptorSetUniformBuffersDynamic); + ASSERT(_layoutTypes[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER] + _layoutTypes[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC] < limits.maxDescriptorSetStorageBuffers); + ASSERT(_layoutTypes[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC] < limits.maxDescriptorSetStorageBuffersDynamic); + ASSERT(_layoutTypes[VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER] + _layoutTypes[VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE] + _layoutTypes[VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER] < limits.maxDescriptorSetSampledImages); + ASSERT(_layoutTypes[VK_DESCRIPTOR_TYPE_STORAGE_IMAGE] + _layoutTypes[VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER]< limits.maxDescriptorSetStorageImages); _handles.Resize(_setLayouts.Count()); - for (int32 i = 0; i < _setLayouts.Count(); i++) { auto& layout = _setLayouts[i]; - VkDescriptorSetLayoutCreateInfo layoutInfo; RenderToolsVulkan::ZeroStruct(layoutInfo, VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO); layoutInfo.bindingCount = layout.LayoutBindings.Count(); layoutInfo.pBindings = layout.LayoutBindings.Get(); - VALIDATE_VULKAN_RESULT(vkCreateDescriptorSetLayout(_device->Device, &layoutInfo, nullptr, &_handles[i])); } @@ -162,11 +125,6 @@ DescriptorPoolVulkan::DescriptorPoolVulkan(GPUDeviceVulkan* device, const Descri // The maximum amount of descriptor sets layout allocations to hold const uint32 MaxSetsAllocations = 256; - - // Descriptor sets number required to allocate the max number of descriptor sets layout. - // When we're hashing pools with types usage ID the descriptor pool can be used for different layouts so the initial layout does not make much sense. - // In the latter case we'll be probably over-allocating the descriptor types but given the relatively small number of max allocations this should not have - // a serious impact. DescriptorSetsMax = MaxSetsAllocations * (VULKAN_HASH_POOLS_WITH_TYPES_USAGE_ID ? 1 : Layout.GetLayouts().Count()); for (uint32 typeIndex = VULKAN_DESCRIPTOR_TYPE_BEGIN; typeIndex <= VULKAN_DESCRIPTOR_TYPE_END; typeIndex++) { diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp index 341b708eb..29ceb8230 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp @@ -72,18 +72,6 @@ static VKAPI_ATTR VkBool32 VKAPI_PTR DebugReportFunction(VkDebugReportFlagsEXT m return VK_FALSE; } } - if (!StringUtils::Compare(layerPrefix, "DS")) - { - if (msgCode == 6) - { - auto* Found = StringUtils::Find(msg, " array layer "); - if (Found && Found[13] >= '1' && Found[13] <= '9') - { - // Potential bug in the validation layers for slice > 1 on 3d textures - return VK_FALSE; - } - } - } } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { @@ -1634,7 +1622,7 @@ bool GPUDeviceVulkan::Init() if ((curProps.queueFlags & VK_QUEUE_TRANSFER_BIT) == VK_QUEUE_TRANSFER_BIT) { - // Prefer a non-gfx transfer queue + // Favor a non-gfx transfer queue if (transferQueueFamilyIndex == -1 && (curProps.queueFlags & VK_QUEUE_GRAPHICS_BIT) != VK_QUEUE_GRAPHICS_BIT && (curProps.queueFlags & VK_QUEUE_COMPUTE_BIT) != VK_QUEUE_COMPUTE_BIT) { transferQueueFamilyIndex = familyIndex; @@ -2084,10 +2072,10 @@ bool FenceManagerVulkan::WaitForFence(FenceVulkan* fence, uint64 timeInNanosecon if (result == VK_SUCCESS) { fence->_signaled = true; - return true; + return false; } - return false; + return true; } void FenceManagerVulkan::ResetFence(FenceVulkan* fence) diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h index 2d3522d2c..805cfd8f9 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h @@ -134,20 +134,20 @@ public: return CheckFenceState(fence); } - // Returns false if it timed out + // Returns true if waiting timed out or failed, false otherwise. bool WaitForFence(FenceVulkan* fence, uint64 timeInNanoseconds); void ResetFence(FenceVulkan* fence); - // Sets it to nullptr + // Sets the fence handle to null void ReleaseFence(FenceVulkan*& fence); - // Sets it to nullptr + // Sets the fence handle to null void WaitAndReleaseFence(FenceVulkan*& fence, uint64 timeInNanoseconds); private: - // Returns true if signaled + // Returns true if fence was signaled, otherwise false. bool CheckFenceState(FenceVulkan* fence); void DestroyFence(FenceVulkan* fence); @@ -209,14 +209,14 @@ public: template inline void EnqueueResource(Type type, T handle) { - static_assert(sizeof(T) <= sizeof(uint64), "Vulkan resource handle type size too large."); + static_assert(sizeof(T) <= sizeof(uint64), "Invalid handle size."); EnqueueGenericResource(type, (uint64)handle, VK_NULL_HANDLE); } template inline void EnqueueResource(Type type, T handle, VmaAllocation allocation) { - static_assert(sizeof(T) <= sizeof(uint64), "Vulkan resource handle type size too large."); + static_assert(sizeof(T) <= sizeof(uint64), "Invalid handle size."); EnqueueGenericResource(type, (uint64)handle, allocation); } diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.h index 8c40be054..259d1d838 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.h @@ -49,8 +49,6 @@ private: uint64 _offset; uint32 _minAlignment; byte* _mapped; - - // Fence for wrapping around CmdBufferVulkan* _fenceCmdBuffer; uint64 _fenceCounter; diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUSwapChainVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUSwapChainVulkan.cpp index 6354e9956..fc1c5ab8d 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUSwapChainVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUSwapChainVulkan.cpp @@ -92,7 +92,7 @@ GPUTextureView* GPUSwapChainVulkan::GetBackBufferView() { if (_acquiredImageIndex == -1) { - if (DoCheckedSwapChainJob(DoAcquireImageIndex) < 0) + if (TryPresent(DoAcquireImageIndex) < 0) { LOG(Fatal, "Swapchain acquire image index failed!"); } @@ -415,8 +415,7 @@ GPUSwapChainVulkan::Status GPUSwapChainVulkan::Present(QueueVulkan* presentQueue { if (_currentImageIndex == -1) { - // Skip present silently if image has not been acquired - return Status::Healthy; + return Status::Ok; } VkPresentInfoKHR presentInfo; @@ -436,23 +435,23 @@ GPUSwapChainVulkan::Status GPUSwapChainVulkan::Present(QueueVulkan* presentQueue if (presentResult == VK_ERROR_OUT_OF_DATE_KHR) { - return Status::OutOfDate; + return Status::Outdated; } if (presentResult == VK_ERROR_SURFACE_LOST_KHR) { - return Status::SurfaceLost; + return Status::LostSurface; } if (presentResult != VK_SUCCESS && presentResult != VK_SUBOPTIMAL_KHR) { VALIDATE_VULKAN_RESULT(presentResult); } - return Status::Healthy; + return Status::Ok; } int32 GPUSwapChainVulkan::DoAcquireImageIndex(GPUSwapChainVulkan* viewport, void* customData) { - return viewport->_acquiredImageIndex = viewport->AcquireImageIndex(&viewport->_acquiredSemaphore); + return viewport->_acquiredImageIndex = viewport->AcquireNextImage(&viewport->_acquiredSemaphore); } int32 GPUSwapChainVulkan::DoPresent(GPUSwapChainVulkan* viewport, void* customData) @@ -460,20 +459,20 @@ int32 GPUSwapChainVulkan::DoPresent(GPUSwapChainVulkan* viewport, void* customDa return (int32)viewport->Present((QueueVulkan*)customData, viewport->_backBuffers[viewport->_acquiredImageIndex].RenderingDoneSemaphore); } -int32 GPUSwapChainVulkan::DoCheckedSwapChainJob(Function job, void* customData, bool skipOnOutOfDate) +int32 GPUSwapChainVulkan::TryPresent(Function job, void* customData, bool skipOnOutOfDate) { int32 attemptsPending = 4; int32 status = job(this, customData); while (status < 0 && attemptsPending > 0) { - if (status == (int32)Status::OutOfDate) + if (status == (int32)Status::Outdated) { //LOG(Warning, "Swapchain is out of date"); if (skipOnOutOfDate) return status; } - else if (status == (int32)Status::SurfaceLost) + else if (status == (int32)Status::LostSurface) { LOG(Warning, "Swapchain surface lost"); } @@ -487,7 +486,7 @@ int32 GPUSwapChainVulkan::DoCheckedSwapChainJob(FunctionGetMainContext()->Flush(); _device->WaitForGPU(); @@ -499,7 +498,7 @@ int32 GPUSwapChainVulkan::DoCheckedSwapChainJob(FunctionGetCmdBufferManager()->SubmitActiveCmdBuffer(_backBuffers[_acquiredImageIndex].RenderingDoneSemaphore); // Present the back buffer to the viewport window - const auto result = DoCheckedSwapChainJob(DoPresent, _device->PresentQueue, true); - if (result == (int32)Status::OutOfDate) + const auto result = TryPresent(DoPresent, _device->PresentQueue, true); + if (result == (int32)Status::Outdated) { // Failed to present, window can be minimized or doesn't want to swap the buffers so just ignore the present if (_window->IsMinimized()) diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUSwapChainVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUSwapChainVulkan.h index 36204581c..911032d12 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUSwapChainVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUSwapChainVulkan.h @@ -93,20 +93,19 @@ public: public: - // Has to be negative as we use this also on other callbacks as the acquired image index enum class Status { - Healthy = 0, - OutOfDate = -1, - SurfaceLost = -2, + Ok = 0, + Outdated = -1, + LostSurface = -2, }; Status Present(QueueVulkan* presentQueue, SemaphoreVulkan* backBufferRenderingDoneSemaphore); static int32 DoAcquireImageIndex(GPUSwapChainVulkan* viewport, void* customData); static int32 DoPresent(GPUSwapChainVulkan* viewport, void* customData); - int32 DoCheckedSwapChainJob(Function job, void* customData = nullptr, bool skipOnOutOfDate = false); - int32 AcquireImageIndex(SemaphoreVulkan** outSemaphore); + int32 TryPresent(Function job, void* customData = nullptr, bool skipOnOutOfDate = false); + int32 AcquireNextImage(SemaphoreVulkan** outSemaphore); private: diff --git a/Source/Engine/GraphicsDevice/Vulkan/Linux/LinuxVulkanPlatform.cpp b/Source/Engine/GraphicsDevice/Vulkan/Linux/LinuxVulkanPlatform.cpp index 46ff42641..365e698b9 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/Linux/LinuxVulkanPlatform.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/Linux/LinuxVulkanPlatform.cpp @@ -47,20 +47,20 @@ VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXlibPresentationSupportKHR( extern PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR; extern PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR; -void LinuxVulkanPlatform::GetInstanceExtensions(Array& outExtensions) +void LinuxVulkanPlatform::GetInstanceExtensions(Array& outExextensionstensions) { // Include X11 surface extension - outExtensions.Add(VK_KHR_SURFACE_EXTENSION_NAME); - outExtensions.Add(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); + extensions.Add(VK_KHR_SURFACE_EXTENSION_NAME); + extensions.Add(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); } -void LinuxVulkanPlatform::CreateSurface(void* windowHandle, VkInstance instance, VkSurfaceKHR* outSurface) +void LinuxVulkanPlatform::CreateSurface(void* windowHandle, VkInstance instance, VkSurfaceKHR* surface) { VkXlibSurfaceCreateInfoKHR surfaceCreateInfo; RenderToolsVulkan::ZeroStruct(surfaceCreateInfo, VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR); surfaceCreateInfo.dpy = (X11::Display*)LinuxPlatform::GetXDisplay(); surfaceCreateInfo.window = (X11::Window)windowHandle; - VALIDATE_VULKAN_RESULT(vkCreateXlibSurfaceKHR(instance, &surfaceCreateInfo, nullptr, outSurface)); + VALIDATE_VULKAN_RESULT(vkCreateXlibSurfaceKHR(instance, &surfaceCreateInfo, nullptr, surface)); } #endif diff --git a/Source/Engine/GraphicsDevice/Vulkan/Linux/LinuxVulkanPlatform.h b/Source/Engine/GraphicsDevice/Vulkan/Linux/LinuxVulkanPlatform.h index 04972b7b4..1fc430640 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/Linux/LinuxVulkanPlatform.h +++ b/Source/Engine/GraphicsDevice/Vulkan/Linux/LinuxVulkanPlatform.h @@ -15,7 +15,7 @@ class LinuxVulkanPlatform : public VulkanPlatformBase { public: - static void GetInstanceExtensions(Array& outExtensions); + static void GetInstanceExtensions(Array& extensions); static void CreateSurface(void* windowHandle, VkInstance instance, VkSurfaceKHR* outSurface); }; diff --git a/Source/Engine/GraphicsDevice/Vulkan/Win32/Win32VulkanPlatform.cpp b/Source/Engine/GraphicsDevice/Vulkan/Win32/Win32VulkanPlatform.cpp index 19e8e6e28..49f356ed6 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/Win32/Win32VulkanPlatform.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/Win32/Win32VulkanPlatform.cpp @@ -7,20 +7,20 @@ #include "../RenderToolsVulkan.h" #include "Engine/Graphics/GPUDevice.h" -void Win32VulkanPlatform::GetInstanceExtensions(Array& outExtensions) +void Win32VulkanPlatform::GetInstanceExtensions(Array& extensions) { // Include Windows surface extension - outExtensions.Add(VK_KHR_SURFACE_EXTENSION_NAME); - outExtensions.Add(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); + extensions.Add(VK_KHR_SURFACE_EXTENSION_NAME); + extensions.Add(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); } -void Win32VulkanPlatform::CreateSurface(void* windowHandle, VkInstance instance, VkSurfaceKHR* outSurface) +void Win32VulkanPlatform::CreateSurface(void* windowHandle, VkInstance instance, VkSurfaceKHR* surface) { VkWin32SurfaceCreateInfoKHR surfaceCreateInfo; RenderToolsVulkan::ZeroStruct(surfaceCreateInfo, VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR); surfaceCreateInfo.hinstance = GetModuleHandle(nullptr); surfaceCreateInfo.hwnd = static_cast(windowHandle); - VALIDATE_VULKAN_RESULT(vkCreateWin32SurfaceKHR(instance, &surfaceCreateInfo, nullptr, outSurface)); + VALIDATE_VULKAN_RESULT(vkCreateWin32SurfaceKHR(instance, &surfaceCreateInfo, nullptr, surface)); } #endif diff --git a/Source/Engine/GraphicsDevice/Vulkan/Win32/Win32VulkanPlatform.h b/Source/Engine/GraphicsDevice/Vulkan/Win32/Win32VulkanPlatform.h index 4b3280a0a..435421505 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/Win32/Win32VulkanPlatform.h +++ b/Source/Engine/GraphicsDevice/Vulkan/Win32/Win32VulkanPlatform.h @@ -18,8 +18,8 @@ class Win32VulkanPlatform : public VulkanPlatformBase { public: - static void GetInstanceExtensions(Array& outExtensions); - static void CreateSurface(void* windowHandle, VkInstance instance, VkSurfaceKHR* outSurface); + static void GetInstanceExtensions(Array& extensions); + static void CreateSurface(void* windowHandle, VkInstance instance, VkSurfaceKHR* surface); }; typedef Win32VulkanPlatform VulkanPlatform; diff --git a/Source/Engine/Physics/SimulationEventCallback.cpp b/Source/Engine/Physics/SimulationEventCallback.cpp index 5e1729dd5..4243e3ef6 100644 --- a/Source/Engine/Physics/SimulationEventCallback.cpp +++ b/Source/Engine/Physics/SimulationEventCallback.cpp @@ -142,10 +142,9 @@ void SimulationEventCallback::onSleep(PxActor** actors, PxU32 count) void SimulationEventCallback::onContact(const PxContactPairHeader& pairHeader, const PxContactPair* pairs, PxU32 nbPairs) { - // Check actors are not destroyed + // Skip sending events to removed actors if (pairHeader.flags & (PxContactPairHeaderFlag::eREMOVED_ACTOR_0 | PxContactPairHeaderFlag::eREMOVED_ACTOR_1)) { - LOG(Warning, "SimulationEventCallback::onContact(): Actors have been deleted!"); return; } diff --git a/Source/Engine/Platform/Android/AndroidPlatform.cpp b/Source/Engine/Platform/Android/AndroidPlatform.cpp index de2ef33d8..7c937e111 100644 --- a/Source/Engine/Platform/Android/AndroidPlatform.cpp +++ b/Source/Engine/Platform/Android/AndroidPlatform.cpp @@ -746,15 +746,15 @@ uint64 AndroidPlatform::GetTimeCycles() void AndroidPlatform::GetSystemTime(int32& year, int32& month, int32& dayOfWeek, int32& day, int32& hour, int32& minute, int32& second, int32& millisecond) { - // Query for calendar time + // Get the calendar time struct timeval time; gettimeofday(&time, nullptr); - // Convert to local time + // Convert calendar time to local time struct tm localTime; localtime_r(&time.tv_sec, &localTime); - // Extract time + // Extract time from Unix date year = localTime.tm_year + 1900; month = localTime.tm_mon + 1; dayOfWeek = localTime.tm_wday; diff --git a/Source/Engine/Platform/Base/StringUtilsBase.cpp b/Source/Engine/Platform/Base/StringUtilsBase.cpp index 373307418..4e05f18af 100644 --- a/Source/Engine/Platform/Base/StringUtilsBase.cpp +++ b/Source/Engine/Platform/Base/StringUtilsBase.cpp @@ -18,77 +18,49 @@ const char VolumeSeparatorChar = ':'; const Char* StringUtils::FindIgnoreCase(const Char* str, const Char* toFind) { - // Validate input if (toFind == nullptr || str == nullptr) { return nullptr; } - // Get upper-case first letter of the find string (to reduce the number of full strnicmps) - Char findInitial = ToUpper(*toFind); - - // Get length of find string, and increment past first letter - int32 length = Length(toFind++) - 1; - - // Get the first letter of the search string, and increment past it - Char strChar = *str++; - - // While we aren't at end of string - while (strChar) + const Char findInitial = ToUpper(*toFind); + const int32 length = Length(toFind++) - 1; + Char c = *str++; + while (c) { - // Make sure it's upper-case - strChar = ToUpper(strChar); - - // If it matches the first letter of the find string, do a case-insensitive string compare for the length of the find string - if (strChar == findInitial && !CompareIgnoreCase(str, toFind, length)) + c = ToUpper(c); + if (c == findInitial && !CompareIgnoreCase(str, toFind, length)) { - // If we found the string, then return a pointer to the beginning of it in the search string return str - 1; } - // Go to next letter - strChar = *str++; + c = *str++; } - // Nothing found return nullptr; } const char* StringUtils::FindIgnoreCase(const char* str, const char* toFind) { - // Validate input if (toFind == nullptr || str == nullptr) { return nullptr; } - // Get upper-case first letter of the find string (to reduce the number of full strnicmps) - char findInitial = (char)ToUpper(*toFind); - - // Get length of find string, and increment past first letter - int32 length = Length(toFind++) - 1; - - // Get the first letter of the search string, and increment past it - char strChar = *str++; - - // While we aren't at end of string - while (strChar) + const char findInitial = (char)ToUpper(*toFind); + const int32 length = Length(toFind++) - 1; + char c = *str++; + while (c) { - // Make sure it's upper-case - strChar = (char)ToUpper(strChar); - - // If it matches the first letter of the find string, do a case-insensitive string compare for the length of the find string - if (strChar == findInitial && !CompareIgnoreCase(str, toFind, length)) + c = (char)ToUpper(c); + if (c == findInitial && !CompareIgnoreCase(str, toFind, length)) { - // If we found the string, then return a pointer to the beginning of it in the search string return str - 1; } - // Go to next letter - strChar = *str++; + c = *str++; } - // Nothing found return nullptr; } diff --git a/Source/Engine/Platform/Linux/LinuxFileSystem.cpp b/Source/Engine/Platform/Linux/LinuxFileSystem.cpp index 1c019ec9e..2d89f10a5 100644 --- a/Source/Engine/Platform/Linux/LinuxFileSystem.cpp +++ b/Source/Engine/Platform/Linux/LinuxFileSystem.cpp @@ -229,7 +229,7 @@ uint64 LinuxFileSystem::GetFileSize(const StringView& path) const StringAsANSI<> pathANSI(*path, path.Length()); if (stat(pathANSI.Get(), &fileInfo) != -1) { - // make sure to return -1 for directories + // Check for directories if (S_ISDIR(fileInfo.st_mode)) { fileInfo.st_size = -1; diff --git a/Source/Engine/Platform/Linux/LinuxPlatform.cpp b/Source/Engine/Platform/Linux/LinuxPlatform.cpp index ebe7fbf53..4d16a4c47 100644 --- a/Source/Engine/Platform/Linux/LinuxPlatform.cpp +++ b/Source/Engine/Platform/Linux/LinuxPlatform.cpp @@ -1329,13 +1329,13 @@ bool LinuxPlatform::Init() Platform::MemoryClear(cpuInfos, sizeof(cpuInfos)); int maxCoreId = 0; int maxPackageId = 0; - int numCpusAvailable = 0; + int cpuCountAvailable = 0; for (int32 cpuIdx = 0; cpuIdx < CPU_SETSIZE; cpuIdx++) { if (CPU_ISSET(cpuIdx, &availableCpusMask)) { - numCpusAvailable++; + cpuCountAvailable++; sprintf(fileNameBuffer, "/sys/devices/system/cpu/cpu%d/topology/core_id", cpuIdx); if (FILE* coreIdFile = fopen(fileNameBuffer, "r")) @@ -1363,31 +1363,28 @@ bool LinuxPlatform::Init() } } - int numCores = maxCoreId + 1; - int numPackages = maxPackageId + 1; - int numPairs = numPackages * numCores; + int coresCount = maxCoreId + 1; + int packagesCount = maxPackageId + 1; + int pairsCount = packagesCount * coresCount; - // AArch64 topology seems to be incompatible with the above assumptions, particularly, core_id can be all 0 while the cores themselves are obviously independent. - // Check if num CPUs available to us is more than 2 per core (i.e. more than reasonable when hyperthreading is involved), and if so, don't trust the topology. - if (numCores * 2 < numCpusAvailable) + if (coresCount * 2 < cpuCountAvailable) { - // Consider all CPUs to be separate - numberOfCores = numCpusAvailable; + numberOfCores = cpuCountAvailable; } else { - byte* pairs = (byte*)Allocator::Allocate(numPairs); - Platform::MemoryClear(pairs, numPairs * sizeof(unsigned char)); + byte* pairs = (byte*)Allocator::Allocate(pairsCount); + Platform::MemoryClear(pairs, pairsCount * sizeof(unsigned char)); for (int32 cpuIdx = 0; cpuIdx < CPU_SETSIZE; cpuIdx++) { if (CPU_ISSET(cpuIdx, &availableCpusMask)) { - pairs[cpuInfos[cpuIdx].Package * numCores + cpuInfos[cpuIdx].Core] = 1; + pairs[cpuInfos[cpuIdx].Package * coresCount + cpuInfos[cpuIdx].Core] = 1; } } - for (int32 i = 0; i < numPairs; i++) + for (int32 i = 0; i < pairsCount; i++) { numberOfCores += pairs[i]; } @@ -1395,7 +1392,7 @@ bool LinuxPlatform::Init() Allocator::Free(pairs); } - UnixCpu.ProcessorPackageCount = numPackages; + UnixCpu.ProcessorPackageCount = packagesCount; UnixCpu.ProcessorCoreCount = Math::Max(numberOfCores, 1); UnixCpu.LogicalProcessorCount = CPU_COUNT(&availableCpusMask); } diff --git a/Source/Engine/Platform/Windows/WindowsInput.cpp b/Source/Engine/Platform/Windows/WindowsInput.cpp index 0b6ed50bc..98e69a802 100644 --- a/Source/Engine/Platform/Windows/WindowsInput.cpp +++ b/Source/Engine/Platform/Windows/WindowsInput.cpp @@ -295,7 +295,7 @@ bool WindowsMouse::WndProc(Window* window, const UINT msg, WPARAM wParam, LPARAM float NormalizeXInputAxis(const int16 axisVal) { // Normalize [-32768..32767] -> [-1..1] - const float norm = axisVal <= 0 ? 32768.f : 32767.f; + const float norm = axisVal <= 0 ? 32768.0f : 32767.0f; return float(axisVal) / norm; } diff --git a/Source/Engine/Render2D/FontTextureAtlas.cpp b/Source/Engine/Render2D/FontTextureAtlas.cpp index d87cf0583..63b70f447 100644 --- a/Source/Engine/Render2D/FontTextureAtlas.cpp +++ b/Source/Engine/Render2D/FontTextureAtlas.cpp @@ -20,7 +20,7 @@ FontTextureAtlas::FontTextureAtlas(const SpawnParams& params, const AssetInfo* i uint32 FontTextureAtlas::GetPaddingAmount() const { - return (_paddingStyle == NoPadding ? 0 : 1); + return _paddingStyle == NoPadding ? 0 : 1; } void FontTextureAtlas::Setup(PixelFormat format, PaddingStyle paddingStyle) @@ -97,107 +97,95 @@ bool FontTextureAtlas::Invalidate(uint32 x, uint32 y, uint32 width, uint32 heigh void FontTextureAtlas::CopyDataIntoSlot(const Slot* slot, const Array& data) { - // Copy pixel data to the texture uint8* start = &_data[slot->Y * _width * _bytesPerPixel + slot->X * _bytesPerPixel]; - - // Account for same padding on each sides const uint32 padding = GetPaddingAmount(); const uint32 allPadding = padding * 2; + const uint32 srcWidth = slot->Width - allPadding; + const uint32 srcHeight = slot->Height - allPadding; - // The width of the source texture without padding (actual width) - const uint32 sourceWidth = slot->Width - allPadding; - const uint32 sourceHeight = slot->Height - allPadding; + RowData rowData; + rowData.DstData = start; + rowData.SrcData = data.Get(); + rowData.DstTextureWidth = _width; + rowData.SrcTextureWidth = srcWidth; + rowData.RowWidth = slot->Width; - CopyRowData copyRowData; - copyRowData.DestData = start; - copyRowData.SrcData = data.Get(); - copyRowData.DestTextureWidth = _width; - copyRowData.SrcTextureWidth = sourceWidth; - copyRowData.RowWidth = slot->Width; - - // Apply the padding for bilinear filtering - // Not used if no padding (assumes sampling outside boundaries of the sub texture is not possible) + // Start with padding if (padding > 0) { - // Copy first color row into padding. - copyRowData.SrcRow = 0; - copyRowData.DestRow = 0; + rowData.SrcRow = 0; + rowData.DstRow = 0; if (_paddingStyle == DilateBorder) { - copyRow(copyRowData); + copyRow(rowData); } else { - zeroRow(copyRowData); + zeroRow(rowData); } } // Copy each row of the texture for (uint32 row = padding; row < slot->Height - padding; row++) { - copyRowData.SrcRow = row - padding; - copyRowData.DestRow = row; + rowData.SrcRow = row - padding; + rowData.DstRow = row; - copyRow(copyRowData); + copyRow(rowData); } + // Finish with padding if (padding > 0) { - // Copy last color row into padding row for bilinear filtering - copyRowData.SrcRow = sourceHeight - 1; - copyRowData.DestRow = slot->Height - padding; - + rowData.SrcRow = srcHeight - 1; + rowData.DstRow = slot->Height - padding; if (_paddingStyle == DilateBorder) - { - copyRow(copyRowData); - } + copyRow(rowData); else - { - zeroRow(copyRowData); - } + zeroRow(rowData); } } -void FontTextureAtlas::copyRow(const CopyRowData& copyRowData) const +void FontTextureAtlas::copyRow(const RowData& copyRowData) const { const byte* data = copyRowData.SrcData; - byte* start = copyRowData.DestData; - const uint32 sourceWidth = copyRowData.SrcTextureWidth; - const uint32 destWidth = copyRowData.DestTextureWidth; + byte* start = copyRowData.DstData; + const uint32 srdWidth = copyRowData.SrcTextureWidth; + const uint32 dstWidth = copyRowData.DstTextureWidth; const uint32 srcRow = copyRowData.SrcRow; - const uint32 destRow = copyRowData.DestRow; + const uint32 dstRow = copyRowData.DstRow; const uint32 padding = GetPaddingAmount(); - const byte* sourceDataAddr = &data[(srcRow * sourceWidth) * _bytesPerPixel]; - byte* destDataAddr = &start[(destRow * destWidth + padding) * _bytesPerPixel]; - Platform::MemoryCopy(destDataAddr, sourceDataAddr, sourceWidth * _bytesPerPixel); + const byte* srcData = &data[srcRow * srdWidth * _bytesPerPixel]; + byte* dstData = &start[(dstRow * dstWidth + padding) * _bytesPerPixel]; + Platform::MemoryCopy(dstData, srcData, srdWidth * _bytesPerPixel); if (padding > 0) { - byte* destPaddingPixelLeft = &start[(destRow * destWidth) * _bytesPerPixel]; - byte* destPaddingPixelRight = destPaddingPixelLeft + ((copyRowData.RowWidth - 1) * _bytesPerPixel); + byte* dstPaddingPixelLeft = &start[dstRow * dstWidth * _bytesPerPixel]; + byte* dstPaddingPixelRight = dstPaddingPixelLeft + (copyRowData.RowWidth - 1) * _bytesPerPixel; if (_paddingStyle == DilateBorder) { - const byte* firstPixel = sourceDataAddr; - const byte* lastPixel = sourceDataAddr + ((sourceWidth - 1) * _bytesPerPixel); - Platform::MemoryCopy(destPaddingPixelLeft, firstPixel, _bytesPerPixel); - Platform::MemoryCopy(destPaddingPixelRight, lastPixel, _bytesPerPixel); + const byte* firstPixel = srcData; + const byte* lastPixel = srcData + (srdWidth - 1) * _bytesPerPixel; + Platform::MemoryCopy(dstPaddingPixelLeft, firstPixel, _bytesPerPixel); + Platform::MemoryCopy(dstPaddingPixelRight, lastPixel, _bytesPerPixel); } else { - Platform::MemoryClear(destPaddingPixelLeft, _bytesPerPixel); - Platform::MemoryClear(destPaddingPixelRight, _bytesPerPixel); + Platform::MemoryClear(dstPaddingPixelLeft, _bytesPerPixel); + Platform::MemoryClear(dstPaddingPixelRight, _bytesPerPixel); } } } -void FontTextureAtlas::zeroRow(const CopyRowData& copyRowData) const +void FontTextureAtlas::zeroRow(const RowData& copyRowData) const { - const uint32 destWidth = copyRowData.DestTextureWidth; - const uint32 destRow = copyRowData.DestRow; - byte* destData = ©RowData.DestData[destRow * destWidth * _bytesPerPixel]; - Platform::MemoryClear(destData, copyRowData.RowWidth * _bytesPerPixel); + const uint32 dstWidth = copyRowData.DstTextureWidth; + const uint32 dstRow = copyRowData.DstRow; + byte* dstData = ©RowData.DstData[dstRow * dstWidth * _bytesPerPixel]; + Platform::MemoryClear(dstData, copyRowData.RowWidth * _bytesPerPixel); } void FontTextureAtlas::unload(bool isReloading) diff --git a/Source/Engine/Render2D/FontTextureAtlas.h b/Source/Engine/Render2D/FontTextureAtlas.h index 0ccd510ad..be334d47f 100644 --- a/Source/Engine/Render2D/FontTextureAtlas.h +++ b/Source/Engine/Render2D/FontTextureAtlas.h @@ -15,28 +15,15 @@ API_CLASS(NoSpawn) class FLAXENGINE_API FontTextureAtlas : public Texture DECLARE_BINARY_ASSET_HEADER(FontTextureAtlas, TexturesSerializedVersion); private: - struct CopyRowData + struct RowData { - // Source data to copy const byte* SrcData; - - // Place to copy data to - uint8* DestData; - - // The row number to copy + uint8* DstData; uint32 SrcRow; - - // The row number to copy to - uint32 DestRow; - - // The width of a source row + uint32 DstRow; uint32 RowWidth; - - // The width of the source texture uint32 SrcTextureWidth; - - // The width of the dest texture - uint32 DestTextureWidth; + uint32 DstTextureWidth; }; public: @@ -226,8 +213,8 @@ private: Slot* invalidate(Slot* parent, uint32 x, uint32 y, uint32 width, uint32 height); void markAsDirty(); - void copyRow(const CopyRowData& copyRowData) const; - void zeroRow(const CopyRowData& copyRowData) const; + void copyRow(const RowData& copyRowData) const; + void zeroRow(const RowData& copyRowData) const; protected: diff --git a/Source/Engine/Render2D/Render2D.cpp b/Source/Engine/Render2D/Render2D.cpp index 5c62e7a83..e7c014d03 100644 --- a/Source/Engine/Render2D/Render2D.cpp +++ b/Source/Engine/Render2D/Render2D.cpp @@ -769,26 +769,22 @@ void Render2D::PopClip() OnClipScissors(); } -void ComputeEffectiveKernelSize(float strength, int32& outKernelSize, int32& outDownSampleAmount) +void CalculateKernelSize(float strength, int32& kernelSize, int32& downSample) { - // Auto-compute radius based on the strength - outKernelSize = Math::RoundToInt(strength * 3.f); + kernelSize = Math::RoundToInt(strength * 3.0f); - // Down sample if needed - if (DownsampleForBlur && outKernelSize > 9) + if (DownsampleForBlur && kernelSize > 9) { - outDownSampleAmount = outKernelSize >= 64 ? 4 : 2; - outKernelSize /= outDownSampleAmount; + downSample = kernelSize >= 64 ? 4 : 2; + kernelSize /= downSample; } - // Kernel sizes must be odd - if (outKernelSize % 2 == 0) + if (kernelSize % 2 == 0) { - outKernelSize++; + kernelSize++; } - // Clamp kernel to valid bounds - outKernelSize = Math::Clamp(outKernelSize, 3, 255); + kernelSize = Math::Clamp(kernelSize, 3, 255); } static float GetWeight(float dist, float strength) @@ -940,16 +936,13 @@ void DrawBatch(int32 startIndex, int32 count) int32 renderTargetWidth = Math::Min(Math::RoundToInt(d.AsBlur.Width), limits.MaximumTexture2DSize); int32 renderTargetHeight = Math::Min(Math::RoundToInt(d.AsBlur.Height), limits.MaximumTexture2DSize); - int32 kernelSize = 0; - int32 downSampleAmount = 0; - ComputeEffectiveKernelSize(blurStrength, kernelSize, downSampleAmount); - const bool needDownscale = downSampleAmount > 0; - - if (needDownscale) + int32 kernelSize = 0, downSample = 0; + CalculateKernelSize(blurStrength, kernelSize, downSample); + if (downSample > 0) { - renderTargetWidth = Math::DivideAndRoundUp(renderTargetWidth, downSampleAmount); - renderTargetHeight = Math::DivideAndRoundUp(renderTargetHeight, downSampleAmount); - blurStrength /= downSampleAmount; + renderTargetWidth = Math::DivideAndRoundUp(renderTargetWidth, downSample); + renderTargetHeight = Math::DivideAndRoundUp(renderTargetHeight, downSample); + blurStrength /= downSample; } // Skip if no chance to render anything @@ -1304,10 +1297,8 @@ void Render2D::DrawRectangle(const Rectangle& rect, const Color& color1, const C drawCall.StartIB = IBIndex; drawCall.CountIB = 4 * (6 + 3); - // Half of the width of the filter size to use for anti-aliasing. Increasing this value will increase the fuzziness of line edges. - const float filterScale = 1.0f; // Must match HLSL code - - // The amount we increase each side of the line to generate enough pixels + // The has to match HLSL code + const float filterScale = 1.0f; const float thicknessHalf = (2.82842712f + thickness) * 0.5f + filterScale; for (int32 i = 1; i < 5; i++) diff --git a/Source/Engine/Renderer/ColorGradingPass.cpp b/Source/Engine/Renderer/ColorGradingPass.cpp index 6783aed59..01fcd8e97 100644 --- a/Source/Engine/Renderer/ColorGradingPass.cpp +++ b/Source/Engine/Renderer/ColorGradingPass.cpp @@ -195,7 +195,7 @@ GPUTexture* ColorGradingPass::RenderLUT(RenderContext& renderContext) { context->SetRenderTarget(lut->ViewVolume()); - // Render a quad per slice affected by the given bounds + // Render one fullscreen-triangle per slice intersecting the bounds const int32 numInstances = lutDesc.Depth; context->DrawFullscreenTriangle(numInstances); } diff --git a/Source/Engine/Renderer/VolumetricFogPass.cpp b/Source/Engine/Renderer/VolumetricFogPass.cpp index b4379cc90..f92dcb82c 100644 --- a/Source/Engine/Renderer/VolumetricFogPass.cpp +++ b/Source/Engine/Renderer/VolumetricFogPass.cpp @@ -323,7 +323,7 @@ void VolumetricFogPass::RenderRadialLight(RenderContext& renderContext, GPUConte // Ensure to have valid buffers created if (_vbCircleRasterize == nullptr || _ibCircleRasterize == nullptr) - InitCircleRasterizeBuffers(); + InitCircleBuffer(); // Call rendering to the volume const int32 psIndex = (_cache.TemporalReprojection ? 1 : 0) + 2; @@ -378,7 +378,7 @@ void VolumetricFogPass::RenderRadialLight(RenderContext& renderContext, GPUConte // Ensure to have valid buffers created if (_vbCircleRasterize == nullptr || _ibCircleRasterize == nullptr) - InitCircleRasterizeBuffers(); + InitCircleBuffer(); // Call rendering to the volume const int32 psIndex = (cache.TemporalReprojection ? 1 : 0) + (withShadow ? 2 : 0); @@ -644,19 +644,16 @@ void VolumetricFogPass::Render(RenderContext& renderContext) context->FlushState(); } -void VolumetricFogPass::InitCircleRasterizeBuffers() +void VolumetricFogPass::InitCircleBuffer() { const int32 vertices = 8; const int32 triangles = vertices - 2; const int32 rings = vertices; const float radiansPerRingSegment = PI / (float)rings; - Vector2 vbData[vertices]; uint16 ibData[triangles * 3]; - // Boost the effective radius so that the edges of the circle approximation lie on the circle, instead of the vertices const float radiusScale = 1.0f / Math::Cos(radiansPerRingSegment); - for (int32 vertexIndex = 0; vertexIndex < vertices; vertexIndex++) { const float angle = vertexIndex / static_cast(vertices - 1) * 2 * PI; diff --git a/Source/Engine/Renderer/VolumetricFogPass.h b/Source/Engine/Renderer/VolumetricFogPass.h index 1604d96de..26c4dfc99 100644 --- a/Source/Engine/Renderer/VolumetricFogPass.h +++ b/Source/Engine/Renderer/VolumetricFogPass.h @@ -167,7 +167,7 @@ private: bool Init(RenderContext& renderContext, GPUContext* context, VolumetricFogOptions& options); GPUTextureView* GetLocalShadowedLightScattering(RenderContext& renderContext, GPUContext* context, VolumetricFogOptions& options) const; - void InitCircleRasterizeBuffers(); + void InitCircleBuffer(); template void RenderRadialLight(RenderContext& renderContext, GPUContext* context, T& light, LightShadowData& shadow); template diff --git a/Source/Engine/Utilities/Crc.cpp b/Source/Engine/Utilities/Crc.cpp index 0a791780d..25ca8f0c6 100644 --- a/Source/Engine/Utilities/Crc.cpp +++ b/Source/Engine/Utilities/Crc.cpp @@ -4,10 +4,10 @@ #include "Engine/Core/Math/Math.h" #include "Engine/Platform/Platform.h" -// CRC 32 polynomial +// Use CRC 32 polynomial enum { Crc32Poly = 0x04c11db7 }; -uint32 Crc::CRCTablesSB8[8][256] = +uint32 Crc::CachedCRCTablesSB8[8][256] = { { 0x00000000, @@ -2088,16 +2088,16 @@ void Crc::Init() CRC = (CRC & 1) ? (CRC >> 1) ^ rCrc32Poly : (CRC >> 1); } - ASSERT(CRCTablesSB8[0][i] == CRC); + ASSERT(CachedCRCTablesSB8[0][i] == CRC); } for (uint32 i = 0; i != 256; ++i) { - uint32 CRC = CRCTablesSB8[0][i]; + uint32 CRC = CachedCRCTablesSB8[0][i]; for (uint32 j = 1; j != 8; ++j) { - CRC = CRCTablesSB8[0][CRC & 0xFF] ^ (CRC >> 8); - ASSERT(CRCTablesSB8[j][i] == CRC); + CRC = CachedCRCTablesSB8[0][CRC & 0xFF] ^ (CRC >> 8); + ASSERT(CachedCRCTablesSB8[j][i] == CRC); } } #endif @@ -2121,7 +2121,7 @@ uint32 Crc::MemCrc32(const void* data, int32 length, uint32 crc) for (; initBytes; --initBytes) { - crc = (crc >> 8) ^ CRCTablesSB8[0][(crc & 0xFF) ^ *ptr++]; + crc = (crc >> 8) ^ CachedCRCTablesSB8[0][(crc & 0xFF) ^ *ptr++]; } auto ptr4 = (const uint32*)ptr; @@ -2130,14 +2130,14 @@ uint32 Crc::MemCrc32(const void* data, int32 length, uint32 crc) uint32 v1 = *ptr4++ ^ crc; uint32 v2 = *ptr4++; crc = - CRCTablesSB8[7][v1 & 0xFF] ^ - CRCTablesSB8[6][(v1 >> 8) & 0xFF] ^ - CRCTablesSB8[5][(v1 >> 16) & 0xFF] ^ - CRCTablesSB8[4][v1 >> 24] ^ - CRCTablesSB8[3][v2 & 0xFF] ^ - CRCTablesSB8[2][(v2 >> 8) & 0xFF] ^ - CRCTablesSB8[1][(v2 >> 16) & 0xFF] ^ - CRCTablesSB8[0][v2 >> 24]; + CachedCRCTablesSB8[7][v1 & 0xFF] ^ + CachedCRCTablesSB8[6][(v1 >> 8) & 0xFF] ^ + CachedCRCTablesSB8[5][(v1 >> 16) & 0xFF] ^ + CachedCRCTablesSB8[4][v1 >> 24] ^ + CachedCRCTablesSB8[3][v2 & 0xFF] ^ + CachedCRCTablesSB8[2][(v2 >> 8) & 0xFF] ^ + CachedCRCTablesSB8[1][(v2 >> 16) & 0xFF] ^ + CachedCRCTablesSB8[0][v2 >> 24]; } ptr = (const uint8*)ptr4; @@ -2146,7 +2146,7 @@ uint32 Crc::MemCrc32(const void* data, int32 length, uint32 crc) for (; length; --length) { - crc = (crc >> 8) ^ CRCTablesSB8[0][(crc & 0xFF) ^ *ptr++]; + crc = (crc >> 8) ^ CachedCRCTablesSB8[0][(crc & 0xFF) ^ *ptr++]; } return ~crc; diff --git a/Source/Engine/Utilities/Crc.h b/Source/Engine/Utilities/Crc.h index 5c50a19a8..a43156382 100644 --- a/Source/Engine/Utilities/Crc.h +++ b/Source/Engine/Utilities/Crc.h @@ -5,55 +5,17 @@ #include "Engine/Core/Types/BaseTypes.h" #include "Engine/Core/Templates.h" -// The CRC hash generation for different types of input data. +// The utilities for CRC hash generation. class Crc { public: - // Lookup table with pre-calculated CRC values - slicing by 8 implementation. - static uint32 CRCTablesSB8[8][256]; + // Helper lookup table with cached CRC values. + static uint32 CachedCRCTablesSB8[8][256]; // Initializes the CRC lookup table. Must be called before any of the CRC functions are used. static void Init(); // Generates CRC hash of the memory area static uint32 MemCrc32(const void* data, int32 length, uint32 crc = 0); - - // String CRC. - template - static typename TEnableIf::Type StrCrc32(const CharType* data, uint32 crc = 0) - { - // We ensure that we never try to do a StrCrc32 with a CharType of more than 4 bytes. This is because - // we always want to treat every CRC as if it was based on 4 byte chars, even if it's less, because we - // want consistency between equivalent strings with different character types. - static_assert(sizeof(CharType) <= 4, "StrCrc32 only works with CharType up to 32 bits."); - - crc = ~crc; - while (CharType c = *data++) - { - crc = (crc >> 8) ^ CRCTablesSB8[0][(crc ^ c) & 0xFF]; - c >>= 8; - crc = (crc >> 8) ^ CRCTablesSB8[0][(crc ^ c) & 0xFF]; - c >>= 8; - crc = (crc >> 8) ^ CRCTablesSB8[0][(crc ^ c) & 0xFF]; - c >>= 8; - crc = (crc >> 8) ^ CRCTablesSB8[0][(crc ^ c) & 0xFF]; - } - return ~crc; - } - - template - static typename TEnableIf::Type StrCrc32(const CharType* data, uint32 crc = 0) - { - // Overload for when CharType is a byte, which causes warnings when right-shifting by 8 - crc = ~crc; - while (CharType Ch = *data++) - { - crc = (crc >> 8) ^ CRCTablesSB8[0][(crc ^ Ch) & 0xFF]; - crc = (crc >> 8) ^ CRCTablesSB8[0][(crc) & 0xFF]; - crc = (crc >> 8) ^ CRCTablesSB8[0][(crc) & 0xFF]; - crc = (crc >> 8) ^ CRCTablesSB8[0][(crc) & 0xFF]; - } - return ~crc; - } }; diff --git a/Source/Tools/Flax.Build/Deploy/VCEnvironment.cs b/Source/Tools/Flax.Build/Deploy/VCEnvironment.cs index 962634873..e7ef5997f 100644 --- a/Source/Tools/Flax.Build/Deploy/VCEnvironment.cs +++ b/Source/Tools/Flax.Build/Deploy/VCEnvironment.cs @@ -155,7 +155,7 @@ namespace Flax.Deploy } /// - /// Function to query the registry under HKCU/HKLM Win32/Wow64 software registry keys for a certain install directory. + /// Queries the registry entries for a certain install directory of the MsBuild. /// /// True if found MsBuild tool, otherwise false. private static bool TryReadInstallPath(string keyRelativePath, string keyName, string msBuildRelativePath, out string outMsBuildPath) diff --git a/Source/Tools/Flax.Build/Platforms/Windows/WindowsPlatformBase.cs b/Source/Tools/Flax.Build/Platforms/Windows/WindowsPlatformBase.cs index 1e38ceaa2..3f60dd818 100644 --- a/Source/Tools/Flax.Build/Platforms/Windows/WindowsPlatformBase.cs +++ b/Source/Tools/Flax.Build/Platforms/Windows/WindowsPlatformBase.cs @@ -406,14 +406,13 @@ namespace Flax.Build.Platforms case WindowsPlatformToolset.v142: { /* - // Use the x86-on-x64 compiler string crossCompilerPath = Path.Combine(vcToolChainDir, "bin", "HostX64", "x86", "cl.exe"); if (File.Exists(crossCompilerPath)) { return Path.GetDirectoryName(crossCompilerPath); } */ - // Otherwise the native 32-bit compiler if present + string nativeCompilerPath = Path.Combine(vcToolChainDir, "bin", "HostX86", "x86", "cl.exe"); if (File.Exists(nativeCompilerPath)) { @@ -442,14 +441,12 @@ namespace Flax.Build.Platforms { case WindowsPlatformToolset.v140: { - // Use the native 64-bit compiler if present string nativeCompilerPath = Path.Combine(vcToolChainDir, "bin", "amd64", "cl.exe"); if (File.Exists(nativeCompilerPath)) { return Path.GetDirectoryName(nativeCompilerPath); } - // Otherwise use the x64-on-x86 compiler string crossCompilerPath = Path.Combine(vcToolChainDir, "bin", "x86_amd64", "cl.exe"); if (File.Exists(crossCompilerPath)) { @@ -462,14 +459,12 @@ namespace Flax.Build.Platforms case WindowsPlatformToolset.v141: case WindowsPlatformToolset.v142: { - // Use the native 64-bit compiler if present string nativeCompilerPath = Path.Combine(vcToolChainDir, "bin", "HostX64", "x64", "cl.exe"); if (File.Exists(nativeCompilerPath)) { return Path.GetDirectoryName(nativeCompilerPath); } - // Otherwise try the x64-on-x86 compiler string crossCompilerPath = Path.Combine(vcToolChainDir, "bin", "HostX86", "x64", "cl.exe"); if (File.Exists(crossCompilerPath)) { @@ -488,6 +483,7 @@ namespace Flax.Build.Platforms { } + /// void IProjectCustomizer.GetProjectArchitectureName(Project project, Platform platform, TargetArchitecture architecture, ref string name) { if (architecture == TargetArchitecture.x86) diff --git a/Source/Tools/Flax.Build/Utilities/Utilities.cs b/Source/Tools/Flax.Build/Utilities/Utilities.cs index 752d066af..9c95fed23 100644 --- a/Source/Tools/Flax.Build/Utilities/Utilities.cs +++ b/Source/Tools/Flax.Build/Utilities/Utilities.cs @@ -355,22 +355,21 @@ namespace Flax.Build /// Thew relative path from the given directory. public static string MakePathRelativeTo(string path, string directory) { - // Find how much of the path is common between the two paths. This length does not include a trailing directory separator character - int commonDirectoryLength = -1; + int sharedDirectoryLength = -1; for (int i = 0;; i++) { if (i == path.Length) { - // Check if two paths are the same + // Paths are the same if (i == directory.Length) { return string.Empty; } - // Check if we're finishing on a complete directory name + // Finished on a complete directory if (directory[i] == Path.DirectorySeparatorChar) { - commonDirectoryLength = i; + sharedDirectoryLength = i; } break; @@ -378,16 +377,15 @@ namespace Flax.Build if (i == directory.Length) { - // Check whether the end of the directory name coincides with a boundary for the current name + // End of the directory name starts with a boundary for the current name if (path[i] == Path.DirectorySeparatorChar) { - commonDirectoryLength = i; + sharedDirectoryLength = i; } break; } - // Check the two paths match, and bail if they don't. Increase the common directory length if we've reached a separator if (string.Compare(path, i, directory, i, 1, StringComparison.OrdinalIgnoreCase) != 0) { break; @@ -395,19 +393,19 @@ namespace Flax.Build if (path[i] == Path.DirectorySeparatorChar) { - commonDirectoryLength = i; + sharedDirectoryLength = i; } } - // If there's no relative path, just return the absolute path - if (commonDirectoryLength == -1) + // No shared path found + if (sharedDirectoryLength == -1) { return path; } - // Append all the '..' separators to get back to the common directory, then the rest of the string to reach the target item + // Add all the '..' separators to get back to the shared directory, StringBuilder result = new StringBuilder(); - for (int i = commonDirectoryLength + 1; i < directory.Length; i++) + for (int i = sharedDirectoryLength + 1; i < directory.Length; i++) { // Move up a directory result.Append(".."); @@ -420,9 +418,9 @@ namespace Flax.Build } } - if (commonDirectoryLength + 1 < path.Length) + if (sharedDirectoryLength + 1 < path.Length) { - result.Append(path, commonDirectoryLength + 1, path.Length - commonDirectoryLength - 1); + result.Append(path, sharedDirectoryLength + 1, path.Length - sharedDirectoryLength - 1); } return result.ToString();