Fix code style

This commit is contained in:
Wojtek Figat
2020-12-30 22:56:17 +01:00
parent 5e469a0ae3
commit 05790ab9a1
62 changed files with 300 additions and 456 deletions

BIN
Content/Editor/Camera/M_Camera.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Editor/Gizmo/Material.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Editor/Gizmo/MaterialWire.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

BIN
Content/Editor/Highlight Material.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Editor/Icons/IconsMaterial.flax (Stored with Git LFS)

Binary file not shown.

View File

@@ -114,8 +114,7 @@ Material GetMaterialPS(MaterialInput input)
@4 @4
} }
// Programmatically set the line number after all the material inputs which have a variable number of line endings // Fix line for errors/warnings for shader code from template
// This allows shader error line numbers after this point to be the same regardless of which material is being compiled
#line 1000 #line 1000
// Input macro specified by the material: DECAL_BLEND_MODE // Input macro specified by the material: DECAL_BLEND_MODE
@@ -160,10 +159,7 @@ void PS_Decal(
float3 positionWS = positionHS.xyz / positionHS.w; float3 positionWS = positionHS.xyz / positionHS.w;
float3 positionOS = mul(float4(positionWS, 1), InvWorld).xyz; float3 positionOS = mul(float4(positionWS, 1), InvWorld).xyz;
// Clip content outside the decal
clip(0.5 - abs(positionOS.xyz)); clip(0.5 - abs(positionOS.xyz));
// By default, map textures using the vectors perpendicular to the projection direction
float2 decalUVs = positionOS.xz + 0.5f; float2 decalUVs = positionOS.xz + 0.5f;
// Setup material input // Setup material input

View File

@@ -197,8 +197,7 @@ Material GetMaterialPS(MaterialInput input)
@4 @4
} }
// Programmatically set the line number after all the material inputs which have a variable number of line endings // Fix line for errors/warnings for shader code from template
// This allows shader error line numbers after this point to be the same regardless of which material is being compiled
#line 1000 #line 1000
// Vertex Shader function for GUI materials rendering // Vertex Shader function for GUI materials rendering

View File

@@ -330,8 +330,7 @@ Material GetMaterialPS(MaterialInput input)
@4 @4
} }
// Programmatically set the line number after all the material inputs which have a variable number of line endings // Fix line for errors/warnings for shader code from template
// This allows shader error line numbers after this point to be the same regardless of which material is being compiled
#line 1000 #line 1000
// Calculates the transform matrix from mesh tangent space to local space // Calculates the transform matrix from mesh tangent space to local space
@@ -834,7 +833,7 @@ float4 PS_Distortion(PixelInput input) : SV_Target0
// Scale up for better precision in low/subtle refractions at the expense of artefacts at higher refraction // Scale up for better precision in low/subtle refractions at the expense of artefacts at higher refraction
distortion *= 4.0f; distortion *= 4.0f;
// Store positive and negative offsets separately // Use separate storage for positive and negative offsets
float2 addOffset = max(distortion, 0); float2 addOffset = max(distortion, 0);
float2 subOffset = abs(min(distortion, 0)); float2 subOffset = abs(min(distortion, 0));
return float4(addOffset.x, addOffset.y, subOffset.x, subOffset.y); return float4(addOffset.x, addOffset.y, subOffset.x, subOffset.y);

View File

@@ -134,8 +134,7 @@ Material GetMaterialPS(MaterialInput input)
@4 @4
} }
// Programmatically set the line number after all the material inputs which have a variable number of line endings // Fix line for errors/warnings for shader code from template
// This allows shader error line numbers after this point to be the same regardless of which material is being compiled
#line 1000 #line 1000
// Pixel Shader function for PostFx materials rendering // Pixel Shader function for PostFx materials rendering

View File

@@ -340,8 +340,7 @@ Material GetMaterialPS(MaterialInput input)
@4 @4
} }
// Programmatically set the line number after all the material inputs which have a variable number of line endings // Fix line for errors/warnings for shader code from template
// This allows shader error line numbers after this point to be the same regardless of which material is being compiled
#line 1000 #line 1000
// Calculates the transform matrix from mesh tangent space to local space // Calculates the transform matrix from mesh tangent space to local space
@@ -500,7 +499,7 @@ float3x4 GetBoneMatrix(int index)
} }
// Calculates the transposed transform matrix for the given vertex (uses blending) // Calculates the transposed transform matrix for the given vertex (uses blending)
float3x4 CalcBoneMatrix(ModelInput_Skinned input) float3x4 GetBoneMatrix(ModelInput_Skinned input)
{ {
float3x4 boneMatrix = input.BlendWeights.x * GetBoneMatrix(input.BlendIndices.x); float3x4 boneMatrix = input.BlendWeights.x * GetBoneMatrix(input.BlendIndices.x);
boneMatrix += input.BlendWeights.y * GetBoneMatrix(input.BlendIndices.y); boneMatrix += input.BlendWeights.y * GetBoneMatrix(input.BlendIndices.y);
@@ -549,7 +548,7 @@ VertexOutput VS_Skinned(ModelInput_Skinned input)
// Perform skinning // Perform skinning
SkinningData data; SkinningData data;
data.BlendMatrix = CalcBoneMatrix(input); data.BlendMatrix = GetBoneMatrix(input);
float3 position = SkinPosition(input, data); float3 position = SkinPosition(input, data);
float3x3 tangentToLocal = SkinTangents(input, data); float3x3 tangentToLocal = SkinTangents(input, data);
@@ -808,7 +807,6 @@ TessalationDSToPS DS(TessalationPatch constantData, float3 barycentricCoords : S
#define COPY(thing) output.thing = input[0].thing #define COPY(thing) output.thing = input[0].thing
INTERPOLATE(Position); INTERPOLATE(Position);
#if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PN #if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PN
// Precompute squares and squares * 3
float UU = U * U; float UU = U * U;
float VV = V * V; float VV = V * V;
float WW = W * W; float WW = W * W;

View File

@@ -337,8 +337,7 @@ Material GetMaterialPS(MaterialInput input)
@4 @4
} }
// Programmatically set the line number after all the material inputs which have a variable number of line endings // Fix line for errors/warnings for shader code from template
// This allows shader error line numbers after this point to be the same regardless of which material is being compiled
#line 1000 #line 1000
// Calculates the transform matrix from mesh tangent space to local space // Calculates the transform matrix from mesh tangent space to local space
@@ -474,7 +473,7 @@ float3x4 GetBoneMatrix(int index)
} }
// Calculates the transposed transform matrix for the given vertex (uses blending) // Calculates the transposed transform matrix for the given vertex (uses blending)
float3x4 CalcBoneMatrix(ModelInput_Skinned input) float3x4 GetBoneMatrix(ModelInput_Skinned input)
{ {
float3x4 boneMatrix = input.BlendWeights.x * GetBoneMatrix(input.BlendIndices.x); float3x4 boneMatrix = input.BlendWeights.x * GetBoneMatrix(input.BlendIndices.x);
boneMatrix += input.BlendWeights.y * GetBoneMatrix(input.BlendIndices.y); boneMatrix += input.BlendWeights.y * GetBoneMatrix(input.BlendIndices.y);
@@ -521,7 +520,7 @@ VertexOutput VS_Skinned(ModelInput_Skinned input)
// Perform skinning // Perform skinning
SkinningData data; SkinningData data;
data.BlendMatrix = CalcBoneMatrix(input); data.BlendMatrix = GetBoneMatrix(input);
float3 position = SkinPosition(input, data); float3 position = SkinPosition(input, data);
half3x3 tangentToLocal = SkinTangents(input, data); half3x3 tangentToLocal = SkinTangents(input, data);
@@ -755,7 +754,6 @@ TessalationDSToPS DS(TessalationPatch constantData, float3 barycentricCoords : S
#define COPY(thing) output.thing = input[0].thing #define COPY(thing) output.thing = input[0].thing
INTERPOLATE(Position); INTERPOLATE(Position);
#if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PN #if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PN
// Precompute squares and squares * 3
float UU = U * U; float UU = U * U;
float VV = V * V; float VV = V * V;
float WW = W * W; float WW = W * W;
@@ -978,7 +976,7 @@ float4 PS_Distortion(PixelInput input) : SV_Target0
// Scale up for better precision in low/subtle refractions at the expense of artefacts at higher refraction // Scale up for better precision in low/subtle refractions at the expense of artefacts at higher refraction
distortion *= 4.0f; distortion *= 4.0f;
// Store positive and negative offsets separately // Use separate storage for positive and negative offsets
float2 addOffset = max(distortion, 0); float2 addOffset = max(distortion, 0);
float2 subOffset = abs(min(distortion, 0)); float2 subOffset = abs(min(distortion, 0));
return float4(addOffset.x, addOffset.y, subOffset.x, subOffset.y); return float4(addOffset.x, addOffset.y, subOffset.x, subOffset.y);

View File

@@ -234,8 +234,7 @@ Material GetMaterialPS(MaterialInput input)
@4 @4
} }
// Programmatically set the line number after all the material inputs which have a variable number of line endings // Fix line for errors/warnings for shader code from template
// This allows shader error line numbers after this point to be the same regardless of which material is being compiled
#line 1000 #line 1000
// Calculates LOD value (with fractional part for blending) // Calculates LOD value (with fractional part for blending)
@@ -595,7 +594,6 @@ TessalationDSToPS DS(TessalationPatch constantData, float3 barycentricCoords : S
#define COPY(thing) output.thing = input[0].thing #define COPY(thing) output.thing = input[0].thing
INTERPOLATE(Position); INTERPOLATE(Position);
#if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PN #if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PN
// Precompute squares and squares * 3
float UU = U * U; float UU = U * U;
float VV = V * V; float VV = V * V;
float WW = W * W; float WW = W * W;

Binary file not shown.

BIN
Content/Editor/Wires Debug Material.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Engine/DefaultMaterial.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Engine/DefaultTerrainMaterial.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/ColorGrading.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/Forward.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/PostProcessing.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/VolumetricFog.flax (Stored with Git LFS)

Binary file not shown.

View File

@@ -115,11 +115,9 @@ namespace FlaxEditor.Viewport.Previews
var color = Color; var color = Color;
if (!EnabledInHierarchy) if (!EnabledInHierarchy)
color *= 0.4f; color *= 0.4f;
var sampleValueScale = height / info.NumChannels;
// Compute the scaled y-value used to render the channel data // Calculate the amount of samples that are contained in the view
float sampleYScale = height / info.NumChannels;
// Compute amount of samples that are contained in the view
float unitsPerSecond = UnitsPerSecond * ViewScale; float unitsPerSecond = UnitsPerSecond * ViewScale;
float clipDefaultWidth = length * unitsPerSecond; float clipDefaultWidth = length * unitsPerSecond;
float clipsInView = width / clipDefaultWidth; float clipsInView = width / clipDefaultWidth;
@@ -173,7 +171,7 @@ namespace FlaxEditor.Viewport.Previews
if (samplesInPixel > 0) if (samplesInPixel > 0)
{ {
float sampleValueAvg = samplesSum / samplesInPixel; float sampleValueAvg = samplesSum / samplesInPixel;
float sampleValueAvgScaled = sampleValueAvg * sampleYScale; float sampleValueAvgScaled = sampleValueAvg * sampleValueScale;
if (sampleValueAvgScaled > 0.1f) if (sampleValueAvgScaled > 0.1f)
{ {
Render2D.DrawLine(new Vector2(pixelX, yCenter - sampleValueAvgScaled), new Vector2(pixelX, yCenter + sampleValueAvgScaled), color); Render2D.DrawLine(new Vector2(pixelX, yCenter - sampleValueAvgScaled), new Vector2(pixelX, yCenter + sampleValueAvgScaled), color);

View File

@@ -300,46 +300,35 @@ float IESLoader::ComputeFilterPos(float value, const Array<float>& sortedValues)
{ {
return 0.0f; return 0.0f;
} }
if (value > sortedValues[endPos]) if (value > sortedValues[endPos])
{ {
return static_cast<float>(endPos); return static_cast<float>(endPos);
} }
// Binary search
while (startPos < endPos) while (startPos < endPos)
{ {
const uint32 testPos = (startPos + endPos + 1) / 2; const uint32 testPos = (startPos + endPos + 1) / 2;
const float testValue = sortedValues[testPos]; const float testValue = sortedValues[testPos];
if (value >= testValue) if (value >= testValue)
{ {
// Prevent endless loop
ASSERT(startPos != testPos); ASSERT(startPos != testPos);
startPos = testPos; startPos = testPos;
} }
else else
{ {
// Prevent endless loop
ASSERT(endPos != testPos - 1); ASSERT(endPos != testPos - 1);
endPos = testPos - 1; endPos = testPos - 1;
} }
} }
const float leftValue = sortedValues[startPos]; const float leftValue = sortedValues[startPos];
float fraction = 0.0f; float fraction = 0.0f;
if (startPos + 1 < static_cast<uint32>(sortedValues.Count())) if (startPos + 1 < static_cast<uint32>(sortedValues.Count()))
{ {
// If not at right border
const float rightValue = sortedValues[startPos + 1]; const float rightValue = sortedValues[startPos + 1];
const float deltaValue = rightValue - leftValue; const float deltaValue = rightValue - leftValue;
if (deltaValue > 0.00005f)
if (deltaValue > 0.0001f)
{ {
fraction = (value - leftValue) / deltaValue; fraction = (value - leftValue) / deltaValue;
} }

View File

@@ -45,22 +45,13 @@ uint32 Math::FloorLog2(uint32 value)
Vector3 Math::RotateAboutAxis(const Vector3& normalizedRotationAxis, float angle, const Vector3& positionOnAxis, const Vector3& position) 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
const Vector3 closestPointOnAxis = positionOnAxis + normalizedRotationAxis * Vector3::Dot(normalizedRotationAxis, position - positionOnAxis); const Vector3 closestPointOnAxis = positionOnAxis + normalizedRotationAxis * Vector3::Dot(normalizedRotationAxis, position - positionOnAxis);
// Construct orthogonal axes in the plane of the rotation
const Vector3 axisU = position - closestPointOnAxis; const Vector3 axisU = position - closestPointOnAxis;
const Vector3 axisV = Vector3::Cross(normalizedRotationAxis, axisU); const Vector3 axisV = Vector3::Cross(normalizedRotationAxis, axisU);
float cosAngle, sinAngle; float cosAngle, sinAngle;
Math::SinCos(angle, sinAngle, cosAngle); Math::SinCos(angle, sinAngle, cosAngle);
// Rotate using the orthogonal axes
const Vector3 rotation = axisU * cosAngle + axisV * sinAngle; const Vector3 rotation = axisU * cosAngle + axisV * sinAngle;
// Reconstruct the rotated world space position
const Vector3 rotatedPosition = closestPointOnAxis + rotation; const Vector3 rotatedPosition = closestPointOnAxis + rotation;
// Convert from position to a position offset
return rotatedPosition - position; return rotatedPosition - position;
} }

View File

@@ -216,7 +216,6 @@ void Plane::Transform(Plane planes[], int32 planesCount, const Quaternion& rotat
const float y = planes[i].Normal.Y; const float y = planes[i].Normal.Y;
const float z = planes[i].Normal.Z; const float z = planes[i].Normal.Z;
// Factor common arithmetic out of loop
planes[i].Normal.X = x * (1.0f - yy - zz) + y * (xy - wz) + z * (xz + wy); planes[i].Normal.X = x * (1.0f - yy - zz) + y * (xy - wz) + z * (xz + wy);
planes[i].Normal.Y = x * (xy + wz) + y * (1.0f - xx - zz) + z * (yz - wx); planes[i].Normal.Y = x * (xy + wz) + y * (1.0f - xx - zz) + z * (yz - wx);
planes[i].Normal.Z = x * (xz - wy) + y * (yz + wx) + z * (1.0f - xx - yy); planes[i].Normal.Z = x * (xz - wy) + y * (yz + wx) + z * (1.0f - xx - yy);

View File

@@ -56,7 +56,6 @@ int32 DateTime::GetDay() const
DayOfWeek DateTime::GetDayOfWeek() const DayOfWeek DateTime::GetDayOfWeek() const
{ {
// January 1, 0001 was a Monday
return static_cast<DayOfWeek>((Ticks / Constants::TicksPerDay) % 7); return static_cast<DayOfWeek>((Ticks / Constants::TicksPerDay) % 7);
} }
@@ -64,8 +63,8 @@ int32 DateTime::GetDayOfYear() const
{ {
int32 year, month, day; int32 year, month, day;
GetDate(year, month, day); GetDate(year, month, day);
for (int32 currentMonth = 1; currentMonth < month; currentMonth++) for (int32 i = 1; i < month; i++)
day += DaysInMonth(year, currentMonth); day += DaysInMonth(year, i);
return day; return day;
} }
@@ -131,13 +130,7 @@ DateTime DateTime::NowUTC()
bool DateTime::Validate(int32 year, int32 month, int32 day, int32 hour, int32 minute, int32 second, int32 millisecond) bool DateTime::Validate(int32 year, int32 month, int32 day, int32 hour, int32 minute, int32 second, int32 millisecond)
{ {
return (year >= 1) && (year <= 9999) && return year >= 1 && year <= 999999 && month >= 1 && month <= 12 && day >= 1 && day <= DaysInMonth(year, month) && hour >= 0 && hour <= 23 && minute >= 0 && minute <= 59 && second >= 0 && second <= 59 && millisecond >= 0 && millisecond <= 999;
(month >= 1) && (month <= 12) &&
(day >= 1) && (day <= DaysInMonth(year, month)) &&
(hour >= 0) && (hour <= 23) &&
(minute >= 0) && (minute <= 59) &&
(second >= 0) && (second <= 59) &&
(millisecond >= 0) && (millisecond <= 999);
} }
String DateTime::ToString() const String DateTime::ToString() const

View File

@@ -33,7 +33,7 @@ TimeSpan TimeSpan::FromSeconds(double seconds)
return TimeSpan(static_cast<int64>(seconds * Constants::TicksPerSecond)); return TimeSpan(static_cast<int64>(seconds * Constants::TicksPerSecond));
} }
void TimeSpan::Assign(int32 days, int32 hours, int32 minutes, int32 seconds, int32 milliseconds) void TimeSpan::Set(int32 days, int32 hours, int32 minutes, int32 seconds, int32 milliseconds)
{ {
const int64 totalMs = 1000 * (60 * 60 * 24 * (int64)days + 60 * 60 * (int64)hours + 60 * (int64)minutes + (int64)seconds) + (int64)milliseconds; const int64 totalMs = 1000 * (60 * 60 * 24 * (int64)days + 60 * 60 * (int64)hours + 60 * (int64)minutes + (int64)seconds) + (int64)milliseconds;
ASSERT_LOW_LAYER((totalMs >= MinValue().GetTotalMilliseconds()) && (totalMs <= MaxValue().GetTotalMilliseconds())); ASSERT_LOW_LAYER((totalMs >= MinValue().GetTotalMilliseconds()) && (totalMs <= MaxValue().GetTotalMilliseconds()));

View File

@@ -49,8 +49,10 @@ public:
{ {
} }
// Init /// <summary>
// @param ticks The number of ticks /// Initializes a new instance of the <see cref="TimeSpan"/> struct.
/// </summary>
/// <param name="ticks">The ticks in 100 nanoseconds resolution.</param>
TimeSpan(int64 ticks) TimeSpan(int64 ticks)
: Ticks(ticks) : Ticks(ticks)
{ {
@@ -62,7 +64,7 @@ public:
// @param Minutes Amount of minutes // @param Minutes Amount of minutes
TimeSpan(int32 days, int32 hours, int32 minutes) TimeSpan(int32 days, int32 hours, int32 minutes)
{ {
Assign(days, hours, minutes, 0, 0); Set(days, hours, minutes, 0, 0);
} }
// Init // Init
@@ -72,7 +74,7 @@ public:
// @param Seconds Amount of seconds // @param Seconds Amount of seconds
TimeSpan(int32 days, int32 hours, int32 minutes, int32 seconds) TimeSpan(int32 days, int32 hours, int32 minutes, int32 seconds)
{ {
Assign(days, hours, minutes, seconds, 0); Set(days, hours, minutes, seconds, 0);
} }
// Init // Init
@@ -83,7 +85,7 @@ public:
// @param Milliseconds Amount of milliseconds // @param Milliseconds Amount of milliseconds
TimeSpan(int32 days, int32 hours, int32 minutes, int32 seconds, int32 milliseconds) TimeSpan(int32 days, int32 hours, int32 minutes, int32 seconds, int32 milliseconds)
{ {
Assign(days, hours, minutes, seconds, milliseconds); Set(days, hours, minutes, seconds, milliseconds);
} }
public: public:
@@ -325,7 +327,7 @@ public:
private: private:
void Assign(int32 days, int32 hours, int32 minutes, int32 seconds, int32 milliseconds); void Set(int32 days, int32 hours, int32 minutes, int32 seconds, int32 milliseconds);
}; };
inline TimeSpan operator*(float scalar, const TimeSpan& timespan) inline TimeSpan operator*(float scalar, const TimeSpan& timespan)

View File

@@ -46,13 +46,13 @@ public:
{ {
ASSERT(_subresourceState.IsEmpty() && subresourceCount > 0); ASSERT(_subresourceState.IsEmpty() && subresourceCount > 0);
// Allocate space for per-subresource tracking structures
if (usePerSubresourceTracking && subresourceCount > 1)
_subresourceState.Resize(subresourceCount, false);
// Initialize state // Initialize state
_allSubresourcesSame = true; _allSubresourcesSame = true;
_resourceState = initialState; _resourceState = initialState;
// Allocate space for per-subresource state tracking
if (usePerSubresourceTracking && subresourceCount > 1)
_subresourceState.Resize(subresourceCount, false);
#if BUILD_DEBUG #if BUILD_DEBUG
_subresourceState.SetAll(InvalidState); _subresourceState.SetAll(InvalidState);
#endif #endif
@@ -124,7 +124,7 @@ public:
void SetSubresourceState(int32 subresourceIndex, StateType state) void SetSubresourceState(int32 subresourceIndex, StateType state)
{ {
// If setting all subresources, or the resource only has a single subresource, set the per-resource state // Check if use single state for the whole resource
if (subresourceIndex == -1 || _subresourceState.Count() <= 1) if (subresourceIndex == -1 || _subresourceState.Count() <= 1)
{ {
SetResourceState(state); SetResourceState(state);
@@ -133,16 +133,14 @@ public:
{ {
ASSERT(subresourceIndex < static_cast<int32>(_subresourceState.Count())); ASSERT(subresourceIndex < static_cast<int32>(_subresourceState.Count()));
// If state was previously tracked on a per-resource level, then transition to per-subresource tracking // Transition for all sub-resources
if (_allSubresourcesSame) if (_allSubresourcesSame)
{ {
for (int32 i = 0; i < _subresourceState.Count(); i++) for (int32 i = 0; i < _subresourceState.Count(); i++)
{ {
_subresourceState[i] = _resourceState; _subresourceState[i] = _resourceState;
} }
_allSubresourcesSame = 0; _allSubresourcesSame = 0;
#if BUILD_DEBUG #if BUILD_DEBUG
_resourceState = InvalidState; _resourceState = InvalidState;
#endif #endif

View File

@@ -23,9 +23,8 @@
#define DX11_FORCE_USE_DX10 0 #define DX11_FORCE_USE_DX10 0
#define DX11_FORCE_USE_DX10_1 0 #define DX11_FORCE_USE_DX10_1 0
static bool TryCreateDevice(IDXGIAdapter* adapter, D3D_FEATURE_LEVEL maxFeatureLevel, D3D_FEATURE_LEVEL* outFeatureLevel) static bool TryCreateDevice(IDXGIAdapter* adapter, D3D_FEATURE_LEVEL maxFeatureLevel, D3D_FEATURE_LEVEL* featureLevel)
{ {
// Temporary data
ID3D11Device* device = nullptr; ID3D11Device* device = nullptr;
ID3D11DeviceContext* context = nullptr; ID3D11DeviceContext* context = nullptr;
uint32 deviceFlags = D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_BGRA_SUPPORT; uint32 deviceFlags = D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_BGRA_SUPPORT;
@@ -33,26 +32,22 @@ static bool TryCreateDevice(IDXGIAdapter* adapter, D3D_FEATURE_LEVEL maxFeatureL
deviceFlags |= D3D11_CREATE_DEVICE_DEBUG; deviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif #endif
D3D_FEATURE_LEVEL requestedFeatureLevels[] = // Pick the first level
D3D_FEATURE_LEVEL featureLevels[] =
{ {
D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0 D3D_FEATURE_LEVEL_10_0
}; };
int32 levelIndex = 0;
int32 firstAllowedFeatureLevel = 0; while (levelIndex < ARRAY_COUNT(featureLevels))
int32 numAllowedFeatureLevels = ARRAY_COUNT(requestedFeatureLevels);
while (firstAllowedFeatureLevel < numAllowedFeatureLevels)
{
if (requestedFeatureLevels[firstAllowedFeatureLevel] == maxFeatureLevel)
{ {
if (featureLevels[levelIndex] == maxFeatureLevel)
break; break;
levelIndex++;
} }
firstAllowedFeatureLevel++; if (levelIndex >= ARRAY_COUNT(featureLevels))
}
numAllowedFeatureLevels -= firstAllowedFeatureLevel;
if (numAllowedFeatureLevels == 0)
{ {
return false; return false;
} }
@@ -63,18 +58,16 @@ static bool TryCreateDevice(IDXGIAdapter* adapter, D3D_FEATURE_LEVEL maxFeatureL
D3D_DRIVER_TYPE_UNKNOWN, D3D_DRIVER_TYPE_UNKNOWN,
NULL, NULL,
deviceFlags, deviceFlags,
&requestedFeatureLevels[firstAllowedFeatureLevel], &featureLevels[levelIndex],
numAllowedFeatureLevels, ARRAY_COUNT(featureLevels) - levelIndex,
D3D11_SDK_VERSION, D3D11_SDK_VERSION,
&device, &device,
outFeatureLevel, featureLevel,
&context &context
))) )))
{ {
// Release created stuff
device->Release(); device->Release();
context->Release(); context->Release();
return true; return true;
} }

View File

@@ -144,10 +144,8 @@ bool GPUTextureDX12::OnInit()
{ {
resourceDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; resourceDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
initialState = D3D12_RESOURCE_STATE_DEPTH_WRITE; initialState = D3D12_RESOURCE_STATE_DEPTH_WRITE;
if (!useSRV) if (!useSRV)
{ {
// Only deny shader resources if it's a depth resource that will never be used as SRV
resourceDesc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE; resourceDesc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
} }
} }

View File

@@ -86,7 +86,7 @@ void QueryHeapDX12::EndQueryBatchAndResolveQueryData(GPUContextDX12* context)
{ {
ASSERT(_currentBatch.Open); ASSERT(_currentBatch.Open);
// Discard empty batches // Skip empty batches
if (_currentBatch.Count == 0) if (_currentBatch.Count == 0)
{ {
return; return;

View File

@@ -297,7 +297,7 @@ void CmdBufferManagerVulkan::PrepareForNewActiveCommandBuffer()
} }
} }
// All cmd buffers are being executed still // Always begin fresh command buffer for rendering
_activeCmdBuffer = _pool.Create(); _activeCmdBuffer = _pool.Create();
_activeCmdBuffer->Begin(); _activeCmdBuffer->Begin();

View File

@@ -32,7 +32,6 @@ void DescriptorSetLayoutInfoVulkan::CacheTypesUsageID()
void DescriptorSetLayoutInfoVulkan::AddDescriptor(int32 descriptorSetIndex, const VkDescriptorSetLayoutBinding& descriptor) void DescriptorSetLayoutInfoVulkan::AddDescriptor(int32 descriptorSetIndex, const VkDescriptorSetLayoutBinding& descriptor)
{ {
// Increment type usage
_layoutTypes[descriptor.descriptorType]++; _layoutTypes[descriptor.descriptorType]++;
if (descriptorSetIndex >= _setLayouts.Count()) if (descriptorSetIndex >= _setLayouts.Count())
@@ -43,7 +42,6 @@ void DescriptorSetLayoutInfoVulkan::AddDescriptor(int32 descriptorSetIndex, cons
SetLayout& descSetLayout = _setLayouts[descriptorSetIndex]; SetLayout& descSetLayout = _setLayouts[descriptorSetIndex];
descSetLayout.LayoutBindings.Add(descriptor); descSetLayout.LayoutBindings.Add(descriptor);
// TODO: manual hash update method?
_hash = Crc::MemCrc32(&descriptor, sizeof(descriptor), _hash); _hash = Crc::MemCrc32(&descriptor, sizeof(descriptor), _hash);
} }
@@ -116,20 +114,20 @@ void DescriptorSetLayoutVulkan::Compile()
DescriptorPoolVulkan::DescriptorPoolVulkan(GPUDeviceVulkan* device, const DescriptorSetLayoutVulkan& layout) DescriptorPoolVulkan::DescriptorPoolVulkan(GPUDeviceVulkan* device, const DescriptorSetLayoutVulkan& layout)
: _device(device) : _device(device)
, _handle(VK_NULL_HANDLE) , _handle(VK_NULL_HANDLE)
, DescriptorSetsMax(0) , _descriptorSetsMax(0)
, AllocatedDescriptorSetsCount(0) , _allocatedDescriptorSetsCount(0)
, AllocatedDescriptorSetsCountMax(0) , _allocatedDescriptorSetsCountMax(0)
, Layout(layout) , _layout(layout)
{ {
Array<VkDescriptorPoolSize, FixedAllocation<VULKAN_DESCRIPTOR_TYPE_END + 1>> types; Array<VkDescriptorPoolSize, FixedAllocation<VULKAN_DESCRIPTOR_TYPE_END + 1>> types;
// The maximum amount of descriptor sets layout allocations to hold // The maximum amount of descriptor sets layout allocations to hold
const uint32 MaxSetsAllocations = 256; const uint32 MaxSetsAllocations = 256;
DescriptorSetsMax = MaxSetsAllocations * (VULKAN_HASH_POOLS_WITH_TYPES_USAGE_ID ? 1 : Layout.GetLayouts().Count()); _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++) for (uint32 typeIndex = VULKAN_DESCRIPTOR_TYPE_BEGIN; typeIndex <= VULKAN_DESCRIPTOR_TYPE_END; typeIndex++)
{ {
const VkDescriptorType descriptorType = (VkDescriptorType)typeIndex; const VkDescriptorType descriptorType = (VkDescriptorType)typeIndex;
const uint32 typesUsed = Layout.GetTypesUsed(descriptorType); const uint32 typesUsed = _layout.GetTypesUsed(descriptorType);
if (typesUsed > 0) if (typesUsed > 0)
{ {
VkDescriptorPoolSize& type = types.AddOne(); VkDescriptorPoolSize& type = types.AddOne();
@@ -144,7 +142,7 @@ DescriptorPoolVulkan::DescriptorPoolVulkan(GPUDeviceVulkan* device, const Descri
createInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; createInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
createInfo.poolSizeCount = types.Count(); createInfo.poolSizeCount = types.Count();
createInfo.pPoolSizes = types.Get(); createInfo.pPoolSizes = types.Get();
createInfo.maxSets = DescriptorSetsMax; createInfo.maxSets = _descriptorSetsMax;
VALIDATE_VULKAN_RESULT(vkCreateDescriptorPool(_device->Device, &createInfo, nullptr, &_handle)); VALIDATE_VULKAN_RESULT(vkCreateDescriptorPool(_device->Device, &createInfo, nullptr, &_handle));
} }
@@ -156,16 +154,16 @@ DescriptorPoolVulkan::~DescriptorPoolVulkan()
} }
} }
void DescriptorPoolVulkan::TrackAddUsage(const DescriptorSetLayoutVulkan& layout) void DescriptorPoolVulkan::Track(const DescriptorSetLayoutVulkan& layout)
{ {
// Check and increment our current type usage #if !BUILD_RELEASE
for (uint32 typeIndex = VULKAN_DESCRIPTOR_TYPE_BEGIN; typeIndex <= VULKAN_DESCRIPTOR_TYPE_END; typeIndex++) for (uint32 typeIndex = VULKAN_DESCRIPTOR_TYPE_BEGIN; typeIndex <= VULKAN_DESCRIPTOR_TYPE_END; typeIndex++)
{ {
ASSERT(Layout.GetTypesUsed((VkDescriptorType)typeIndex) == layout.GetTypesUsed((VkDescriptorType)typeIndex)); ASSERT(_layout.GetTypesUsed((VkDescriptorType)typeIndex) == layout.GetTypesUsed((VkDescriptorType)typeIndex));
} }
#endif
AllocatedDescriptorSetsCount += layout.GetLayouts().Count(); _allocatedDescriptorSetsCount += layout.GetLayouts().Count();
AllocatedDescriptorSetsCountMax = Math::Max(AllocatedDescriptorSetsCount, AllocatedDescriptorSetsCountMax); _allocatedDescriptorSetsCountMax = Math::Max(_allocatedDescriptorSetsCount, _allocatedDescriptorSetsCountMax);
} }
void DescriptorPoolVulkan::TrackRemoveUsage(const DescriptorSetLayoutVulkan& layout) void DescriptorPoolVulkan::TrackRemoveUsage(const DescriptorSetLayoutVulkan& layout)
@@ -173,10 +171,10 @@ void DescriptorPoolVulkan::TrackRemoveUsage(const DescriptorSetLayoutVulkan& lay
// Check and increment our current type usage // Check and increment our current type usage
for (uint32 typeIndex = VULKAN_DESCRIPTOR_TYPE_BEGIN; typeIndex <= VULKAN_DESCRIPTOR_TYPE_END; typeIndex++) for (uint32 typeIndex = VULKAN_DESCRIPTOR_TYPE_BEGIN; typeIndex <= VULKAN_DESCRIPTOR_TYPE_END; typeIndex++)
{ {
ASSERT(Layout.GetTypesUsed((VkDescriptorType)typeIndex) == layout.GetTypesUsed((VkDescriptorType)typeIndex)); ASSERT(_layout.GetTypesUsed((VkDescriptorType)typeIndex) == layout.GetTypesUsed((VkDescriptorType)typeIndex));
} }
AllocatedDescriptorSetsCount -= layout.GetLayouts().Count(); _allocatedDescriptorSetsCount -= layout.GetLayouts().Count();
} }
void DescriptorPoolVulkan::Reset() void DescriptorPoolVulkan::Reset()
@@ -185,7 +183,7 @@ void DescriptorPoolVulkan::Reset()
{ {
VALIDATE_VULKAN_RESULT(vkResetDescriptorPool(_device->Device, _handle, 0)); VALIDATE_VULKAN_RESULT(vkResetDescriptorPool(_device->Device, _handle, 0));
} }
AllocatedDescriptorSetsCount = 0; _allocatedDescriptorSetsCount = 0;
} }
bool DescriptorPoolVulkan::AllocateDescriptorSets(const VkDescriptorSetAllocateInfo& descriptorSetAllocateInfo, VkDescriptorSet* result) bool DescriptorPoolVulkan::AllocateDescriptorSets(const VkDescriptorSetAllocateInfo& descriptorSetAllocateInfo, VkDescriptorSet* result)
@@ -335,8 +333,6 @@ void DescriptorPoolsManagerVulkan::ReleasePoolSet(DescriptorPoolSetContainerVulk
void DescriptorPoolsManagerVulkan::GC() void DescriptorPoolsManagerVulkan::GC()
{ {
ScopeLock lock(_locker); ScopeLock lock(_locker);
// Pool sets are forward allocated - iterate from the back to increase the chance of finding an unused one
for (int32 i = _poolSets.Count() - 1; i >= 0; i--) for (int32 i = _poolSets.Count() - 1; i >= 0; i--)
{ {
const auto poolSet = _poolSets[i]; const auto poolSet = _poolSets[i];
@@ -374,12 +370,12 @@ PipelineLayoutVulkan::~PipelineLayoutVulkan()
} }
} }
uint32 DescriptorSetWriterVulkan::SetupDescriptorWrites(const SpirvShaderDescriptorInfo& info, VkWriteDescriptorSet* writeDescriptors, VkDescriptorImageInfo* imageInfo, VkDescriptorBufferInfo* bufferInfo, uint8* bindingToDynamicOffsetMap) uint32 DescriptorSetWriterVulkan::SetupDescriptorWrites(const SpirvShaderDescriptorInfo& info, VkWriteDescriptorSet* writeDescriptors, VkDescriptorImageInfo* imageInfo, VkDescriptorBufferInfo* bufferInfo, uint8* bindingToDynamicOffset)
{ {
ASSERT(info.DescriptorTypesCount <= 64);
WriteDescriptors = writeDescriptors; WriteDescriptors = writeDescriptors;
WritesCount = info.DescriptorTypesCount; WritesCount = info.DescriptorTypesCount;
ASSERT(info.DescriptorTypesCount <= 64 && TEXT("Out of bits for Dirty Mask! More than 64 resources in one descriptor set!")); BindingToDynamicOffset = bindingToDynamicOffset;
BindingToDynamicOffsetMap = bindingToDynamicOffsetMap;
uint32 dynamicOffsetIndex = 0; uint32 dynamicOffsetIndex = 0;
for (uint32 i = 0; i < info.DescriptorTypesCount; i++) for (uint32 i = 0; i < info.DescriptorTypesCount; i++)
@@ -392,8 +388,8 @@ uint32 DescriptorSetWriterVulkan::SetupDescriptorWrites(const SpirvShaderDescrip
switch (writeDescriptors->descriptorType) switch (writeDescriptors->descriptorType)
{ {
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
BindingToDynamicOffsetMap[i] = dynamicOffsetIndex; BindingToDynamicOffset[i] = dynamicOffsetIndex;
++dynamicOffsetIndex; dynamicOffsetIndex++;
writeDescriptors->pBufferInfo = bufferInfo++; writeDescriptors->pBufferInfo = bufferInfo++;
break; break;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:

View File

@@ -230,16 +230,15 @@ private:
GPUDeviceVulkan* _device; GPUDeviceVulkan* _device;
VkDescriptorPool _handle; VkDescriptorPool _handle;
uint32 DescriptorSetsMax; uint32 _descriptorSetsMax;
uint32 AllocatedDescriptorSetsCount; uint32 _allocatedDescriptorSetsCount;
uint32 AllocatedDescriptorSetsCountMax; uint32 _allocatedDescriptorSetsCountMax;
const DescriptorSetLayoutVulkan& Layout; const DescriptorSetLayoutVulkan& _layout;
public: public:
DescriptorPoolVulkan(GPUDeviceVulkan* device, const DescriptorSetLayoutVulkan& layout); DescriptorPoolVulkan(GPUDeviceVulkan* device, const DescriptorSetLayoutVulkan& layout);
~DescriptorPoolVulkan(); ~DescriptorPoolVulkan();
public: public:
@@ -251,25 +250,24 @@ public:
inline bool IsEmpty() const inline bool IsEmpty() const
{ {
return AllocatedDescriptorSetsCount == 0; return _allocatedDescriptorSetsCount == 0;
} }
inline bool CanAllocate(const DescriptorSetLayoutVulkan& layout) const inline bool CanAllocate(const DescriptorSetLayoutVulkan& layout) const
{ {
return DescriptorSetsMax > AllocatedDescriptorSetsCount + layout.GetLayouts().Count(); return _descriptorSetsMax > _allocatedDescriptorSetsCount + layout.GetLayouts().Count();
} }
inline uint32 GetAllocatedDescriptorSetsCount() const inline uint32 GetAllocatedDescriptorSetsCount() const
{ {
return AllocatedDescriptorSetsCount; return _allocatedDescriptorSetsCount;
} }
void TrackAddUsage(const DescriptorSetLayoutVulkan& layout); public:
void Track(const DescriptorSetLayoutVulkan& layout);
void TrackRemoveUsage(const DescriptorSetLayoutVulkan& layout); void TrackRemoveUsage(const DescriptorSetLayoutVulkan& layout);
void Reset(); void Reset();
bool AllocateDescriptorSets(const VkDescriptorSetAllocateInfo& descriptorSetAllocateInfo, VkDescriptorSet* result); bool AllocateDescriptorSets(const VkDescriptorSetAllocateInfo& descriptorSetAllocateInfo, VkDescriptorSet* result);
}; };
@@ -416,14 +414,14 @@ struct DescriptorSetWriteContainerVulkan
Array<VkDescriptorImageInfo> DescriptorImageInfo; Array<VkDescriptorImageInfo> DescriptorImageInfo;
Array<VkDescriptorBufferInfo> DescriptorBufferInfo; Array<VkDescriptorBufferInfo> DescriptorBufferInfo;
Array<VkWriteDescriptorSet> DescriptorWrites; Array<VkWriteDescriptorSet> DescriptorWrites;
Array<uint8> BindingToDynamicOffsetMap; Array<byte> BindingToDynamicOffset;
void Release() void Release()
{ {
DescriptorImageInfo.Resize(0); DescriptorImageInfo.Resize(0);
DescriptorBufferInfo.Resize(0); DescriptorBufferInfo.Resize(0);
DescriptorWrites.Resize(0); DescriptorWrites.Resize(0);
BindingToDynamicOffsetMap.Resize(0); BindingToDynamicOffset.Resize(0);
} }
}; };
@@ -431,24 +429,14 @@ class DescriptorSetWriterVulkan
{ {
public: public:
VkWriteDescriptorSet* WriteDescriptors; VkWriteDescriptorSet* WriteDescriptors = nullptr;
uint8* BindingToDynamicOffsetMap; byte* BindingToDynamicOffset = nullptr;
uint32* DynamicOffsets; uint32* DynamicOffsets = nullptr;
uint32 WritesCount; uint32 WritesCount = 0;
public: public:
DescriptorSetWriterVulkan() uint32 SetupDescriptorWrites(const SpirvShaderDescriptorInfo& info, VkWriteDescriptorSet* writeDescriptors, VkDescriptorImageInfo* imageInfo, VkDescriptorBufferInfo* bufferInfo, byte* bindingToDynamicOffset);
: WriteDescriptors(nullptr)
, BindingToDynamicOffsetMap(nullptr)
, DynamicOffsets(nullptr)
, WritesCount(0)
{
}
public:
uint32 SetupDescriptorWrites(const SpirvShaderDescriptorInfo& info, VkWriteDescriptorSet* writeDescriptors, VkDescriptorImageInfo* imageInfo, VkDescriptorBufferInfo* bufferInfo, uint8* bindingToDynamicOffsetMap);
bool WriteUniformBuffer(uint32 descriptorIndex, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range) const bool WriteUniformBuffer(uint32 descriptorIndex, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range) const
{ {
@@ -471,7 +459,7 @@ public:
bool edited = DescriptorSet::CopyAndReturnNotEqual(bufferInfo->buffer, buffer); bool edited = DescriptorSet::CopyAndReturnNotEqual(bufferInfo->buffer, buffer);
edited |= DescriptorSet::CopyAndReturnNotEqual(bufferInfo->offset, offset); edited |= DescriptorSet::CopyAndReturnNotEqual(bufferInfo->offset, offset);
edited |= DescriptorSet::CopyAndReturnNotEqual(bufferInfo->range, range); edited |= DescriptorSet::CopyAndReturnNotEqual(bufferInfo->range, range);
const uint8 dynamicOffsetIndex = BindingToDynamicOffsetMap[descriptorIndex]; const byte dynamicOffsetIndex = BindingToDynamicOffset[descriptorIndex];
DynamicOffsets[dynamicOffsetIndex] = dynamicOffset; DynamicOffsets[dynamicOffsetIndex] = dynamicOffset;
return edited; return edited;
} }

View File

@@ -146,7 +146,6 @@ void GPUContextVulkan::AddImageBarrier(GPUTextureViewVulkan* handle, VkImageLayo
{ {
// Transition entire resource at once // Transition entire resource at once
const VkImageLayout srcLayout = state.GetSubresourceState(0); const VkImageLayout srcLayout = state.GetSubresourceState(0);
VkImageSubresourceRange range; VkImageSubresourceRange range;
range.aspectMask = handle->Info.subresourceRange.aspectMask; range.aspectMask = handle->Info.subresourceRange.aspectMask;
range.baseMipLevel = 0; range.baseMipLevel = 0;
@@ -157,7 +156,7 @@ void GPUContextVulkan::AddImageBarrier(GPUTextureViewVulkan* handle, VkImageLayo
} }
else else
{ {
// Slow path. Want to transition the entire resource (with multiple subresources). But they aren't in the same state. // Slow path to transition each subresource
for (int32 i = 0; i < state.GetSubresourcesCount(); i++) for (int32 i = 0; i < state.GetSubresourcesCount(); i++)
{ {
const VkImageLayout srcLayout = state.GetSubresourceState(i); const VkImageLayout srcLayout = state.GetSubresourceState(i);
@@ -174,8 +173,6 @@ void GPUContextVulkan::AddImageBarrier(GPUTextureViewVulkan* handle, VkImageLayo
state.SetSubresourceState(i, dstLayout); state.SetSubresourceState(i, dstLayout);
} }
} }
// The entire resource should now be in the after state on this command list
ASSERT(state.CheckResourceState(dstLayout)); ASSERT(state.CheckResourceState(dstLayout));
} }
@@ -538,7 +535,7 @@ void GPUContextVulkan::UpdateDescriptorSets(GPUPipelineStateVulkan* pipelineStat
remainingHasDescriptorsPerStageMask >>= 1; remainingHasDescriptorsPerStageMask >>= 1;
} }
// Allocate sets based on what changed // Allocate sets if need to
//if (needsWrite) // TODO: write on change only? //if (needsWrite) // TODO: write on change only?
{ {
if (!pipelineState->AllocateDescriptorSets()) if (!pipelineState->AllocateDescriptorSets())
@@ -578,7 +575,7 @@ void GPUContextVulkan::UpdateDescriptorSets(ComputePipelineStateVulkan* pipeline
// Update descriptors // Update descriptors
UpdateDescriptorSets(*pipelineState->DescriptorInfo, pipelineState->DSWriter, needsWrite); UpdateDescriptorSets(*pipelineState->DescriptorInfo, pipelineState->DSWriter, needsWrite);
// Allocate sets based on what changed // Allocate sets if need to
//if (needsWrite) // TODO: write on change only?f //if (needsWrite) // TODO: write on change only?f
{ {
if (!pipelineState->AllocateDescriptorSets()) if (!pipelineState->AllocateDescriptorSets())

View File

@@ -149,12 +149,12 @@ static int FindLayerIndex(const Array<LayerExtension>& list, const char* layerNa
return i; return i;
} }
} }
return INVALID_INDEX; return -1;
} }
static bool ContainsLayer(const Array<LayerExtension>& list, const char* layerName) static bool ContainsLayer(const Array<LayerExtension>& list, const char* layerName)
{ {
return FindLayerIndex(list, layerName) != INVALID_INDEX; return FindLayerIndex(list, layerName) != -1;
} }
static bool FindLayerExtension(const Array<LayerExtension>& list, const char* extensionName, const char*& foundLayer) static bool FindLayerExtension(const Array<LayerExtension>& list, const char* extensionName, const char*& foundLayer)
@@ -400,7 +400,6 @@ void GPUDeviceVulkan::GetInstanceLayersAndExtensions(Array<const char*>& outInst
void GPUDeviceVulkan::GetDeviceExtensionsAndLayers(VkPhysicalDevice gpu, Array<const char*>& outDeviceExtensions, Array<const char*>& outDeviceLayers) void GPUDeviceVulkan::GetDeviceExtensionsAndLayers(VkPhysicalDevice gpu, Array<const char*>& outDeviceExtensions, Array<const char*>& outDeviceLayers)
{ {
Array<LayerExtension> deviceLayerExtensions; Array<LayerExtension> deviceLayerExtensions;
// 0 is reserved for regular device
deviceLayerExtensions.AddDefault(1); deviceLayerExtensions.AddDefault(1);
{ {
uint32 count = 0; uint32 count = 0;
@@ -409,10 +408,10 @@ void GPUDeviceVulkan::GetDeviceExtensionsAndLayers(VkPhysicalDevice gpu, Array<c
properties.AddZeroed(count); properties.AddZeroed(count);
VALIDATE_VULKAN_RESULT(vkEnumerateDeviceLayerProperties(gpu, &count, properties.Get())); VALIDATE_VULKAN_RESULT(vkEnumerateDeviceLayerProperties(gpu, &count, properties.Get()));
ASSERT(count == properties.Count()); ASSERT(count == properties.Count());
for (const VkLayerProperties& Property : properties) for (const VkLayerProperties& property : properties)
{ {
deviceLayerExtensions.AddDefault(1); deviceLayerExtensions.AddDefault(1);
deviceLayerExtensions.Last().Layer = Property; deviceLayerExtensions.Last().Layer = property;
} }
} }
@@ -530,7 +529,6 @@ void GPUDeviceVulkan::GetDeviceExtensionsAndLayers(VkPhysicalDevice gpu, Array<c
return false; return false;
}; };
// Now go through the actual requested lists
Array<const char*> platformExtensions; Array<const char*> platformExtensions;
VulkanPlatform::GetDeviceExtensions(platformExtensions); VulkanPlatform::GetDeviceExtensions(platformExtensions);
for (const char* extension : platformExtensions) for (const char* extension : platformExtensions)

View File

@@ -345,10 +345,6 @@ DeferredDeletionQueueVulkan::~DeferredDeletionQueueVulkan()
void DeferredDeletionQueueVulkan::ReleaseResources(bool deleteImmediately) void DeferredDeletionQueueVulkan::ReleaseResources(bool deleteImmediately)
{ {
ScopeLock lock(&_locker); ScopeLock lock(&_locker);
const VkDevice device = _device->Device;
// Traverse list backwards so the swap switches to elements already tested
const uint64 checkFrame = Engine::FrameCount - VULKAN_RESOURCE_DELETE_SAFE_FRAMES_COUNT; const uint64 checkFrame = Engine::FrameCount - VULKAN_RESOURCE_DELETE_SAFE_FRAMES_COUNT;
for (int32 i = 0; i < _entries.Count(); i++) for (int32 i = 0; i < _entries.Count(); i++)
{ {
@@ -361,24 +357,26 @@ void DeferredDeletionQueueVulkan::ReleaseResources(bool deleteImmediately)
{ {
switch (e->StructureType) switch (e->StructureType)
{ {
#define VK_SWITCH(type) case Type::type: vkDestroy##type(device, (Vk##type)e->Handle, nullptr); break #define SWITCH_CASE(type) case Type::type: vkDestroy##type(_device->Device, (Vk##type)e->Handle, nullptr); break
VK_SWITCH(RenderPass); SWITCH_CASE(RenderPass);
VK_SWITCH(Buffer); SWITCH_CASE(Buffer);
VK_SWITCH(BufferView); SWITCH_CASE(BufferView);
VK_SWITCH(Image); SWITCH_CASE(Image);
VK_SWITCH(ImageView); SWITCH_CASE(ImageView);
VK_SWITCH(Pipeline); SWITCH_CASE(Pipeline);
VK_SWITCH(PipelineLayout); SWITCH_CASE(PipelineLayout);
VK_SWITCH(Framebuffer); SWITCH_CASE(Framebuffer);
VK_SWITCH(DescriptorSetLayout); SWITCH_CASE(DescriptorSetLayout);
VK_SWITCH(Sampler); SWITCH_CASE(Sampler);
VK_SWITCH(Semaphore); SWITCH_CASE(Semaphore);
VK_SWITCH(ShaderModule); SWITCH_CASE(ShaderModule);
VK_SWITCH(Event); SWITCH_CASE(Event);
VK_SWITCH(QueryPool); SWITCH_CASE(QueryPool);
#undef VK_SWITCH #undef SWITCH_CASE
default: default:
#if !BUILD_RELEASE
CRASH; CRASH;
#endif
break; break;
} }
} }
@@ -1068,23 +1066,10 @@ GPUDeviceVulkan::GPUDeviceVulkan(ShaderProfile shaderProfile, GPUAdapterVulkan*
, _renderPasses(512) , _renderPasses(512)
, _framebuffers(512) , _framebuffers(512)
, _layouts(4096) , _layouts(4096)
, MainContext(nullptr)
, Adapter(adapter) , Adapter(adapter)
, Device(VK_NULL_HANDLE)
, DeferredDeletionQueue(this) , DeferredDeletionQueue(this)
, StagingManager(this) , StagingManager(this)
, HelperResources(this) , HelperResources(this)
, GraphicsQueue(nullptr)
, ComputeQueue(nullptr)
, TransferQueue(nullptr)
, PresentQueue(nullptr)
, Allocator(VK_NULL_HANDLE)
, PipelineCache(VK_NULL_HANDLE)
#if VK_EXT_validation_cache
, ValidationCache(VK_NULL_HANDLE)
#endif
, UniformBufferUploader(nullptr)
, DescriptorPoolsManager(nullptr)
{ {
} }
@@ -1151,7 +1136,7 @@ GPUDevice* GPUDeviceVulkan::Create()
} }
if (result == VK_ERROR_EXTENSION_NOT_PRESENT) if (result == VK_ERROR_EXTENSION_NOT_PRESENT)
{ {
// Check for missing extensions // Extensions error
uint32_t propertyCount; uint32_t propertyCount;
vkEnumerateInstanceExtensionProperties(nullptr, &propertyCount, nullptr); vkEnumerateInstanceExtensionProperties(nullptr, &propertyCount, nullptr);
Array<VkExtensionProperties> properties; Array<VkExtensionProperties> properties;
@@ -1159,28 +1144,27 @@ GPUDevice* GPUDeviceVulkan::Create()
vkEnumerateInstanceExtensionProperties(nullptr, &propertyCount, properties.Get()); vkEnumerateInstanceExtensionProperties(nullptr, &propertyCount, properties.Get());
for (const char* extension : InstanceExtensions) for (const char* extension : InstanceExtensions)
{ {
bool extensionFound = false; bool found = false;
for (uint32_t propertyIndex = 0; propertyIndex < propertyCount; propertyIndex++) for (uint32_t propertyIndex = 0; propertyIndex < propertyCount; propertyIndex++)
{ {
if (!StringUtils::Compare(properties[propertyIndex].extensionName, extension)) if (!StringUtils::Compare(properties[propertyIndex].extensionName, extension))
{ {
extensionFound = true; found = true;
break; break;
} }
} }
if (!extensionFound) if (!found)
{ {
LOG(Warning, "Missing required Vulkan extension: {0}", String(extension)); LOG(Warning, "Missing required Vulkan extension: {0}", String(extension));
} }
} }
// Missing extensions
auto error = String::Format(TEXT("Vulkan driver doesn't contain specified extensions:\n{0}\nPlease make sure your layers path is set appropriately.")); auto error = String::Format(TEXT("Vulkan driver doesn't contain specified extensions:\n{0}\nPlease make sure your layers path is set appropriately."));
Platform::Error(*error); Platform::Error(*error);
return nullptr; return nullptr;
} }
if (result != VK_SUCCESS) if (result != VK_SUCCESS)
{ {
// Driver error
LOG(Warning, "Vulkan create instance failed with error code: {0}", RenderToolsVulkan::GetVkErrorString(result)); LOG(Warning, "Vulkan create instance failed with error code: {0}", RenderToolsVulkan::GetVkErrorString(result));
Platform::Fatal(TEXT("Vulkan failed to create instance\n\nDo you have a compatible Vulkan driver installed?")); Platform::Fatal(TEXT("Vulkan failed to create instance\n\nDo you have a compatible Vulkan driver installed?"));
return nullptr; return nullptr;
@@ -1560,7 +1544,7 @@ bool GPUDeviceVulkan::Init()
_state = DeviceState::Created; _state = DeviceState::Created;
const auto gpu = Adapter->Gpu; const auto gpu = Adapter->Gpu;
// Query queues properties // Get queues properties
uint32 queueCount = 0; uint32 queueCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queueCount, nullptr); vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queueCount, nullptr);
ASSERT(queueCount >= 1); ASSERT(queueCount >= 1);
@@ -1570,23 +1554,21 @@ bool GPUDeviceVulkan::Init()
// Query device features // Query device features
vkGetPhysicalDeviceFeatures(Adapter->Gpu, &PhysicalDeviceFeatures); vkGetPhysicalDeviceFeatures(Adapter->Gpu, &PhysicalDeviceFeatures);
// Setup extension and layer info // Get extensions and layers
VkDeviceCreateInfo deviceInfo;
RenderToolsVulkan::ZeroStruct(deviceInfo, VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO);
Array<const char*> deviceExtensions; Array<const char*> deviceExtensions;
Array<const char*> validationLayers; Array<const char*> validationLayers;
GetDeviceExtensionsAndLayers(gpu, deviceExtensions, validationLayers); GetDeviceExtensionsAndLayers(gpu, deviceExtensions, validationLayers);
ParseOptionalDeviceExtensions(deviceExtensions); ParseOptionalDeviceExtensions(deviceExtensions);
// Setup device info
VkDeviceCreateInfo deviceInfo;
RenderToolsVulkan::ZeroStruct(deviceInfo, VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO);
deviceInfo.enabledExtensionCount = deviceExtensions.Count(); deviceInfo.enabledExtensionCount = deviceExtensions.Count();
deviceInfo.ppEnabledExtensionNames = deviceExtensions.Get(); deviceInfo.ppEnabledExtensionNames = deviceExtensions.Get();
deviceInfo.enabledLayerCount = validationLayers.Count(); deviceInfo.enabledLayerCount = validationLayers.Count();
deviceInfo.ppEnabledLayerNames = deviceInfo.enabledLayerCount > 0 ? validationLayers.Get() : nullptr; deviceInfo.ppEnabledLayerNames = deviceInfo.enabledLayerCount > 0 ? validationLayers.Get() : nullptr;
// Setup Queue info // Setup queues info
Array<VkDeviceQueueCreateInfo> queueFamilyInfos; Array<VkDeviceQueueCreateInfo> queueFamilyInfos;
int32 graphicsQueueFamilyIndex = -1; int32 graphicsQueueFamilyIndex = -1;
int32 computeQueueFamilyIndex = -1; int32 computeQueueFamilyIndex = -1;
@@ -1655,7 +1637,6 @@ bool GPUDeviceVulkan::Init()
numPriorities += curProps.queueCount; numPriorities += curProps.queueCount;
LOG(Info, "- queue family {0}: {1} queues{2}", familyIndex, curProps.queueCount, queueTypeInfo); LOG(Info, "- queue family {0}: {1} queues{2}", familyIndex, curProps.queueCount, queueTypeInfo);
} }
Array<float> queuePriorities; Array<float> queuePriorities;
queuePriorities.AddDefault(numPriorities); queuePriorities.AddDefault(numPriorities);
float* currentPriority = queuePriorities.Get(); float* currentPriority = queuePriorities.Get();
@@ -1663,14 +1644,12 @@ bool GPUDeviceVulkan::Init()
{ {
VkDeviceQueueCreateInfo& queue = queueFamilyInfos[index]; VkDeviceQueueCreateInfo& queue = queueFamilyInfos[index];
queue.pQueuePriorities = currentPriority; queue.pQueuePriorities = currentPriority;
const VkQueueFamilyProperties& properties = QueueFamilyProps[queue.queueFamilyIndex]; const VkQueueFamilyProperties& properties = QueueFamilyProps[queue.queueFamilyIndex];
for (int32 queueIndex = 0; queueIndex < (int32)properties.queueCount; queueIndex++) for (int32 queueIndex = 0; queueIndex < (int32)properties.queueCount; queueIndex++)
{ {
*currentPriority++ = 1.0f; *currentPriority++ = 1.0f;
} }
} }
deviceInfo.queueCreateInfoCount = queueFamilyInfos.Count(); deviceInfo.queueCreateInfoCount = queueFamilyInfos.Count();
deviceInfo.pQueueCreateInfos = queueFamilyInfos.Get(); deviceInfo.pQueueCreateInfos = queueFamilyInfos.Get();
@@ -2129,7 +2108,6 @@ bool FenceManagerVulkan::CheckFenceState(FenceVulkan* fence)
void FenceManagerVulkan::DestroyFence(FenceVulkan* fence) void FenceManagerVulkan::DestroyFence(FenceVulkan* fence)
{ {
// Does not need to go in the deferred deletion queue
vkDestroyFence(_device->Device, fence->GetHandle(), nullptr); vkDestroyFence(_device->Device, fence->GetHandle(), nullptr);
fence->_handle = VK_NULL_HANDLE; fence->_handle = VK_NULL_HANDLE;
Delete(fence); Delete(fence);

View File

@@ -554,17 +554,17 @@ public:
/// <summary> /// <summary>
/// The main Vulkan commands context. /// The main Vulkan commands context.
/// </summary> /// </summary>
GPUContextVulkan* MainContext; GPUContextVulkan* MainContext = nullptr;
/// <summary> /// <summary>
/// The Vulkan adapter. /// The Vulkan adapter.
/// </summary> /// </summary>
GPUAdapterVulkan* Adapter; GPUAdapterVulkan* Adapter = nullptr;
/// <summary> /// <summary>
/// The Vulkan device. /// The Vulkan device.
/// </summary> /// </summary>
VkDevice Device; VkDevice Device = VK_NULL_HANDLE;
/// <summary> /// <summary>
/// The Vulkan device queues family properties. /// The Vulkan device queues family properties.
@@ -594,51 +594,51 @@ public:
/// <summary> /// <summary>
/// The graphics queue. /// The graphics queue.
/// </summary> /// </summary>
QueueVulkan* GraphicsQueue; QueueVulkan* GraphicsQueue = nullptr;
/// <summary> /// <summary>
/// The compute queue. /// The compute queue.
/// </summary> /// </summary>
QueueVulkan* ComputeQueue; QueueVulkan* ComputeQueue = nullptr;
/// <summary> /// <summary>
/// The transfer queue. /// The transfer queue.
/// </summary> /// </summary>
QueueVulkan* TransferQueue; QueueVulkan* TransferQueue = nullptr;
/// <summary> /// <summary>
/// The present queue. /// The present queue.
/// </summary> /// </summary>
QueueVulkan* PresentQueue; QueueVulkan* PresentQueue = nullptr;
/// <summary> /// <summary>
/// The Vulkan memory allocator. /// The Vulkan memory allocator.
/// </summary> /// </summary>
VmaAllocator Allocator; VmaAllocator Allocator = VK_NULL_HANDLE;
/// <summary> /// <summary>
/// The pipeline cache. /// The pipeline cache.
/// </summary> /// </summary>
VkPipelineCache PipelineCache; VkPipelineCache PipelineCache = VK_NULL_HANDLE;
#if VK_EXT_validation_cache #if VK_EXT_validation_cache
/// <summary> /// <summary>
/// The optional validation cache. /// The optional validation cache.
/// </summary> /// </summary>
VkValidationCacheEXT ValidationCache; VkValidationCacheEXT ValidationCache = VK_NULL_HANDLE;
#endif #endif
/// <summary> /// <summary>
/// The uniform buffers uploader. /// The uniform buffers uploader.
/// </summary> /// </summary>
UniformBufferUploaderVulkan* UniformBufferUploader; UniformBufferUploaderVulkan* UniformBufferUploader = nullptr;
/// <summary> /// <summary>
/// The descriptor pools manager. /// The descriptor pools manager.
/// </summary> /// </summary>
DescriptorPoolsManagerVulkan* DescriptorPoolsManager; DescriptorPoolsManagerVulkan* DescriptorPoolsManager = nullptr;
/// <summary> /// <summary>
/// The physical device limits. /// The physical device limits.

View File

@@ -45,13 +45,10 @@ ComputePipelineStateVulkan* GPUShaderProgramCSVulkan::GetOrCreateState()
// Setup the state // Setup the state
_pipelineState = New<ComputePipelineStateVulkan>(_device, pipeline, layout); _pipelineState = New<ComputePipelineStateVulkan>(_device, pipeline, layout);
_pipelineState->DescriptorInfo = &DescriptorInfo; _pipelineState->DescriptorInfo = &DescriptorInfo;
_pipelineState->DescriptorSetsLayout = &layout->GetDescriptorSetLayout(); _pipelineState->DescriptorSetsLayout = &layout->GetDescriptorSetLayout();
_pipelineState->DescriptorSetHandles.AddZeroed(_pipelineState->DescriptorSetsLayout->GetHandles().Count()); _pipelineState->DescriptorSetHandles.AddZeroed(_pipelineState->DescriptorSetsLayout->GetHandles().Count());
uint32 dynamicOffsetsCount = 0;
uint32 totalNumDynamicOffsets = 0;
if (DescriptorInfo.DescriptorTypesCount != 0) if (DescriptorInfo.DescriptorTypesCount != 0)
{ {
_pipelineState->DSWriteContainer.DescriptorWrites.AddZeroed(DescriptorInfo.DescriptorTypesCount); _pipelineState->DSWriteContainer.DescriptorWrites.AddZeroed(DescriptorInfo.DescriptorTypesCount);
@@ -59,18 +56,18 @@ ComputePipelineStateVulkan* GPUShaderProgramCSVulkan::GetOrCreateState()
_pipelineState->DSWriteContainer.DescriptorBufferInfo.AddZeroed(DescriptorInfo.BufferInfosCount); _pipelineState->DSWriteContainer.DescriptorBufferInfo.AddZeroed(DescriptorInfo.BufferInfosCount);
ASSERT(DescriptorInfo.DescriptorTypesCount < 255); ASSERT(DescriptorInfo.DescriptorTypesCount < 255);
_pipelineState->DSWriteContainer.BindingToDynamicOffsetMap.AddDefault(DescriptorInfo.DescriptorTypesCount); _pipelineState->DSWriteContainer.BindingToDynamicOffset.AddDefault(DescriptorInfo.DescriptorTypesCount);
_pipelineState->DSWriteContainer.BindingToDynamicOffsetMap.SetAll(255); _pipelineState->DSWriteContainer.BindingToDynamicOffset.SetAll(255);
VkWriteDescriptorSet* currentDescriptorWrite = _pipelineState->DSWriteContainer.DescriptorWrites.Get(); VkWriteDescriptorSet* currentDescriptorWrite = _pipelineState->DSWriteContainer.DescriptorWrites.Get();
VkDescriptorImageInfo* currentImageInfo = _pipelineState->DSWriteContainer.DescriptorImageInfo.Get(); VkDescriptorImageInfo* currentImageInfo = _pipelineState->DSWriteContainer.DescriptorImageInfo.Get();
VkDescriptorBufferInfo* currentBufferInfo = _pipelineState->DSWriteContainer.DescriptorBufferInfo.Get(); VkDescriptorBufferInfo* currentBufferInfo = _pipelineState->DSWriteContainer.DescriptorBufferInfo.Get();
uint8* currentBindingToDynamicOffsetMap = _pipelineState->DSWriteContainer.BindingToDynamicOffsetMap.Get(); uint8* currentBindingToDynamicOffsetMap = _pipelineState->DSWriteContainer.BindingToDynamicOffset.Get();
totalNumDynamicOffsets = _pipelineState->DSWriter.SetupDescriptorWrites(DescriptorInfo, currentDescriptorWrite, currentImageInfo, currentBufferInfo, currentBindingToDynamicOffsetMap); dynamicOffsetsCount = _pipelineState->DSWriter.SetupDescriptorWrites(DescriptorInfo, currentDescriptorWrite, currentImageInfo, currentBufferInfo, currentBindingToDynamicOffsetMap);
} }
_pipelineState->DynamicOffsets.AddZeroed(totalNumDynamicOffsets); _pipelineState->DynamicOffsets.AddZeroed(dynamicOffsetsCount);
_pipelineState->DSWriter.DynamicOffsets = _pipelineState->DynamicOffsets.Get(); _pipelineState->DSWriter.DynamicOffsets = _pipelineState->DynamicOffsets.Get();
return _pipelineState; return _pipelineState;
@@ -346,26 +343,26 @@ bool GPUPipelineStateVulkan::Init(const Description& desc)
DSWriteContainer.DescriptorBufferInfo.AddZeroed(descriptor->BufferInfosCount); DSWriteContainer.DescriptorBufferInfo.AddZeroed(descriptor->BufferInfosCount);
ASSERT(descriptor->DescriptorTypesCount < 255); ASSERT(descriptor->DescriptorTypesCount < 255);
DSWriteContainer.BindingToDynamicOffsetMap.AddDefault(descriptor->DescriptorTypesCount); DSWriteContainer.BindingToDynamicOffset.AddDefault(descriptor->DescriptorTypesCount);
DSWriteContainer.BindingToDynamicOffsetMap.SetAll(255); DSWriteContainer.BindingToDynamicOffset.SetAll(255);
} }
VkWriteDescriptorSet* currentDescriptorWrite = DSWriteContainer.DescriptorWrites.Get(); VkWriteDescriptorSet* currentDescriptorWrite = DSWriteContainer.DescriptorWrites.Get();
VkDescriptorImageInfo* currentImageInfo = DSWriteContainer.DescriptorImageInfo.Get(); VkDescriptorImageInfo* currentImageInfo = DSWriteContainer.DescriptorImageInfo.Get();
VkDescriptorBufferInfo* currentBufferInfo = DSWriteContainer.DescriptorBufferInfo.Get(); VkDescriptorBufferInfo* currentBufferInfo = DSWriteContainer.DescriptorBufferInfo.Get();
uint8* currentBindingToDynamicOffsetMap = DSWriteContainer.BindingToDynamicOffsetMap.Get(); byte* currentBindingToDynamicOffsetMap = DSWriteContainer.BindingToDynamicOffset.Get();
uint32 dynamicOffsetsStart[DescriptorSet::GraphicsStagesCount]; uint32 dynamicOffsetsStart[DescriptorSet::GraphicsStagesCount];
uint32 totalNumDynamicOffsets = 0; uint32 dynamicOffsetsCount = 0;
for (int32 stage = 0; stage < DescriptorSet::GraphicsStagesCount; stage++) for (int32 stage = 0; stage < DescriptorSet::GraphicsStagesCount; stage++)
{ {
dynamicOffsetsStart[stage] = totalNumDynamicOffsets; dynamicOffsetsStart[stage] = dynamicOffsetsCount;
const auto descriptor = DescriptorInfoPerStage[stage]; const auto descriptor = DescriptorInfoPerStage[stage];
if (descriptor == nullptr || descriptor->DescriptorTypesCount == 0) if (descriptor == nullptr || descriptor->DescriptorTypesCount == 0)
continue; continue;
const uint32 numDynamicOffsets = DSWriter[stage].SetupDescriptorWrites(*descriptor, currentDescriptorWrite, currentImageInfo, currentBufferInfo, currentBindingToDynamicOffsetMap); const uint32 numDynamicOffsets = DSWriter[stage].SetupDescriptorWrites(*descriptor, currentDescriptorWrite, currentImageInfo, currentBufferInfo, currentBindingToDynamicOffsetMap);
totalNumDynamicOffsets += numDynamicOffsets; dynamicOffsetsCount += numDynamicOffsets;
currentDescriptorWrite += descriptor->DescriptorTypesCount; currentDescriptorWrite += descriptor->DescriptorTypesCount;
currentImageInfo += descriptor->ImageInfosCount; currentImageInfo += descriptor->ImageInfosCount;
@@ -373,7 +370,7 @@ bool GPUPipelineStateVulkan::Init(const Description& desc)
currentBindingToDynamicOffsetMap += descriptor->DescriptorTypesCount; currentBindingToDynamicOffsetMap += descriptor->DescriptorTypesCount;
} }
DynamicOffsets.AddZeroed(totalNumDynamicOffsets); DynamicOffsets.AddZeroed(dynamicOffsetsCount);
for (int32 stage = 0; stage < DescriptorSet::GraphicsStagesCount; stage++) for (int32 stage = 0; stage < DescriptorSet::GraphicsStagesCount; stage++)
{ {
DSWriter[stage].DynamicOffsets = dynamicOffsetsStart[stage] + DynamicOffsets.Get(); DSWriter[stage].DynamicOffsets = dynamicOffsetsStart[stage] + DynamicOffsets.Get();

View File

@@ -187,10 +187,10 @@ bool GPUSwapChainVulkan::CreateSwapChain(int32 width, int32 height)
const auto& gpu = _device->Adapter->Gpu; const auto& gpu = _device->Adapter->Gpu;
// Find pixel format for presentable images // Pick a format for backbuffer
PixelFormat resultFormat = GPU_BACK_BUFFER_PIXEL_FORMAT; PixelFormat resultFormat = GPU_BACK_BUFFER_PIXEL_FORMAT;
VkSurfaceFormatKHR curFormat; VkSurfaceFormatKHR result;
Platform::MemoryClear(&curFormat, sizeof(curFormat)); Platform::MemoryClear(&result, sizeof(result));
{ {
uint32 surfaceFormatsCount; uint32 surfaceFormatsCount;
VALIDATE_VULKAN_RESULT(vkGetPhysicalDeviceSurfaceFormatsKHR(gpu, _surface, &surfaceFormatsCount, nullptr)); VALIDATE_VULKAN_RESULT(vkGetPhysicalDeviceSurfaceFormatsKHR(gpu, _surface, &surfaceFormatsCount, nullptr));
@@ -210,7 +210,7 @@ bool GPUSwapChainVulkan::CreateSwapChain(int32 width, int32 height)
{ {
if (surfaceFormats[i].format == requested) if (surfaceFormats[i].format == requested)
{ {
curFormat = surfaceFormats[i]; result = surfaceFormats[i];
found = true; found = true;
break; break;
} }
@@ -240,8 +240,8 @@ bool GPUSwapChainVulkan::CreateSwapChain(int32 width, int32 height)
if (surfaceFormats[i].format == RenderToolsVulkan::ToVulkanFormat(static_cast<PixelFormat>(pixelFormat))) if (surfaceFormats[i].format == RenderToolsVulkan::ToVulkanFormat(static_cast<PixelFormat>(pixelFormat)))
{ {
resultFormat = static_cast<PixelFormat>(pixelFormat); resultFormat = static_cast<PixelFormat>(pixelFormat);
curFormat = surfaceFormats[i]; result = surfaceFormats[i];
LOG(Info, "No swapchain format requested, picking up Vulkan format {0}", (uint32)curFormat.format); LOG(Info, "No swapchain format requested, picking up Vulkan format {0}", (uint32)result.format);
break; break;
} }
} }
@@ -264,7 +264,7 @@ bool GPUSwapChainVulkan::CreateSwapChain(int32 width, int32 height)
if (surfaceFormats[i].format == format) if (surfaceFormats[i].format == format)
{ {
supported = true; supported = true;
curFormat = surfaceFormats[i]; result = surfaceFormats[i];
break; break;
} }
} }
@@ -290,13 +290,13 @@ bool GPUSwapChainVulkan::CreateSwapChain(int32 width, int32 height)
LOG(Error, "Unable to find a pixel format for the swapchain; swapchain returned {0} Vulkan formats {1}", surfaceFormats.Count(), *msg); LOG(Error, "Unable to find a pixel format for the swapchain; swapchain returned {0} Vulkan formats {1}", surfaceFormats.Count(), *msg);
} }
} }
curFormat.format = RenderToolsVulkan::ToVulkanFormat(resultFormat); result.format = RenderToolsVulkan::ToVulkanFormat(resultFormat);
_format = resultFormat; _format = resultFormat;
// Prepare present queue // Prepare present queue
_device->SetupPresentQueue(_surface); _device->SetupPresentQueue(_surface);
// Fetch present mode // Calculate the swap chain present mode
VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
{ {
uint32 presentModesCount = 0; uint32 presentModesCount = 0;
@@ -358,8 +358,8 @@ bool GPUSwapChainVulkan::CreateSwapChain(int32 width, int32 height)
RenderToolsVulkan::ZeroStruct(swapChainInfo, VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR); RenderToolsVulkan::ZeroStruct(swapChainInfo, VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
swapChainInfo.surface = _surface; swapChainInfo.surface = _surface;
swapChainInfo.minImageCount = VULKAN_BACK_BUFFERS_COUNT; swapChainInfo.minImageCount = VULKAN_BACK_BUFFERS_COUNT;
swapChainInfo.imageFormat = curFormat.format; swapChainInfo.imageFormat = result.format;
swapChainInfo.imageColorSpace = curFormat.colorSpace; swapChainInfo.imageColorSpace = result.colorSpace;
swapChainInfo.imageExtent.width = width; swapChainInfo.imageExtent.width = width;
swapChainInfo.imageExtent.height = height; swapChainInfo.imageExtent.height = height;
swapChainInfo.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; swapChainInfo.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;

View File

@@ -78,7 +78,7 @@ protected:
{ {
if (this->hasBlock) if (this->hasBlock)
{ {
// Copy blocking hit to hits // Blocking hits go to hits
processTouches(&this->block, 1); processTouches(&this->block, 1);
} }
} }

View File

@@ -177,8 +177,7 @@ bool PhysicsService::Init()
// only in non-production builds. // only in non-production builds.
#if PHYSX_MEMORY_STATS #if PHYSX_MEMORY_STATS
// Want names of PhysX allocations _foundation->setReportAllocationNames(true);
GPhysXFoundation->setReportAllocationNames(true);
#endif #endif
// Config // Config

View File

@@ -767,7 +767,7 @@ void AndroidPlatform::GetSystemTime(int32& year, int32& month, int32& dayOfWeek,
void AndroidPlatform::GetUTCTime(int32& year, int32& month, int32& dayOfWeek, int32& day, int32& hour, int32& minute, int32& second, int32& millisecond) void AndroidPlatform::GetUTCTime(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; struct timeval time;
gettimeofday(&time, nullptr); gettimeofday(&time, nullptr);
@@ -803,11 +803,11 @@ bool AndroidPlatform::Init()
} }
// Set info about the CPU // Set info about the CPU
cpu_set_t availableCpusMask; cpu_set_t cpus;
CPU_ZERO(&availableCpusMask); CPU_ZERO(&cpus);
if (sched_getaffinity(0, sizeof(availableCpusMask), &availableCpusMask) == 0) if (sched_getaffinity(0, sizeof(cpus), &cpus) == 0)
{ {
AndroidCpu.ProcessorCoreCount = AndroidCpu.LogicalProcessorCount = CPU_COUNT(&availableCpusMask); AndroidCpu.ProcessorCoreCount = AndroidCpu.LogicalProcessorCount = CPU_COUNT(&cpus);
} }
else else
{ {

View File

@@ -1277,7 +1277,7 @@ void LinuxPlatform::GetSystemTime(int32& year, int32& month, int32& dayOfWeek, i
void LinuxPlatform::GetUTCTime(int32& year, int32& month, int32& dayOfWeek, int32& day, int32& hour, int32& minute, int32& second, int32& millisecond) void LinuxPlatform::GetUTCTime(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; struct timeval time;
gettimeofday(&time, nullptr); gettimeofday(&time, nullptr);
@@ -1315,34 +1315,33 @@ bool LinuxPlatform::Init()
} }
// Set info about the CPU // Set info about the CPU
cpu_set_t availableCpusMask; cpu_set_t cpus;
CPU_ZERO(&availableCpusMask); CPU_ZERO(&cpus);
if (sched_getaffinity(0, sizeof(availableCpusMask), &availableCpusMask) == 0) if (sched_getaffinity(0, sizeof(cpus), &cpus) == 0)
{ {
int32 numberOfCores = 0; int32 numberOfCores = 0;
struct CpuInfo struct CpuInfo
{ {
int Core; int32 Core;
int Package; int32 Package;
} cpuInfos[CPU_SETSIZE]; } cpusInfo[CPU_SETSIZE];
Platform::MemoryClear(cpusInfo, sizeof(cpusInfo));
Platform::MemoryClear(cpuInfos, sizeof(cpuInfos)); int32 maxCoreId = 0;
int maxCoreId = 0; int32 maxPackageId = 0;
int maxPackageId = 0; int32 cpuCountAvailable = 0;
int cpuCountAvailable = 0;
for (int32 cpuIdx = 0; cpuIdx < CPU_SETSIZE; cpuIdx++) for (int32 cpuIdx = 0; cpuIdx < CPU_SETSIZE; cpuIdx++)
{ {
if (CPU_ISSET(cpuIdx, &availableCpusMask)) if (CPU_ISSET(cpuIdx, &cpus))
{ {
cpuCountAvailable++; cpuCountAvailable++;
sprintf(fileNameBuffer, "/sys/devices/system/cpu/cpu%d/topology/core_id", cpuIdx); sprintf(fileNameBuffer, "/sys/devices/system/cpu/cpu%d/topology/core_id", cpuIdx);
if (FILE* coreIdFile = fopen(fileNameBuffer, "r")) if (FILE* coreIdFile = fopen(fileNameBuffer, "r"))
{ {
if (fscanf(coreIdFile, "%d", &cpuInfos[cpuIdx].Core) != 1) if (fscanf(coreIdFile, "%d", &cpusInfo[cpuIdx].Core) != 1)
{ {
cpuInfos[cpuIdx].Core = 0; cpusInfo[cpuIdx].Core = 0;
} }
fclose(coreIdFile); fclose(coreIdFile);
} }
@@ -1350,22 +1349,21 @@ bool LinuxPlatform::Init()
sprintf(fileNameBuffer, "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpuIdx); sprintf(fileNameBuffer, "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpuIdx);
if (FILE* packageIdFile = fopen(fileNameBuffer, "r")) if (FILE* packageIdFile = fopen(fileNameBuffer, "r"))
{ {
// physical_package_id can be -1 on embedded devices - treat all CPUs as separate in that case. if (fscanf(packageIdFile, "%d", &cpusInfo[cpuIdx].Package) != 1 || cpusInfo[cpuIdx].Package < 0)
if (fscanf(packageIdFile, "%d", &cpuInfos[cpuIdx].Package) != 1 || cpuInfos[cpuIdx].Package < 0)
{ {
cpuInfos[cpuIdx].Package = cpuInfos[cpuIdx].Core; cpusInfo[cpuIdx].Package = cpusInfo[cpuIdx].Core;
} }
fclose(packageIdFile); fclose(packageIdFile);
} }
maxCoreId = Math::Max(maxCoreId, cpuInfos[cpuIdx].Core); maxCoreId = Math::Max(maxCoreId, cpusInfo[cpuIdx].Core);
maxPackageId = Math::Max(maxPackageId, cpuInfos[cpuIdx].Package); maxPackageId = Math::Max(maxPackageId, cpusInfo[cpuIdx].Package);
} }
} }
int coresCount = maxCoreId + 1; int32 coresCount = maxCoreId + 1;
int packagesCount = maxPackageId + 1; int32 packagesCount = maxPackageId + 1;
int pairsCount = packagesCount * coresCount; int32 pairsCount = packagesCount * coresCount;
if (coresCount * 2 < cpuCountAvailable) if (coresCount * 2 < cpuCountAvailable)
{ {
@@ -1378,9 +1376,9 @@ bool LinuxPlatform::Init()
for (int32 cpuIdx = 0; cpuIdx < CPU_SETSIZE; cpuIdx++) for (int32 cpuIdx = 0; cpuIdx < CPU_SETSIZE; cpuIdx++)
{ {
if (CPU_ISSET(cpuIdx, &availableCpusMask)) if (CPU_ISSET(cpuIdx, &cpus))
{ {
pairs[cpuInfos[cpuIdx].Package * coresCount + cpuInfos[cpuIdx].Core] = 1; pairs[cpusInfo[cpuIdx].Package * coresCount + cpusInfo[cpuIdx].Core] = 1;
} }
} }
@@ -1394,7 +1392,7 @@ bool LinuxPlatform::Init()
UnixCpu.ProcessorPackageCount = packagesCount; UnixCpu.ProcessorPackageCount = packagesCount;
UnixCpu.ProcessorCoreCount = Math::Max(numberOfCores, 1); UnixCpu.ProcessorCoreCount = Math::Max(numberOfCores, 1);
UnixCpu.LogicalProcessorCount = CPU_COUNT(&availableCpusMask); UnixCpu.LogicalProcessorCount = CPU_COUNT(&cpus);
} }
else else
{ {

View File

@@ -417,13 +417,13 @@ void WindowsWindow::GetScreenInfo(int32& x, int32& y, int32& width, int32& heigh
{ {
ASSERT(HasHWND()); ASSERT(HasHWND());
// Grab current monitor data for sizing // Pick the current monitor data for sizing
const HMONITOR monitor = MonitorFromWindow(_handle, MONITOR_DEFAULTTONEAREST); const HMONITOR monitor = MonitorFromWindow(_handle, MONITOR_DEFAULTTONEAREST);
MONITORINFO monitorInfo; MONITORINFO monitorInfo;
monitorInfo.cbSize = sizeof(MONITORINFO); monitorInfo.cbSize = sizeof(MONITORINFO);
GetMonitorInfoW(monitor, &monitorInfo); GetMonitorInfoW(monitor, &monitorInfo);
// Return result // Calculate result
x = monitorInfo.rcMonitor.left; x = monitorInfo.rcMonitor.left;
y = monitorInfo.rcMonitor.top; y = monitorInfo.rcMonitor.top;
width = monitorInfo.rcMonitor.right - x; width = monitorInfo.rcMonitor.right - x;

View File

@@ -126,12 +126,11 @@ void FontTextureAtlas::CopyDataIntoSlot(const Slot* slot, const Array<byte>& dat
} }
} }
// Copy each row of the texture // Actual data copy
for (uint32 row = padding; row < slot->Height - padding; row++) for (uint32 row = padding; row < slot->Height - padding; row++)
{ {
rowData.SrcRow = row - padding; rowData.SrcRow = row - padding;
rowData.DstRow = row; rowData.DstRow = row;
copyRow(rowData); copyRow(rowData);
} }

View File

@@ -1292,7 +1292,7 @@ void Render2D::DrawRectangle(const Rectangle& rect, const Color& color1, const C
drawCall.StartIB = IBIndex; drawCall.StartIB = IBIndex;
drawCall.CountIB = 4 * (6 + 3); drawCall.CountIB = 4 * (6 + 3);
// The has to match HLSL code // This must be the same as in HLSL code
const float filterScale = 1.0f; const float filterScale = 1.0f;
const float thicknessHalf = (2.82842712f + thickness) * 0.5f + filterScale; const float thicknessHalf = (2.82842712f + thickness) * 0.5f + filterScale;
@@ -1544,10 +1544,8 @@ void DrawLines(const Vector2* points, int32 pointsCount, const Color& color1, co
Vector2 p1t, p2t; Vector2 p1t, p2t;
#if RENDER2D_USE_LINE_AA #if RENDER2D_USE_LINE_AA
// Half of the width of the filter size to use for anti-aliasing. Increasing this value will increase the fuzziness of line edges. // This must be the same as in HLSL code
const float filterScale = 1.0f; // Must match HLSL code const float filterScale = 1.0f;
// The amount we increase each side of the line to generate enough pixels
const float thicknessHalf = (2.82842712f + thickness) * 0.5f + filterScale; const float thicknessHalf = (2.82842712f + thickness) * 0.5f + filterScale;
drawCall.Type = DrawCallType::LineAA; drawCall.Type = DrawCallType::LineAA;

View File

@@ -12,6 +12,10 @@
#if GENERATE_GF_CACHE #if GENERATE_GF_CACHE
// This code below (PreIntegratedGF namespace) is based on many Siggraph presentations about BRDF shading:
// https://blog.selfshadow.com/publications/s2015-shading-course/
// https://blog.selfshadow.com/publications/s2012-shading-course/
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>

View File

@@ -152,7 +152,7 @@ bool VolumetricFogPass::Init(RenderContext& renderContext, GPUContext* context,
_cache.GridSizeZ = 64; _cache.GridSizeZ = 64;
_cache.FogJitter = false; _cache.FogJitter = false;
_cache.TemporalReprojection = false; _cache.TemporalReprojection = false;
_cache.HistoryMissSupersampleCount = 1; _cache.MissedHistorySamplesCount = 1;
break; break;
} }
case Quality::Medium: case Quality::Medium:
@@ -161,7 +161,7 @@ bool VolumetricFogPass::Init(RenderContext& renderContext, GPUContext* context,
_cache.GridSizeZ = 64; _cache.GridSizeZ = 64;
_cache.FogJitter = true; _cache.FogJitter = true;
_cache.TemporalReprojection = true; _cache.TemporalReprojection = true;
_cache.HistoryMissSupersampleCount = 4; _cache.MissedHistorySamplesCount = 4;
break; break;
} }
case Quality::High: case Quality::High:
@@ -170,7 +170,7 @@ bool VolumetricFogPass::Init(RenderContext& renderContext, GPUContext* context,
_cache.GridSizeZ = 128; _cache.GridSizeZ = 128;
_cache.FogJitter = true; _cache.FogJitter = true;
_cache.TemporalReprojection = true; _cache.TemporalReprojection = true;
_cache.HistoryMissSupersampleCount = 4; _cache.MissedHistorySamplesCount = 4;
break; break;
} }
case Quality::Ultra: case Quality::Ultra:
@@ -179,7 +179,7 @@ bool VolumetricFogPass::Init(RenderContext& renderContext, GPUContext* context,
_cache.GridSizeZ = 256; _cache.GridSizeZ = 256;
_cache.FogJitter = true; _cache.FogJitter = true;
_cache.TemporalReprojection = true; _cache.TemporalReprojection = true;
_cache.HistoryMissSupersampleCount = 8; _cache.MissedHistorySamplesCount = 8;
break; break;
} }
} }
@@ -208,7 +208,7 @@ bool VolumetricFogPass::Init(RenderContext& renderContext, GPUContext* context,
_cache.Data.InverseSquaredLightDistanceBiasScale = _cache.InverseSquaredLightDistanceBiasScale; _cache.Data.InverseSquaredLightDistanceBiasScale = _cache.InverseSquaredLightDistanceBiasScale;
_cache.Data.PhaseG = options.ScatteringDistribution; _cache.Data.PhaseG = options.ScatteringDistribution;
_cache.Data.VolumetricFogMaxDistance = options.Distance; _cache.Data.VolumetricFogMaxDistance = options.Distance;
_cache.Data.HistoryMissSuperSampleCount = Math::Clamp(_cache.HistoryMissSupersampleCount, 1, (int32)ARRAY_COUNT(_cache.Data.FrameJitterOffsets)); _cache.Data.MissedHistorySamplesCount = Math::Clamp(_cache.MissedHistorySamplesCount, 1, (int32)ARRAY_COUNT(_cache.Data.FrameJitterOffsets));
Matrix::Transpose(view.PrevViewProjection, _cache.Data.PrevWorldToClip); Matrix::Transpose(view.PrevViewProjection, _cache.Data.PrevWorldToClip);
_cache.Data.DirectionalLightShadow.NumCascades = 0; _cache.Data.DirectionalLightShadow.NumCascades = 0;
_cache.Data.SkyLight.VolumetricScatteringIntensity = 0; _cache.Data.SkyLight.VolumetricScatteringIntensity = 0;
@@ -221,7 +221,7 @@ bool VolumetricFogPass::Init(RenderContext& renderContext, GPUContext* context,
} }
if (_cache.FogJitter && _cache.TemporalReprojection) if (_cache.FogJitter && _cache.TemporalReprojection)
{ {
for (int32 i = 0; i < _cache.HistoryMissSupersampleCount; i++) for (int32 i = 0; i < _cache.MissedHistorySamplesCount; i++)
{ {
const uint64 frameNumber = renderContext.Task->LastUsedFrame - i; const uint64 frameNumber = renderContext.Task->LastUsedFrame - i;
_cache.Data.FrameJitterOffsets[i] = Vector4( _cache.Data.FrameJitterOffsets[i] = Vector4(

View File

@@ -30,7 +30,7 @@ private:
float HistoryWeight; float HistoryWeight;
Vector3 GridSize; Vector3 GridSize;
uint32 HistoryMissSuperSampleCount; uint32 MissedHistorySamplesCount;
int32 GridSizeIntX; int32 GridSizeIntX;
int32 GridSizeIntY; int32 GridSizeIntY;
@@ -105,9 +105,9 @@ private:
float HistoryWeight; float HistoryWeight;
/// <summary> /// <summary>
/// Number of lighting samples to compute for voxels whose history value is not available. This reduces noise when panning or on camera cuts, but introduces a variable cost to volumetric fog computation. Valid range [1, 8]. /// The amount of lighting samples to compute for voxels whose history value is not available. This reduces noise when panning or on camera cuts, but introduces a variable cost to volumetric fog computation. Valid range [1, 8].
/// </summary> /// </summary>
int32 HistoryMissSupersampleCount; int32 MissedHistorySamplesCount;
/// <summary> /// <summary>
/// Scales the amount added to the inverse squared falloff denominator. This effectively removes the spike from inverse squared falloff that causes extreme aliasing. /// Scales the amount added to the inverse squared falloff denominator. This effectively removes the spike from inverse squared falloff that causes extreme aliasing.

View File

@@ -4,7 +4,9 @@
#include "Engine/Core/Math/Math.h" #include "Engine/Core/Math/Math.h"
#include "Engine/Platform/Platform.h" #include "Engine/Platform/Platform.h"
// Use CRC 32 polynomial // Based on the Slicing-by-8 implementation found here:
// http://slicing-by-8.sourceforge.net/
enum { Crc32Poly = 0x04c11db7 }; enum { Crc32Poly = 0x04c11db7 };
uint32 Crc::CachedCRCTablesSB8[8][256] = uint32 Crc::CachedCRCTablesSB8[8][256] =

View File

@@ -71,9 +71,9 @@ namespace FlaxEngine.Utilities
return Base + noise * NoiseAmount; return Base + noise * NoiseAmount;
} }
private float Fade(float T) private float Fade(float t)
{ {
return T * T * T * (T * (T * 6 - 15) + 10); return t * t * t * (t * (t * 6 - 15) + 10);
} }
private float Grad(int hash, float x, float y) private float Grad(int hash, float x, float y)

View File

@@ -109,8 +109,14 @@ float3 ColorCorrect(float3 color, float luma, float4 saturation, float4 contrast
return color; return color;
} }
float3 ColorCorrectAll(float3 color) float3 ColorGrade(float3 linearColor)
{ {
// Convert into ACEScg color
const float3x3 sRGB_2_AP1 = mul(XYZ_2_AP1_MAT, mul(D65_2_D60_CAT, sRGB_2_XYZ_MAT));
const float3x3 AP1_2_sRGB = mul(XYZ_2_sRGB_MAT, mul(D60_2_D65_CAT, AP1_2_XYZ_MAT));
float3 color = mul(sRGB_2_AP1, linearColor);
// Perform color grading with CC wheels
float luma = dot(color, AP1_RGB2Y); float luma = dot(color, AP1_RGB2Y);
float3 ccColorShadows = ColorCorrect(color, luma, ColorSaturationShadows, ColorContrastShadows, ColorGammaShadows, ColorGainShadows, ColorOffsetShadows); float3 ccColorShadows = ColorCorrect(color, luma, ColorSaturationShadows, ColorContrastShadows, ColorGammaShadows, ColorGainShadows, ColorOffsetShadows);
float ccWeightShadows = 1 - smoothstep(0, ColorCorrectionShadowsMax, luma); float ccWeightShadows = 1 - smoothstep(0, ColorCorrectionShadowsMax, luma);
@@ -118,18 +124,7 @@ float3 ColorCorrectAll(float3 color)
float ccWeightHighlights = smoothstep(ColorCorrectionHighlightsMin, 1, luma); float ccWeightHighlights = smoothstep(ColorCorrectionHighlightsMin, 1, luma);
float3 ccColorMidtones = ColorCorrect(color, luma, ColorSaturationMidtones, ColorContrastMidtones, ColorGammaMidtones, ColorGainMidtones, ColorOffsetMidtones); float3 ccColorMidtones = ColorCorrect(color, luma, ColorSaturationMidtones, ColorContrastMidtones, ColorGammaMidtones, ColorGainMidtones, ColorOffsetMidtones);
float ccWeightMidtones = 1 - ccWeightShadows - ccWeightHighlights; float ccWeightMidtones = 1 - ccWeightShadows - ccWeightHighlights;
return ccColorShadows * ccWeightShadows + ccColorMidtones * ccWeightMidtones + ccColorHighlights * ccWeightHighlights; color = ccColorShadows * ccWeightShadows + ccColorMidtones * ccWeightMidtones + ccColorHighlights * ccWeightHighlights;
}
float3 ColorGrade(float3 linearColor)
{
// ACEScg working space
const float3x3 sRGB_2_AP1 = mul(XYZ_2_AP1_MAT, mul(D65_2_D60_CAT, sRGB_2_XYZ_MAT));
const float3x3 AP1_2_sRGB = mul(XYZ_2_sRGB_MAT, mul(D60_2_D65_CAT, AP1_2_XYZ_MAT));
float3 color = mul(sRGB_2_AP1, linearColor);
// Nuke-style color correct
color = ColorCorrectAll(color);
// Convert back to linear color // Convert back to linear color
return mul(AP1_2_sRGB, color); return mul(AP1_2_sRGB, color);
@@ -216,23 +211,20 @@ float4 CombineLUTs(float2 uv, uint layerIndex)
{ {
float3 encodedColor; float3 encodedColor;
#if USE_VOLUME_LUT #if USE_VOLUME_LUT
// Construct the neutral color from a 3d position volume texture // Calculate the neutral color from 3d position
{ {
uv = uv - float2(0.5f / LUTSize, 0.5f / LUTSize); uv = uv - float2(0.5f / LUTSize, 0.5f / LUTSize);
encodedColor = float3(uv * LUTSize / (LUTSize - 1), layerIndex / (LUTSize - 1)); encodedColor = float3(uv * LUTSize / (LUTSize - 1), layerIndex / (LUTSize - 1));
} }
#else #else
// Construct the neutral color from a 2d position in 256x16 // Calculate the neutral color from 2d position
{ {
uv -= float2(0.49999f / (LUTSize * LUTSize), 0.49999f / LUTSize); uv -= float2(0.49999f / (LUTSize * LUTSize), 0.49999f / LUTSize);
float3 rgb; float3 rgb;
rgb.r = frac(uv.x * LUTSize); rgb.r = frac(uv.x * LUTSize);
rgb.b = uv.x - rgb.r / LUTSize; rgb.b = uv.x - rgb.r / LUTSize;
rgb.g = uv.y; rgb.g = uv.y;
encodedColor = rgb * (LUTSize / (LUTSize - 1));
float scale = LUTSize / (LUTSize - 1);
encodedColor = rgb * scale;
} }
#endif #endif

View File

@@ -48,25 +48,20 @@ float4 GetExponentialHeightFog(ExponentialHeightFogData exponentialHeightFog, fl
float excludeIntersectionTime = skipDistance * cameraToPosLenInv; float excludeIntersectionTime = skipDistance * cameraToPosLenInv;
float cameraToExclusionIntersectionY = excludeIntersectionTime * cameraToPos.y; float cameraToExclusionIntersectionY = excludeIntersectionTime * cameraToPos.y;
float exclusionIntersectionY = camWS.y + cameraToExclusionIntersectionY; float exclusionIntersectionY = camWS.y + cameraToExclusionIntersectionY;
float exclusionIntersectionToReceiverY = cameraToPos.y - cameraToExclusionIntersectionY;
// Calculate fog off of the ray starting from the exclusion distance, instead of starting from the camera
rayLength = (1.0f - excludeIntersectionTime) * cameraToPosLen; rayLength = (1.0f - excludeIntersectionTime) * cameraToPosLen;
rayDirectionY = exclusionIntersectionToReceiverY; rayDirectionY = cameraToPos.y - cameraToExclusionIntersectionY;
// Move off the viewer
float exponent = exponentialHeightFog.FogHeightFalloff * (exclusionIntersectionY - exponentialHeightFog.FogHeight); float exponent = exponentialHeightFog.FogHeightFalloff * (exclusionIntersectionY - exponentialHeightFog.FogHeight);
rayOriginTerms = exponentialHeightFog.FogDensity * exp2(-exponent); rayOriginTerms = exponentialHeightFog.FogDensity * exp2(-exponent);
} }
// Calculate the line integral of the ray from the camera to the receiver position through the fog density function // Calculate the integral of the ray starting from the view to the object position with the fog density function
float falloff = max(-127.0f, exponentialHeightFog.FogHeightFalloff * rayDirectionY); float falloff = max(-127.0f, exponentialHeightFog.FogHeightFalloff * rayDirectionY);
float lineIntegral = (1.0f - exp2(-falloff)) / falloff; float lineIntegral = (1.0f - exp2(-falloff)) / falloff;
float lineIntegralTaylor = log(2.0) - (0.5 * Pow2(log(2.0))) * falloff; float lineIntegralTaylor = log(2.0f) - (0.5f * Pow2(log(2.0f))) * falloff;
float exponentialHeightLineIntegralCalc = rayOriginTerms * (abs(falloff) > 0.01f ? lineIntegral : lineIntegralTaylor); float exponentialHeightLineIntegralCalc = rayOriginTerms * (abs(falloff) > 0.01f ? lineIntegral : lineIntegralTaylor);
float exponentialHeightLineIntegral = exponentialHeightLineIntegralCalc * rayLength; float exponentialHeightLineIntegral = exponentialHeightLineIntegralCalc * rayLength;
// Calculate the amount of light that made it through the fog using the transmission equation // Calculate the light that went through the fog
float expFogFactor = max(saturate(exp2(-exponentialHeightLineIntegral)), exponentialHeightFog.FogMinOpacity); float expFogFactor = max(saturate(exp2(-exponentialHeightLineIntegral)), exponentialHeightFog.FogMinOpacity);
// Calculate the directional light inscattering // Calculate the directional light inscattering
@@ -75,17 +70,10 @@ float4 GetExponentialHeightFog(ExponentialHeightFogData exponentialHeightFog, fl
BRANCH BRANCH
if (exponentialHeightFog.ApplyDirectionalInscattering > 0) if (exponentialHeightFog.ApplyDirectionalInscattering > 0)
{ {
// Setup a cosine lobe around the light direction to approximate inscattering from the directional light off of the ambient haze
float3 directionalLightInscattering = exponentialHeightFog.DirectionalInscatteringColor * pow(saturate(dot(cameraToReceiverNorm, exponentialHeightFog.InscatteringLightDirection)), exponentialHeightFog.DirectionalInscatteringExponent); float3 directionalLightInscattering = exponentialHeightFog.DirectionalInscatteringColor * pow(saturate(dot(cameraToReceiverNorm, exponentialHeightFog.InscatteringLightDirection)), exponentialHeightFog.DirectionalInscatteringExponent);
// Calculate the line integral of the eye ray through the haze, using a special starting distance to limit the inscattering to the distance
float dirExponentialHeightLineIntegral = exponentialHeightLineIntegralCalc * max(rayLength - exponentialHeightFog.DirectionalInscatteringStartDistance, 0.0f); float dirExponentialHeightLineIntegral = exponentialHeightLineIntegralCalc * max(rayLength - exponentialHeightFog.DirectionalInscatteringStartDistance, 0.0f);
// Calculate the amount of light that made it through the fog using the transmission equation
float directionalInscatteringFogFactor = saturate(exp2(-dirExponentialHeightLineIntegral)); float directionalInscatteringFogFactor = saturate(exp2(-dirExponentialHeightLineIntegral));
directionalInscattering = directionalLightInscattering * (1.0f - directionalInscatteringFogFactor);
// Final inscattering from the light
directionalInscattering = directionalLightInscattering * (1 - directionalInscatteringFogFactor);
} }
// Disable fog after a certain distance // Disable fog after a certain distance

View File

@@ -9,24 +9,16 @@ Texture2D Distortion : register(t1);
META_PS(true, FEATURE_LEVEL_ES2) META_PS(true, FEATURE_LEVEL_ES2)
float4 PS_ApplyDistortion(Quad_VS2PS input) : SV_Target float4 PS_ApplyDistortion(Quad_VS2PS input) : SV_Target
{ {
// Sample accumulated distortion offset float4 accumDist = Distortion.Sample(SamplerPointClamp, input.TexCoord);
half4 accumDist = Distortion.Sample(SamplerPointClamp, input.TexCoord); float2 distOffset = (accumDist.rg - accumDist.ba) / 4.0f;
// Offset = [R-B,G-A]
half2 distOffset = (accumDist.rg - accumDist.ba);
static const half InvDistortionScaleBias = 1 / 4.0f;
distOffset *= InvDistortionScaleBias;
float2 newTexCoord = input.TexCoord + distOffset; float2 newTexCoord = input.TexCoord + distOffset;
// If we're about to sample outside the valid area, set to 0 distortion // Clamp around screen
FLATTEN FLATTEN
if (newTexCoord.x < 0 || newTexCoord.x > 1 || newTexCoord.y < 0 || newTexCoord.y > 1) if (newTexCoord.x < 0 || newTexCoord.x > 1 || newTexCoord.y < 0 || newTexCoord.y > 1)
{ {
newTexCoord = input.TexCoord; newTexCoord = input.TexCoord;
} }
// Sample screen using offset coords
return Input.SampleLevel(SamplerPointClamp, newTexCoord, 0); return Input.SampleLevel(SamplerPointClamp, newTexCoord, 0);
} }

View File

@@ -60,34 +60,18 @@ half3 sRGBToLinear(half3 color)
float3 LogToLinear(float3 logColor) float3 LogToLinear(float3 logColor)
{ {
const float linearRange = 14; const float linearRange = 14.0f;
const float linearGrey = 0.18; const float linearGrey = 0.18f;
const float exposureGrey = 444; const float exposureGrey = 444.0f;
return exp2((logColor - exposureGrey / 1023.0) * linearRange) * linearGrey;
// Using stripped down, 'pure log', formula. Parameterized by grey points and dynamic range covered.
float3 linearColor = exp2((logColor - exposureGrey / 1023.0) * linearRange) * linearGrey;
//float3 linearColor = 2 * (pow(10.0, ((logColor - 0.616596 - 0.03) / 0.432699)) - 0.037584); // SLog
//float3 linearColor = (pow( 10, (1023 * logColor - 685) / 300) - 0.0108) / (1 - 0.0108); // Cineon
//linearColor = max(0, linearColor);
return linearColor;
} }
float3 LinearToLog(float3 linearColor) float3 LinearToLog(float3 linearColor)
{ {
const float linearRange = 14; const float linearRange = 14.0f;
const float linearGrey = 0.18; const float linearGrey = 0.18f;
const float exposureGrey = 444; const float exposureGrey = 444.0f;
return saturate(log2(linearColor) / linearRange - log2(linearGrey) / linearRange + exposureGrey / 1023.0f);
// Using stripped down, 'pure log', formula. Parameterized by grey points and dynamic range covered.
float3 logColor = log2(linearColor) / linearRange - log2(linearGrey) / linearRange + exposureGrey / 1023.0; // scalar: 3log2 3mad
//float3 logColor = (log2(linearColor) - log2(linearGrey)) / linearRange + exposureGrey / 1023.0;
//float3 logColor = log2(linearColor / linearGrey) / linearRange + exposureGrey / 1023.0;
//float3 logColor = (0.432699 * log10(0.5 * linearColor + 0.037584) + 0.616596) + 0.03; // SLog
//float3 logColor = (300 * log10(linearColor * (1 - 0.0108) + 0.0108) + 685) / 1023; // Cineon
logColor = saturate(logColor);
return logColor;
} }
#endif #endif

View File

@@ -82,19 +82,16 @@ void GetRadialLightAttenuation(
BRANCH BRANCH
if (lightData.SourceLength > 0) if (lightData.SourceLength > 0)
{ {
// Line segment irradiance float3 l01 = lightData.Direction * lightData.SourceLength;
float3 L01 = lightData.Direction * lightData.SourceLength; float3 l0 = toLight - 0.5 * l01;
float3 L0 = toLight - 0.5 * L01; float3 l1 = toLight + 0.5 * l01;
float3 L1 = toLight + 0.5 * L01; float lengthL0 = length(l0);
float LengthL0 = length(L0); float lengthL1 = length(l1);
float LengthL1 = length(L1); distanceAttenuation = rcp((lengthL0 * lengthL1 + dot(l0, l1)) * 0.5 + distanceBiasSqr);
NoL = saturate(0.5 * (dot(N, l0) / lengthL0 + dot(N, l1) / lengthL1));
distanceAttenuation = rcp((LengthL0 * LengthL1 + dot(L0, L1)) * 0.5 + distanceBiasSqr);
NoL = saturate(0.5 * (dot(N, L0) / LengthL0 + dot(N, L1) / LengthL1));
} }
else else
{ {
// Sphere irradiance (technically just 1/d^2 but this avoids inf)
distanceAttenuation = rcp(distanceSqr + distanceBiasSqr); distanceAttenuation = rcp(distanceSqr + distanceBiasSqr);
NoL = saturate(dot(N, L)); NoL = saturate(dot(N, L));
} }

View File

@@ -98,8 +98,6 @@ Texture2D Input3 : register(t3);
Texture2D LensDirt : register(t4); Texture2D LensDirt : register(t4);
Texture2D LensStar : register(t5); Texture2D LensStar : register(t5);
Texture2D LensColor : register(t6); Texture2D LensColor : register(t6);
// LUT for color grading
#if USE_VOLUME_LUT #if USE_VOLUME_LUT
Texture3D ColorGradingLUT : register(t7); Texture3D ColorGradingLUT : register(t7);
#else #else

View File

@@ -119,7 +119,7 @@ float SampleShadowMapFixedSizePCF(Texture2DArray shadowMap, float2 shadowMapSize
if (value != 0.0f) if (value != 0.0f)
{ {
// Using Gather: xyzw in counter clockwise order starting with the sample to the lower left of the queried location // Gather returns xyzw which is counter clockwise order starting with the sample to the lower left of the queried location
#if CAN_USE_GATHER #if CAN_USE_GATHER
v1[(col + FS_2) / 2] = shadowMap.GatherCmp(ShadowSampler, baseUV, sceneDepth, int2(col, row)); v1[(col + FS_2) / 2] = shadowMap.GatherCmp(ShadowSampler, baseUV, sceneDepth, int2(col, row));

View File

@@ -37,7 +37,7 @@ float3 GlobalEmissive;
float HistoryWeight; float HistoryWeight;
float3 GridSize; float3 GridSize;
uint HistoryMissSuperSampleCount; uint MissedHistorySamplesCount;
int3 GridSizeInt; int3 GridSizeInt;
float PhaseG; float PhaseG;
@@ -205,7 +205,7 @@ float4 PS_InjectLight(Quad_GS2PS input) : SV_Target0
{ {
historyAlpha = 0; historyAlpha = 0;
} }
uint samplesCount = historyAlpha < 0.001f ? HistoryMissSuperSampleCount : 1; uint samplesCount = historyAlpha < 0.001f ? MissedHistorySamplesCount : 1;
#else #else
uint samplesCount = 1; uint samplesCount = 1;
#endif #endif
@@ -261,7 +261,6 @@ void CS_Initialize(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_Dispa
{ {
uint3 gridCoordinate = DispatchThreadId; uint3 gridCoordinate = DispatchThreadId;
// Center of the voxel
float voxelOffset = 0.5f; float voxelOffset = 0.5f;
float3 positionWS = GetCellPositionWS(gridCoordinate, voxelOffset); float3 positionWS = GetCellPositionWS(gridCoordinate, voxelOffset);
@@ -272,11 +271,10 @@ void CS_Initialize(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_Dispa
// Calculate the global fog density that matches the exponential height fog density // Calculate the global fog density that matches the exponential height fog density
float globalDensity = fogDensity * exp2(-fogHeightFalloff * (positionWS.y - fogHeight)); float globalDensity = fogDensity * exp2(-fogHeightFalloff * (positionWS.y - fogHeight));
float matchFactor = 0.24f; float extinction = max(0.0f, globalDensity * GlobalExtinctionScale * 0.24f);
float extinction = max(globalDensity * GlobalExtinctionScale * matchFactor, 0);
float3 scattering = GlobalAlbedo * extinction; float3 scattering = GlobalAlbedo * extinction;
float absorption = max(extinction - Luminance(scattering), 0.0f); float absorption = max(0.0f, extinction - Luminance(scattering));
if (all((int3)gridCoordinate < GridSizeInt)) if (all((int3)gridCoordinate < GridSizeInt))
{ {
@@ -306,7 +304,7 @@ void CS_LightScattering(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_
{ {
uint3 gridCoordinate = DispatchThreadId; uint3 gridCoordinate = DispatchThreadId;
float3 lightScattering = 0; float3 lightScattering = 0;
uint numSuperSamples = 1; uint samplesCount = 1;
#if USE_TEMPORAL_REPROJECTION #if USE_TEMPORAL_REPROJECTION
float3 historyUV = GetVolumeUV(GetCellPositionWS(gridCoordinate, 0.5f), PrevWorldToClip); float3 historyUV = GetVolumeUV(GetCellPositionWS(gridCoordinate, 0.5f), PrevWorldToClip);
@@ -319,12 +317,10 @@ void CS_LightScattering(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_
historyAlpha = 0; historyAlpha = 0;
} }
// Supersample if the history was outside the camera frustum samplesCount = historyAlpha < 0.001f && all(gridCoordinate < GridSizeInt) ? MissedHistorySamplesCount : 1;
// The compute shader is dispatched with extra threads, make sure those don't supersample
numSuperSamples = historyAlpha < 0.001f && all(gridCoordinate < GridSizeInt) ? HistoryMissSuperSampleCount : 1;
#endif #endif
for (uint sampleIndex = 0; sampleIndex < numSuperSamples; sampleIndex++) for (uint sampleIndex = 0; sampleIndex < samplesCount; sampleIndex++)
{ {
float3 cellOffset = FrameJitterOffsets[sampleIndex].xyz; float3 cellOffset = FrameJitterOffsets[sampleIndex].xyz;
//float3 cellOffset = 0.5f; //float3 cellOffset = 0.5f;
@@ -357,8 +353,7 @@ void CS_LightScattering(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_
lightScattering += skyLighting * SkyLight.VolumetricScatteringIntensity; lightScattering += skyLighting * SkyLight.VolumetricScatteringIntensity;
} }
} }
lightScattering /= (float)samplesCount;
lightScattering /= (float)numSuperSamples;
// Apply scattering from the point and spot lights // Apply scattering from the point and spot lights
lightScattering += LocalShadowedLightScattering[gridCoordinate].rgb; lightScattering += LocalShadowedLightScattering[gridCoordinate].rgb;

View File

@@ -71,7 +71,7 @@ namespace Flax.Deploy
} }
} }
if (TryReadInstallPath("Microsoft\\VisualStudio\\SxS\\VS7", "15.0", "MSBuild\\15.0\\bin\\MSBuild.exe", out toolPath)) if (CheckMsBuildPathFromRegistry("Microsoft\\VisualStudio\\SxS\\VS7", "15.0", "MSBuild\\15.0\\bin\\MSBuild.exe", out toolPath))
{ {
return toolPath; return toolPath;
} }
@@ -82,17 +82,17 @@ namespace Flax.Deploy
return toolPath; return toolPath;
} }
if (TryReadInstallPath("Microsoft\\MSBuild\\ToolsVersions\\14.0", "MSBuildToolsPath", "MSBuild.exe", out toolPath)) if (CheckMsBuildPathFromRegistry("Microsoft\\MSBuild\\ToolsVersions\\14.0", "MSBuildToolsPath", "MSBuild.exe", out toolPath))
{ {
return toolPath; return toolPath;
} }
if (TryReadInstallPath("Microsoft\\MSBuild\\ToolsVersions\\12.0", "MSBuildToolsPath", "MSBuild.exe", out toolPath)) if (CheckMsBuildPathFromRegistry("Microsoft\\MSBuild\\ToolsVersions\\12.0", "MSBuildToolsPath", "MSBuild.exe", out toolPath))
{ {
return toolPath; return toolPath;
} }
if (TryReadInstallPath("Microsoft\\MSBuild\\ToolsVersions\\4.0", "MSBuildToolsPath", "MSBuild.exe", out toolPath)) if (CheckMsBuildPathFromRegistry("Microsoft\\MSBuild\\ToolsVersions\\4.0", "MSBuildToolsPath", "MSBuild.exe", out toolPath))
{ {
return toolPath; return toolPath;
} }
@@ -121,7 +121,7 @@ namespace Flax.Deploy
} }
case TargetPlatform.Windows: case TargetPlatform.Windows:
{ {
if (TryReadInstallPath("Microsoft\\VisualStudio\\SxS\\VS7", "15.0", "MSBuild\\15.0\\bin\\csc.exe", out toolPath)) if (CheckMsBuildPathFromRegistry("Microsoft\\VisualStudio\\SxS\\VS7", "15.0", "MSBuild\\15.0\\bin\\csc.exe", out toolPath))
{ {
return toolPath; return toolPath;
} }
@@ -132,17 +132,17 @@ namespace Flax.Deploy
return toolPath; return toolPath;
} }
if (TryReadInstallPath("Microsoft\\MSBuild\\ToolsVersions\\14.0", "MSBuildToolsPath", "csc.exe", out toolPath)) if (CheckMsBuildPathFromRegistry("Microsoft\\MSBuild\\ToolsVersions\\14.0", "MSBuildToolsPath", "csc.exe", out toolPath))
{ {
return toolPath; return toolPath;
} }
if (TryReadInstallPath("Microsoft\\MSBuild\\ToolsVersions\\12.0", "MSBuildToolsPath", "csc.exe", out toolPath)) if (CheckMsBuildPathFromRegistry("Microsoft\\MSBuild\\ToolsVersions\\12.0", "MSBuildToolsPath", "csc.exe", out toolPath))
{ {
return toolPath; return toolPath;
} }
if (TryReadInstallPath("Microsoft\\MSBuild\\ToolsVersions\\4.0", "MSBuildToolsPath", "csc.exe", out toolPath)) if (CheckMsBuildPathFromRegistry("Microsoft\\MSBuild\\ToolsVersions\\4.0", "MSBuildToolsPath", "csc.exe", out toolPath))
{ {
return toolPath; return toolPath;
} }
@@ -154,13 +154,9 @@ namespace Flax.Deploy
return string.Empty; return string.Empty;
} }
/// <summary> private static bool CheckMsBuildPathFromRegistry(string keyRelativePath, string keyName, string msBuildRelativePath, out string outMsBuildPath)
/// Queries the registry entries for a certain install directory of the MsBuild.
/// </summary>
/// <returns>True if found MsBuild tool, otherwise false.</returns>
private static bool TryReadInstallPath(string keyRelativePath, string keyName, string msBuildRelativePath, out string outMsBuildPath)
{ {
string[] keyBasePaths = string[] prefixes =
{ {
@"HKEY_CURRENT_USER\SOFTWARE\", @"HKEY_CURRENT_USER\SOFTWARE\",
@"HKEY_LOCAL_MACHINE\SOFTWARE\", @"HKEY_LOCAL_MACHINE\SOFTWARE\",
@@ -168,9 +164,9 @@ namespace Flax.Deploy
@"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\" @"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\"
}; };
foreach (string keyBasePath in keyBasePaths) for (var i = 0; i < prefixes.Length; i++)
{ {
if (Registry.GetValue(keyBasePath + keyRelativePath, keyName, null) is string value) if (Registry.GetValue(prefixes[i] + keyRelativePath, keyName, null) is string value)
{ {
string msBuildPath = Path.Combine(value, msBuildRelativePath); string msBuildPath = Path.Combine(value, msBuildRelativePath);
if (File.Exists(msBuildPath)) if (File.Exists(msBuildPath))