diff --git a/.vscode/launch.json b/.vscode/launch.json index 60de4f3..dc76048 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -55,6 +55,7 @@ "environment": [], "symbolSearchPath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.25.28610\\lib\\x64", "requireExactSource": false, + "visualizerFile": "${workspaceRoot}/Seele.natvis", "logging": { "moduleLoad": false, "exceptions": true, @@ -82,6 +83,7 @@ "stopAtEntry": false, "console": "internalConsole", "cwd": "${workspaceRoot}/bin/Debug", + "visualizerFile": "${workspaceRoot}/Seele.natvis", "environment": [], }, ] diff --git a/Seele.natvis b/Seele.natvis index dbac7bc..7b956ce 100644 --- a/Seele.natvis +++ b/Seele.natvis @@ -31,7 +31,7 @@ - {{size={_size}} + {{ size={_size} } _size comp diff --git a/external/slang b/external/slang index 858c7c5..c479030 160000 --- a/external/slang +++ b/external/slang @@ -1 +1 @@ -Subproject commit 858c7c57b125afed9b5b2329d6b02477284e4803 +Subproject commit c4790309ec46ae2f4f7c49eb50699a950ee7a9a4 diff --git a/res/shaders/ComputeFrustums.slang b/res/shaders/ComputeFrustums.slang index fbed51c..108210a 100644 --- a/res/shaders/ComputeFrustums.slang +++ b/res/shaders/ComputeFrustums.slang @@ -28,10 +28,10 @@ void computeFrustums(ComputeShaderInput in) float4 screenSpace[4]; - screenSpace[0] = float4(in.dispatchThreadID.xy * BLOCK_SIZE, 1.0f, 1.0f); - screenSpace[1] = float4(float2(in.dispatchThreadID.x + 1, in.dispatchThreadID.y) * BLOCK_SIZE, 1.0f, 1.0f); - screenSpace[2] = float4(float2(in.dispatchThreadID.x, in.dispatchThreadID.y + 1) * BLOCK_SIZE, 1.0f, 1.0f); - screenSpace[3] = float4(float2(in.dispatchThreadID.x + 1, in.dispatchThreadID.y + 1) * BLOCK_SIZE, 1.0f, 1.0f); + screenSpace[0] = float4(in.dispatchThreadID.xy * BLOCK_SIZE, -1.0f, 1.0f); + screenSpace[1] = float4(float2(in.dispatchThreadID.x + 1, in.dispatchThreadID.y) * BLOCK_SIZE, -1.0f, 1.0f); + screenSpace[2] = float4(float2(in.dispatchThreadID.x, in.dispatchThreadID.y + 1) * BLOCK_SIZE, -1.0f, 1.0f); + screenSpace[3] = float4(float2(in.dispatchThreadID.x + 1, in.dispatchThreadID.y + 1) * BLOCK_SIZE, -1.0f, 1.0f); //Convert to viewSpace float3 viewSpace[4]; @@ -44,10 +44,10 @@ void computeFrustums(ComputeShaderInput in) //Compute frustum Frustum frustum; - frustum.planes[0] = computePlane(eyePos, viewSpace[0], viewSpace[2]); - frustum.planes[1] = computePlane(eyePos, viewSpace[3], viewSpace[1]); - frustum.planes[2] = computePlane(eyePos, viewSpace[1], viewSpace[0]); - frustum.planes[3] = computePlane(eyePos, viewSpace[2], viewSpace[3]); + frustum.planes[0] = computePlane(eyePos, viewSpace[2], viewSpace[0]); + frustum.planes[1] = computePlane(eyePos, viewSpace[1], viewSpace[3]); + frustum.planes[2] = computePlane(eyePos, viewSpace[0], viewSpace[1]); + frustum.planes[3] = computePlane(eyePos, viewSpace[3], viewSpace[2]); if(in.dispatchThreadID.x < numThreads.x && in.dispatchThreadID.y < numThreads.y) { diff --git a/res/shaders/ForwardPlus.slang b/res/shaders/ForwardPlus.slang index 727ff72..359cc23 100644 --- a/res/shaders/ForwardPlus.slang +++ b/res/shaders/ForwardPlus.slang @@ -32,9 +32,9 @@ VertexStageOutput vertexMain( float4 clipSpacePosition; float3x3 tangentToLocal = cache.getTangentToLocal(); - MaterialVertexParameter vertexParams = input.getMaterialVertexParameters(cache, worldPosition, tangentToLocal); - float4 viewSpacePosition = mul(gViewParams.viewMatrix, float4(worldPosition, 1)); + MaterialVertexParameter vertexParams = input.getMaterialVertexParameters(cache, worldPosition, viewSpacePosition.xyz, tangentToLocal); + clipSpacePosition = mul(gViewParams.projectionMatrix, viewSpacePosition); output.position = clipSpacePosition; output.shaderAttributeInterpolation = input.getInterpolants(cache, vertexParams); @@ -66,12 +66,13 @@ float4 fragmentMain( uint startOffset = gridValue.x; uint lightCount = gridValue.y; - for (int j = 0; j < lightCount; ++j) + for (int j = 0; j < numPointLights; ++j) { - uint lightIndex = lightIndexList[startOffset + j]; - PointLight pointLight = pointLights[lightIndex]; + //uint lightIndex = lightIndexList[startOffset + j]; + PointLight pointLight = pointLights[j]; + if(pointLight.colorRange.w < length(pointLight.getViewPos() - input.viewPosition)) continue; result += pointLight.illuminate(materialParams, brdf, viewDir); } - return float4(result, 0.1f); + return float4(result, 1.0f); } diff --git a/res/shaders/lib/LightEnv.slang b/res/shaders/lib/LightEnv.slang index 09d75af..b206173 100644 --- a/res/shaders/lib/LightEnv.slang +++ b/res/shaders/lib/LightEnv.slang @@ -4,18 +4,18 @@ import Common; interface ILightEnv { - float3 illuminate(MaterialFragmentParameter input, B brdf, float3 wo); + float3 illuminate(MaterialFragmentParameter input, B brdf, float3 wo); }; struct DirectionalLight : ILightEnv { - float4 color; - float4 direction; - float4 intensity; + float4 color; + float4 direction; + float4 intensity; float3 illuminate(MaterialFragmentParameter input, B brdf, float3 wo) - { - return intensity.xyz * brdf.evaluate(wo, normalize(direction.xyz), input.worldNormal, input.worldTangent, input.worldBiTangent, color.xyz); + { + return intensity.xyz * brdf.evaluate(wo, normalize(direction.xyz), input.worldNormal, input.worldTangent, input.worldBiTangent, color.xyz); } }; @@ -25,40 +25,40 @@ struct PointLight : ILightEnv float4 colorRange; float3 illuminate(MaterialFragmentParameter input, B brdf, float3 viewDir) - { + { float3 lightVec = positionWS.xyz - input.worldPosition; float d = length(lightVec); float3 direction = normalize(lightVec); float illuminance = max(1 - d / colorRange.w, 0); - return illuminance * brdf.evaluate(viewDir, direction, input.worldNormal, input.worldTangent, input.worldBiTangent, colorRange.xyz); + return illuminance * brdf.evaluate(viewDir, direction, input.worldNormal, input.worldTangent, input.worldBiTangent, colorRange.xyz); } - bool insidePlane(Plane plane) - { + bool insidePlane(Plane plane) + { return dot(plane.n, getViewPos().xyz) - plane.d < -colorRange.w; - } + } - bool insideFrustum(Frustum frustum, float zNear, float zFar) - { + bool insideFrustum(Frustum frustum, float zNear, float zFar) + { bool result = true; - if(getViewPos().z - colorRange.w > zNear || getViewPos().z + colorRange.w < zFar) - { - result = false; - } - for(int i = 0; i < 4 && result; ++i) - { - if(insidePlane(frustum.planes[i])) - { - result = false; - } - } - return result; - } - float3 getViewPos() - { - return mul(gViewParams.viewMatrix, positionWS).xyz; - } + if(getViewPos().z - colorRange.w > zNear || getViewPos().z + colorRange.w < zFar) + { + //result = false; + } + for(int i = 0; i < 4 && result; ++i) + { + if(insidePlane(frustum.planes[i])) + { + //result = false; + } + } + return result; + } + float3 getViewPos() + { + return mul(gViewParams.viewMatrix, positionWS).xyz; + } }; layout(set = INDEX_LIGHT_ENV, binding = 0, std430) diff --git a/res/shaders/lib/MaterialParameter.slang b/res/shaders/lib/MaterialParameter.slang index 6ec555a..b05adb1 100644 --- a/res/shaders/lib/MaterialParameter.slang +++ b/res/shaders/lib/MaterialParameter.slang @@ -1,6 +1,7 @@ struct MaterialVertexParameter { float3 worldPosition; + float3 viewPosition; float3x3 tangentToWorld; #if NUM_MATERIAL_TEXCOORDS float2 texCoords[NUM_MATERIAL_TEXCOORDS]; diff --git a/res/shaders/lib/StaticMeshVertexInput.slang b/res/shaders/lib/StaticMeshVertexInput.slang index 60e5acd..ed37a38 100644 --- a/res/shaders/lib/StaticMeshVertexInput.slang +++ b/res/shaders/lib/StaticMeshVertexInput.slang @@ -45,6 +45,7 @@ struct VertexValueCache struct ShaderAttributeInterpolation { float3 worldPosition; + float3 viewPosition; float3 normal; float3 tangent; float3 biTangent; @@ -158,10 +159,11 @@ struct VertexShaderInput return cache; } - MaterialVertexParameter getMaterialVertexParameters(VertexValueCache cache, float3 worldPosition, float3x3 tangentToLocal) + MaterialVertexParameter getMaterialVertexParameters(VertexValueCache cache, float3 worldPosition, float3 viewPosition, float3x3 tangentToLocal) { MaterialVertexParameter result; result.worldPosition = worldPosition; + result.viewPosition = viewPosition; result.vertexColor = cache.color; result.tangentToWorld = cache.getTangentToWorld(); // TODO instancing @@ -186,6 +188,7 @@ struct VertexShaderInput result.biTangent = mul(gSceneData.localToWorld, float4(biTangent, 0.0f)).xyz; result.color = color; result.worldPosition = vertexParams.worldPosition; + result.viewPosition = vertexParams.viewPosition; for(int i = 0; i < NUM_MATERIAL_TEXCOORDS; ++i) { if(i % 2) diff --git a/src/Engine/Asset/AssetRegistry.cpp b/src/Engine/Asset/AssetRegistry.cpp index c485937..9a6d037 100644 --- a/src/Engine/Asset/AssetRegistry.cpp +++ b/src/Engine/Asset/AssetRegistry.cpp @@ -27,7 +27,8 @@ void AssetRegistry::importFile(const std::string &filePath) std::filesystem::path fsPath = std::filesystem::path(filePath); std::string extension = fsPath.extension().string(); if (extension.compare(".fbx") == 0 - || extension.compare(".obj") == 0) + || extension.compare(".obj") == 0 + || extension.compare(".blend") == 0) { get().importMesh(fsPath); } diff --git a/src/Engine/Concepts.h b/src/Engine/Concepts.h index 33dcd4d..80fc1c3 100644 --- a/src/Engine/Concepts.h +++ b/src/Engine/Concepts.h @@ -3,11 +3,6 @@ namespace Seele { -template -concept iterable = requires(A&& a) -{ - a.begin(); a.end(); -}; template concept invocable = std::invocable; } \ No newline at end of file diff --git a/src/Engine/Graphics/GraphicsEnums.h b/src/Engine/Graphics/GraphicsEnums.h index 096f48a..299717e 100644 --- a/src/Engine/Graphics/GraphicsEnums.h +++ b/src/Engine/Graphics/GraphicsEnums.h @@ -148,7 +148,7 @@ enum class InputAction REPEAT = 2 }; -enum class KeyModifier +enum class KeyModifier : uint32 { MOD_SHIFT = 0x0001, MOD_CONTROL = 0x0002, diff --git a/src/Engine/Graphics/RenderPass/BasePass.cpp b/src/Engine/Graphics/RenderPass/BasePass.cpp index dc1393e..da9b253 100644 --- a/src/Engine/Graphics/RenderPass/BasePass.cpp +++ b/src/Engine/Graphics/RenderPass/BasePass.cpp @@ -20,7 +20,7 @@ BasePassMeshProcessor::~BasePassMeshProcessor() { } -Job BasePassMeshProcessor::processMeshBatch( +MainJob BasePassMeshProcessor::processMeshBatch( const MeshBatch& batch, // const PPrimitiveComponent primitiveComponent, const Gfx::PRenderPass& renderPass, diff --git a/src/Engine/Graphics/RenderPass/BasePass.h b/src/Engine/Graphics/RenderPass/BasePass.h index bbcc9a4..c63ac42 100644 --- a/src/Engine/Graphics/RenderPass/BasePass.h +++ b/src/Engine/Graphics/RenderPass/BasePass.h @@ -11,7 +11,7 @@ public: BasePassMeshProcessor(Gfx::PViewport viewport, Gfx::PGraphics graphics, uint8 translucentBasePass); virtual ~BasePassMeshProcessor(); - virtual Job processMeshBatch( + virtual MainJob processMeshBatch( const MeshBatch& batch, // const PPrimitiveComponent primitiveComponent, const Gfx::PRenderPass& renderPass, diff --git a/src/Engine/Graphics/RenderPass/DepthPrepass.cpp b/src/Engine/Graphics/RenderPass/DepthPrepass.cpp index 5243a39..b87b640 100644 --- a/src/Engine/Graphics/RenderPass/DepthPrepass.cpp +++ b/src/Engine/Graphics/RenderPass/DepthPrepass.cpp @@ -18,7 +18,7 @@ DepthPrepassMeshProcessor::~DepthPrepassMeshProcessor() { } -Job DepthPrepassMeshProcessor::processMeshBatch( +MainJob DepthPrepassMeshProcessor::processMeshBatch( const MeshBatch& batch, // const PPrimitiveComponent primitiveComponent, const Gfx::PRenderPass& renderPass, diff --git a/src/Engine/Graphics/RenderPass/DepthPrepass.h b/src/Engine/Graphics/RenderPass/DepthPrepass.h index d87ab35..83fad40 100644 --- a/src/Engine/Graphics/RenderPass/DepthPrepass.h +++ b/src/Engine/Graphics/RenderPass/DepthPrepass.h @@ -11,7 +11,7 @@ public: DepthPrepassMeshProcessor(Gfx::PViewport viewport, Gfx::PGraphics graphics); virtual ~DepthPrepassMeshProcessor(); - virtual Job processMeshBatch( + virtual MainJob processMeshBatch( const MeshBatch& batch, const Gfx::PRenderPass& renderPass, Gfx::PPipelineLayout pipelineLayout, diff --git a/src/Engine/Graphics/RenderPass/LightCullingPass.cpp b/src/Engine/Graphics/RenderPass/LightCullingPass.cpp index 1f20035..24b4e27 100644 --- a/src/Engine/Graphics/RenderPass/LightCullingPass.cpp +++ b/src/Engine/Graphics/RenderPass/LightCullingPass.cpp @@ -98,7 +98,7 @@ MainJob LightCullingPass::render() computeCommand->bindPipeline(cullingPipeline); Array descriptorSets = {cullingDescriptorSet, lightEnvDescriptorSet}; computeCommand->bindDescriptor(descriptorSets); - computeCommand->dispatch(dispatchParams.numThreadGroups.x, dispatchParams.numThreadGroups.y, dispatchParams.numThreadGroups.z); + //computeCommand->dispatch(dispatchParams.numThreadGroups.x, dispatchParams.numThreadGroups.y, dispatchParams.numThreadGroups.z); Array commands = {computeCommand}; graphics->executeCommands(commands); depthAttachment->changeLayout(Gfx::SE_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); diff --git a/src/Engine/Graphics/RenderPass/MeshProcessor.h b/src/Engine/Graphics/RenderPass/MeshProcessor.h index 24010ec..a8d84f4 100644 --- a/src/Engine/Graphics/RenderPass/MeshProcessor.h +++ b/src/Engine/Graphics/RenderPass/MeshProcessor.h @@ -17,7 +17,7 @@ public: protected: PScene scene; Gfx::PGraphics graphics; - virtual Job processMeshBatch( + virtual MainJob processMeshBatch( const MeshBatch& batch, // const PPrimitiveComponent primitiveComponent, const Gfx::PRenderPass& renderPass, diff --git a/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.cpp b/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.cpp index 9761db2..6517c73 100644 --- a/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.cpp @@ -81,7 +81,7 @@ void CmdBuffer::executeCommands(const Array& commands) assert(state == State::RenderPassActive); if(commands.size() == 0) { - std::cout << "No commands provided" << std::endl; + //std::cout << "No commands provided" << std::endl; return; } std::scoped_lock lock(handleLock); diff --git a/src/Engine/Material/MaterialAsset.cpp b/src/Engine/Material/MaterialAsset.cpp index 103c7af..051fb9d 100644 --- a/src/Engine/Material/MaterialAsset.cpp +++ b/src/Engine/Material/MaterialAsset.cpp @@ -106,11 +106,10 @@ void MaterialAsset::load() std::string defaultString = defaultValue.value().get(); p->data = AssetRegistry::findTexture(defaultString); } - else + if(p->data == nullptr) { p->data = AssetRegistry::findTexture(""); // this will return placeholder texture } - assert(p->data != nullptr); parameters.add(p); } else if(type.compare("SamplerState") == 0) diff --git a/src/Engine/Math/Transform.cpp b/src/Engine/Math/Transform.cpp index c24bcbf..41588a9 100644 --- a/src/Engine/Math/Transform.cpp +++ b/src/Engine/Math/Transform.cpp @@ -4,7 +4,7 @@ using namespace Seele; Transform::Transform() - : position(Vector4(0, 0, 0, 0)), rotation(Quaternion(0, 0, 0, 0)), scale(Vector4(1, 1, 1, 0)) + : position(Vector4(0, 0, 0, 0)), rotation(Quaternion(1, 0, 0, 0)), scale(Vector4(1, 1, 1, 0)) { } @@ -12,7 +12,7 @@ Transform::Transform(Transform &&other) : position(other.position), rotation(other.rotation), scale(other.scale) { other.position = Vector4(0, 0, 0, 0); - other.rotation = Quaternion(0, 0, 0, 0); + other.rotation = Quaternion(1, 0, 0, 0); other.scale = Vector4(0, 0, 0, 0); } @@ -22,7 +22,7 @@ Transform::Transform(const Transform &other) } Transform::Transform(Vector position) - : position(Vector4(position, 0)), rotation(Quaternion(0, 0, 0, 0)), scale(Vector4(1, 1, 1, 0)) + : position(Vector4(position, 0)), rotation(Quaternion(1, 0, 0, 0)), scale(Vector4(1, 1, 1, 0)) { } Transform::Transform(Vector position, Quaternion rotation) @@ -144,6 +144,19 @@ Vector Transform::getScale() const return Vector(scale); } +Vector Transform::getForward() const +{ + return Vector(0, 0, 1) * rotation; +} +Vector Transform::getRight() const +{ + return Vector(1, 0, 0) * rotation; +} +Vector Transform::getUp() const +{ + return Vector(0, 1, 0) * rotation; +} + bool Transform::equals(const Transform &other, float tolerance) { if (abs(position - other.position).length() > tolerance) @@ -174,6 +187,13 @@ void Transform::multiply(Transform *outTransform, const Transform *a, const Tran outTransform->position = b->rotation * (b->scale * a->position) + b->position; outTransform->scale = b->scale * a->scale; } +void Transform::add(Transform *outTransform, const Transform *a, const Transform *b) +{ + outTransform->position = a->position + b->position; + outTransform->rotation = a->rotation + b->rotation; + outTransform->scale = a->scale + b->scale; +} + Transform &Transform::operator=(const Transform &other) { @@ -189,11 +209,18 @@ Transform &Transform::operator=(Transform &&other) rotation = other.rotation; scale = other.scale; other.position = Vector4(0, 0, 0, 0); - other.rotation = Quaternion(0, 0, 0, 0); + other.rotation = Quaternion(1, 0, 0, 0); other.scale = Vector4(0, 0, 0, 0); return *this; } +Transform Transform::operator+(const Transform & other) const +{ + Transform outTransform; + add(&outTransform, this, &other); + return outTransform; +} + Transform Transform::operator*(const Transform &other) const { Transform outTransform; diff --git a/src/Engine/Math/Transform.h b/src/Engine/Math/Transform.h index d35351c..3863faf 100644 --- a/src/Engine/Math/Transform.h +++ b/src/Engine/Math/Transform.h @@ -23,12 +23,17 @@ public: Vector getPosition() const; Quaternion getRotation() const; Vector getScale() const; + Vector getForward() const; + Vector getRight() const; + Vector getUp() const; bool equals(const Transform &other, float tolerance = 0.000000001f); static void multiply(Transform *outTransform, const Transform *a, const Transform *b); + static void add(Transform *outTransform, const Transform *a, const Transform *b); Transform &operator=(const Transform &other); Transform &operator=(Transform &&other); + Transform operator+(const Transform& other) const; Transform operator*(const Transform &other) const; private: diff --git a/src/Engine/Math/Vector.h b/src/Engine/Math/Vector.h index 765a686..4e460a7 100644 --- a/src/Engine/Math/Vector.h +++ b/src/Engine/Math/Vector.h @@ -64,30 +64,6 @@ static inline float normalizeRotatorAxis(float angle) return angle; } -static inline Quaternion toQuaternion(const Vector &other) -{ - Quaternion result; - const float DEG_TO_RAD = glm::pi() / (180.f); - const float RADS_DIVIDED_BY_2 = DEG_TO_RAD / 2.f; - - const float PitchNoWinding = fmod(other.x, 360.0f); - const float YawNoWinding = fmod(other.y, 360.0f); - const float RollNoWinding = fmod(other.z, 360.0f); - - const float SP = sin(PitchNoWinding * RADS_DIVIDED_BY_2); - const float SY = sin(YawNoWinding * RADS_DIVIDED_BY_2); - const float SR = sin(RollNoWinding * RADS_DIVIDED_BY_2); - - const float CP = cos(PitchNoWinding * RADS_DIVIDED_BY_2); - const float CY = cos(YawNoWinding * RADS_DIVIDED_BY_2); - const float CR = cos(RollNoWinding * RADS_DIVIDED_BY_2); - - result.x = CR * SP * SY - SR * CP * CY; - result.y = -CR * SP * CY - SR * CP * SY; - result.z = CR * CP * SY - SR * SP * CY; - result.w = CR * CP * CY + SR * SP * SY; - return result; -} static inline Vector toRotator(const Quaternion &other) { diff --git a/src/Engine/Scene/Actor/Actor.cpp b/src/Engine/Scene/Actor/Actor.cpp index 0dc19e8..12e14ce 100644 --- a/src/Engine/Scene/Actor/Actor.cpp +++ b/src/Engine/Scene/Actor/Actor.cpp @@ -74,23 +74,23 @@ void Actor::detachChild(PActor child) child->setParent(nullptr); child->notifySceneAttach(nullptr); } -void Actor::setWorldLocation(Vector location) -{ - rootComponent->setWorldLocation(location); -} - -void Actor::setWorldRotation(Quaternion rotation) -{ - rootComponent->setWorldRotation(rotation); -} -void Actor::setWorldRotation(Vector rotation) -{ - rootComponent->setWorldRotation(rotation); -} -void Actor::setWorldScale(Vector scale) -{ - rootComponent->setWorldScale(scale); -} +//void Actor::setAbsoluteLocation(Vector location) +//{ +// rootComponent->setWorldLocation(location); +//} +// +//void Actor::setAbsoluteRotation(Quaternion rotation) +//{ +// rootComponent->setAbsoluteRotation(rotation); +//} +//void Actor::setAbsoluteRotation(Vector rotation) +//{ +// rootComponent->setAbsoluteRotation(rotation); +//} +//void Actor::setWorldScale(Vector scale) +//{ +// rootComponent->setWorldScale(scale); +//} void Actor::setRelativeLocation(Vector location) { rootComponent->setRelativeLocation(location); @@ -107,17 +107,29 @@ void Actor::setRelativeScale(Vector scale) { rootComponent->setRelativeScale(scale); } -void Actor::addWorldTranslation(Vector translation) +//void Actor::addAbsoluteTranslation(Vector translation) +//{ +// rootComponent->addAbsoluteTranslation(translation); +//} +//void Actor::addAbsoluteRotation(Quaternion rotation) +//{ +// rootComponent->addAbsoluteRotation(rotation); +//} +//void Actor::addAbsoluteRotation(Vector rotation) +//{ +// rootComponent->addAbsoluteRotation(rotation); +//} +void Actor::addRelativeLocation(Vector translation) { - rootComponent->addWorldTranslation(translation); + rootComponent->addRelativeLocation(translation); } -void Actor::addWorldRotation(Quaternion rotation) +void Actor::addRelativeRotation(Quaternion rotation) { - rootComponent->addWorldRotation(rotation); + rootComponent->addRelativeRotation(rotation); } -void Actor::addWorldRotation(Vector rotation) +void Actor::addRelativeRotation(Vector rotation) { - rootComponent->addWorldRotation(rotation); + rootComponent->addRelativeRotation(rotation); } PComponent Actor::getRootComponent() { diff --git a/src/Engine/Scene/Actor/Actor.h b/src/Engine/Scene/Actor/Actor.h index 424ee1e..b75164c 100644 --- a/src/Engine/Scene/Actor/Actor.h +++ b/src/Engine/Scene/Actor/Actor.h @@ -26,19 +26,23 @@ public: void addChild(PActor child); void detachChild(PActor child); Array getChildren(); - void setWorldLocation(Vector location); - void setWorldRotation(Quaternion rotation); - void setWorldRotation(Vector rotation); - void setWorldScale(Vector scale); + //void setAbsoluteLocation(Vector location); + //void setAbsoluteRotation(Quaternion rotation); + //void setAbsoluteRotation(Vector rotation); + //void setWorldScale(Vector scale); void setRelativeLocation(Vector location); void setRelativeRotation(Quaternion rotation); void setRelativeRotation(Vector rotation); void setRelativeScale(Vector scale); - void addWorldTranslation(Vector translation); - void addWorldRotation(Quaternion rotation); - void addWorldRotation(Vector rotation); + //void addAbsoluteTranslation(Vector translation); + //void addAbsoluteRotation(Quaternion rotation); + //void addAbsoluteRotation(Vector rotation); + + void addRelativeLocation(Vector translation); + void addRelativeRotation(Quaternion rotation); + void addRelativeRotation(Vector rotation); PComponent getRootComponent(); void setRootComponent(PComponent newRoot); diff --git a/src/Engine/Scene/Actor/CameraActor.cpp b/src/Engine/Scene/Actor/CameraActor.cpp index 3b9d835..d374a2e 100644 --- a/src/Engine/Scene/Actor/CameraActor.cpp +++ b/src/Engine/Scene/Actor/CameraActor.cpp @@ -14,8 +14,6 @@ CameraActor::CameraActor() cameraComponent->aspectRatio = 1.777778f; cameraComponent->setParent(sceneComponent); cameraComponent->setOwner(this); - addWorldTranslation(Vector(0, 0, 50)); - addWorldRotation(Vector(0, -100, 0)); } CameraActor::~CameraActor() diff --git a/src/Engine/Scene/Components/CameraComponent.cpp b/src/Engine/Scene/Components/CameraComponent.cpp index e876562..461fe22 100644 --- a/src/Engine/Scene/Components/CameraComponent.cpp +++ b/src/Engine/Scene/Components/CameraComponent.cpp @@ -6,19 +6,16 @@ using namespace Seele; CameraComponent::CameraComponent() - : aspectRatio(0) - , fieldOfView(0) + : aspectRatio(0) + , fieldOfView(0) , bNeedsViewBuild(true) , bNeedsProjectionBuild(true) - , originPoint(0, 0, 0) - , cameraPosition(0, 0, 50) - , eye(Vector()) - , projectionMatrix(Matrix4()) - , viewMatrix(Matrix4()) + , projectionMatrix(Matrix4()) + , viewMatrix(Matrix4()) { - distance = 50; rotationX = 0; - rotationY = -1.f; + rotationY = 0; + setRelativeLocation(Vector(0, 10, -50)); } CameraComponent::~CameraComponent() @@ -27,54 +24,52 @@ CameraComponent::~CameraComponent() void CameraComponent::mouseMove(float deltaX, float deltaY) { - //0.01 mouse sensitivity - rotationX += deltaX/500.f; - rotationY += deltaY/500.f; - rotationY = std::clamp(rotationY, -1.5f, 1.5f); - getParent()->setWorldRotation(glm::rotate(glm::quat(), rotationX, Vector(0, 1, 0))); - getParent()->setWorldRotation(glm::rotate(glm::quat(), rotationY, Vector(1, 0, 0))); - bNeedsViewBuild = true; + rotationX -= deltaX / 1000.f; + rotationY += deltaY / 1000.f; + //std::cout << "X:" << rotationX << " Y: " << rotationY << std::endl; + setRelativeRotation(Vector(rotationY, rotationX, 0)); + bNeedsViewBuild = true; } -void CameraComponent::mouseScroll(double x) +void CameraComponent::mouseScroll(float x) { - distance -= static_cast(x); - distance = std::max(distance, 1.f); - getParent()->addWorldTranslation(Vector(0, 0, x)); - bNeedsViewBuild = true; + addRelativeLocation(getTransform().getForward()*x); + bNeedsViewBuild = true; } -void CameraComponent::moveOrigin(float up) +void CameraComponent::moveX(float amount) { - originPoint.y += up; - getParent()->addWorldTranslation(Vector(0, up, 0)); - bNeedsViewBuild = true; + addRelativeLocation(getTransform().getForward()*amount); + bNeedsViewBuild = true; +} + +void CameraComponent::moveY(float amount) +{ + addRelativeLocation(getTransform().getRight()*amount); + bNeedsViewBuild = true; } void CameraComponent::buildViewMatrix() { - Matrix4 rotation = glm::rotate(Matrix4(1.0f), rotationX, Vector(0, 1, 0)); - rotation = glm::rotate(rotation, rotationY, Vector(1, 0, 0)); - Vector4 translation(0, 0, distance, 1); - translation = rotation * translation; + Vector eyePos = getTransform().getPosition(); + Vector lookAt = eyePos + getTransform().getForward(); + std::cout << "Eye: " << eyePos << " lookAt: " << lookAt << std::endl; + viewMatrix = glm::lookAt(eyePos, lookAt, Vector(0, 1, 0)); - cameraPosition = originPoint + Vector(translation); - viewMatrix = glm::lookAt(cameraPosition, originPoint, Vector(0, 1, 0)); - - bNeedsViewBuild = false; + bNeedsViewBuild = false; } void CameraComponent::buildProjectionMatrix() { projectionMatrix = glm::perspective(fieldOfView, aspectRatio, 1.0f, 1000.f); - static Matrix4 correctionMatrix = - Matrix4( - Vector4(1, 0, 0, 0), - Vector4(0, 1, 0, 0), - Vector4(0, 0, 0.5f, 0), - Vector4(0, 0, 0.5f, 1)); - projectionMatrix = correctionMatrix * projectionMatrix; - bNeedsProjectionBuild = false; + static Matrix4 correctionMatrix = + Matrix4( + Vector4(1, 0, 0, 0), + Vector4(0, 1, 0, 0), + Vector4(0, 0, 0.5f, 0), + Vector4(0, 0, 0.5f, 1)); + projectionMatrix = correctionMatrix * projectionMatrix; + bNeedsProjectionBuild = false; } diff --git a/src/Engine/Scene/Components/CameraComponent.h b/src/Engine/Scene/Components/CameraComponent.h index e353528..a062448 100644 --- a/src/Engine/Scene/Components/CameraComponent.h +++ b/src/Engine/Scene/Components/CameraComponent.h @@ -10,51 +10,43 @@ public: CameraComponent(); virtual ~CameraComponent(); - Matrix4 getViewMatrix() - { - if (bNeedsViewBuild) - { - buildViewMatrix(); - } - return viewMatrix; - } - Matrix4 getProjectionMatrix() - { - if (bNeedsProjectionBuild) - { - buildProjectionMatrix(); - } - return projectionMatrix; - } - Vector getCameraPosition() - { - if(bNeedsViewBuild) - { - buildViewMatrix(); - } - return cameraPosition; - } - void mouseMove(float deltaX, float deltaY); - void mouseScroll(double x); - void moveOrigin(float up); - float aspectRatio; - float fieldOfView; + Matrix4 getViewMatrix() + { + if (bNeedsViewBuild) + { + buildViewMatrix(); + } + return viewMatrix; + } + Matrix4 getProjectionMatrix() + { + if (bNeedsProjectionBuild) + { + buildProjectionMatrix(); + } + return projectionMatrix; + } + Vector getCameraPosition() + { + return getTransform().getPosition(); + } + void mouseMove(float deltaX, float deltaY); + void mouseScroll(float x); + void moveX(float amount); + void moveY(float amount); + float aspectRatio; + float fieldOfView; private: bool bNeedsViewBuild; - bool bNeedsProjectionBuild; - void buildViewMatrix(); - void buildProjectionMatrix(); + bool bNeedsProjectionBuild; + void buildViewMatrix(); + void buildProjectionMatrix(); - float rotationX; - float rotationY; - float distance; - - Vector eye; - Vector originPoint; - Vector cameraPosition; - //Transforms relative to actor - Matrix4 viewMatrix; - Matrix4 projectionMatrix; + //Transforms relative to actor + Matrix4 viewMatrix; + Matrix4 projectionMatrix; + float rotationX; + float rotationY; }; DEFINE_REF(CameraComponent) } // namespace Seele diff --git a/src/Engine/Scene/Components/Component.cpp b/src/Engine/Scene/Components/Component.cpp index b97785f..701ff48 100644 --- a/src/Engine/Scene/Components/Component.cpp +++ b/src/Engine/Scene/Components/Component.cpp @@ -6,9 +6,6 @@ using namespace Seele; Component::Component() { - relativeLocation = Vector(0); - relativeRotation = Vector(0); - relativeScale = Vector(1, 1, 1); } Component::~Component() { @@ -89,162 +86,101 @@ void Component::notifySceneAttach(PScene scene) child->notifySceneAttach(scene); } } -void Component::setWorldLocation(Vector location) -{ - Vector newRelLocation = location; - if (parent != nullptr) - { - Transform parentToWorld = getParent()->getTransform(); - newRelLocation = parentToWorld.inverseTransformPosition(location); - } - setRelativeLocation(newRelLocation); -} -void Component::setWorldRotation(Vector rotation) -{ - Vector newRelRotator = rotation; - if (parent == nullptr) - { - setRelativeRotation(rotation); - } - else - { - setWorldRotation(toQuaternion(newRelRotator)); - } -} -void Component::setWorldRotation(Quaternion rotation) -{ - Quaternion newRelRotation = getRelativeWorldRotation(rotation); - setRelativeRotation(newRelRotation); -} -void Component::setWorldScale(Vector scale) -{ - Vector newRelScale = scale; - if (parent != nullptr) - { - Transform parentToWorld = parent->getTransform(); - newRelScale = scale * parentToWorld.getSafeScaleReciprocal(Vector4(parentToWorld.getScale(), 0)); - } - setRelativeScale(newRelScale); -} + +//void Component::setAbsoluteLocation(Vector location) +//{ +// Vector newRelLocation = location; +// if (parent != nullptr) +// { +// Transform parentToWorld = getParent()->getTransform(); +// newRelLocation = parentToWorld.inverseTransformPosition(location); +// } +// setRelativeLocation(newRelLocation); +//} +//void Component::setAbsoluteRotation(Vector rotation) +//{ +// Vector newRelRotator = rotation; +// if (parent == nullptr) +// { +// setRelativeRotation(rotation); +// } +// else +// { +// setAbsoluteRotation(toQuaternion(newRelRotator)); +// } +//} +//void Component::setAbsoluteRotation(Quaternion rotation) +//{ +// Quaternion newRelRotation = getRelativeWorldRotation(rotation); +// setRelativeRotation(newRelRotation); +//} +//void Component::setWorldScale(Vector scale) +//{ +// Vector newRelScale = scale; +// if (parent != nullptr) +// { +// Transform parentToWorld = parent->getTransform(); +// newRelScale = scale * parentToWorld.getSafeScaleReciprocal(Vector4(parentToWorld.getScale(), 0)); +// } +// setRelativeScale(newRelScale); +//} + void Component::setRelativeLocation(Vector location) { - setRelativeLocationAndRotation(location, relativeRotation); + transform = Transform(location, transform.getRotation(), transform.getScale()); } void Component::setRelativeRotation(Vector rotation) { - setRelativeLocationAndRotation(relativeLocation, toQuaternion(rotation)); + transform = Transform(transform.getPosition(), Quaternion(rotation), transform.getScale()); } void Component::setRelativeRotation(Quaternion rotation) { - setRelativeLocationAndRotation(relativeLocation, rotation); + transform = Transform(transform.getPosition(), rotation, transform.getScale()); } void Component::setRelativeScale(Vector scale) { - if (scale != relativeScale) - { - relativeScale = scale; - updateComponentTransform(relativeRotation); - } + transform = Transform(transform.getPosition(), transform.getRotation(), scale); } -void Component::addWorldTranslation(Vector translation) + +//void Component::addAbsoluteTranslation(Vector translation) +//{ +// const Vector newWorldLocation = translation + getTransform().getPosition(); +// setAbsoluteLocation(newWorldLocation); +//} +//void Component::addAbsoluteRotation(Vector rotation) +//{ +// const Quaternion newWorldRotation = toQuaternion(rotation) * getTransform().getRotation(); +// setAbsoluteRotation(newWorldRotation); +//} +//void Component::addAbsoluteRotation(Quaternion rotation) +//{ +// const Quaternion newWorldRotation = rotation * getTransform().getRotation(); +// setAbsoluteRotation(newWorldRotation); +//} + +void Component::addRelativeLocation(Vector translation) { - const Vector newWorldLocation = translation + getTransform().getPosition(); - setWorldLocation(newWorldLocation); + transform = Transform(transform.getPosition() + translation, transform.getRotation(), transform.getScale()); } -void Component::addWorldRotation(Vector rotation) +void Component::addRelativeRotation(Vector rotation) { - const Quaternion newWorldRotation = toQuaternion(rotation) * getTransform().getRotation(); - setWorldRotation(newWorldRotation); + transform = Transform(transform.getPosition(), transform.getRotation() + Quaternion(rotation), transform.getScale()); } -void Component::addWorldRotation(Quaternion rotation) +void Component::addRelativeRotation(Quaternion rotation) { - const Quaternion newWorldRotation = rotation * getTransform().getRotation(); - setWorldRotation(newWorldRotation); + transform = Transform(transform.getPosition(), transform.getRotation(), transform.getScale()); } + Transform Component::getTransform() const { return transform; } -void Component::internalSetTransform(Vector newLocation, Quaternion newRotation) +Transform Component::getAbsoluteTransform() const { - if (parent != nullptr) - { - Transform parentTransform = parent->getTransform(); - newLocation = parentTransform.inverseTransformPosition(newLocation); - newRotation = glm::inverse(parentTransform.getRotation()) * newRotation; - } - - const Vector newRelRotation = toRotator(newRotation); - if (newLocation != relativeLocation || newRelRotation != relativeLocation) - { - relativeLocation = newLocation; - relativeRotation = newRelRotation; - updateComponentTransform(newRelRotation); - } -} - -void Component::propagateTransformUpdate() -{ - for (auto child : children) - { - child->updateComponentTransform(child->relativeRotation); - } -} - -void Component::updateComponentTransform(Quaternion relativeRotationQuat) -{ - if (parent != nullptr && !parent->bComponentTransformClean) - { - parent->updateComponentTransform(parent->relativeRotation); - - if (bComponentTransformClean) - { - return; - } - } - bComponentTransformClean = true; - Transform newTransform; - const Transform relTransform(relativeLocation, relativeRotationQuat, relativeScale); if(parent != nullptr) { - newTransform = relTransform * parent->getTransform(); + return transform + parent->getAbsoluteTransform(); } - else - { - newTransform = relTransform; - } - bool bHasChanged = !getTransform().equals(newTransform); - if (bHasChanged) - { - transform = newTransform; - propagateTransformUpdate(); - } -} - -Quaternion Component::getRelativeWorldRotation(Quaternion worldRotation) -{ - Quaternion newRelRotation = worldRotation; - if (parent != nullptr) - { - const Transform parentToWorld = parent->getTransform(); - - const Quaternion parentToWorldQuat = parentToWorld.getRotation(); - const Quaternion newRelQuat = glm::inverse(parentToWorldQuat) * worldRotation; - newRelRotation = newRelQuat; - } - return newRelRotation; -} - -void Component::setRelativeLocationAndRotation(Vector newLocation, Quaternion newRotation) -{ - if (!bComponentTransformClean) - { - updateComponentTransform(toQuaternion(relativeRotation)); - } - - const Transform desiredRelTransform(newLocation, newRotation); - const Transform desiredWorldTransform = desiredRelTransform; // Check for absolutes etc - - internalSetTransform(desiredWorldTransform.getPosition(), desiredWorldTransform.getRotation()); -} + return transform; +} \ No newline at end of file diff --git a/src/Engine/Scene/Components/Component.h b/src/Engine/Scene/Components/Component.h index 95dae38..6479cc6 100644 --- a/src/Engine/Scene/Components/Component.h +++ b/src/Engine/Scene/Components/Component.h @@ -28,27 +28,33 @@ public: void addChildComponent(PComponent component); virtual void notifySceneAttach(PScene scene); - void setWorldLocation(Vector location); - void setWorldRotation(Vector rotation); - void setWorldRotation(Quaternion rotation); - void setWorldScale(Vector scale); + //void setAbsoluteLocation(Vector location); + //void setAbsoluteRotation(Vector rotation); + //void setAbsoluteRotation(Quaternion rotation); + //void setWorldScale(Vector scale); void setRelativeLocation(Vector location); void setRelativeRotation(Vector rotation); void setRelativeRotation(Quaternion rotation); void setRelativeScale(Vector scale); - void addWorldTranslation(Vector translation); - void addWorldRotation(Vector rotation); - void addWorldRotation(Quaternion rotation); + //void addAbsoluteTranslation(Vector translation); + //void addAbsoluteRotation(Vector rotation); + //void addAbsoluteRotation(Quaternion rotation); + + void addRelativeLocation(Vector translation); + void addRelativeRotation(Vector rotation); + void addRelativeRotation(Quaternion rotation); Transform getTransform() const; + Transform getAbsoluteTransform() const; template RefPtr getComponent() { return tryFindComponent(); } + private: template RefPtr tryFindComponent() @@ -68,15 +74,6 @@ private: } return nullptr; } - void internalSetTransform(Vector newLocation, Quaternion newRotation); - void propagateTransformUpdate(); - void updateComponentTransform(Quaternion relativeRotationQuat); - Quaternion getRelativeWorldRotation(Quaternion worldRotation); - void setRelativeLocationAndRotation(Vector newLocation, Quaternion newRotation); - uint8 bComponentTransformClean : 1; - Vector relativeLocation; - Vector relativeRotation; - Vector relativeScale; Transform transform; PScene owningScene; PActor owner; diff --git a/src/Engine/Scene/Components/PrimitiveComponent.cpp b/src/Engine/Scene/Components/PrimitiveComponent.cpp index aefba4d..7f83011 100644 --- a/src/Engine/Scene/Components/PrimitiveComponent.cpp +++ b/src/Engine/Scene/Components/PrimitiveComponent.cpp @@ -50,5 +50,5 @@ void PrimitiveComponent::notifySceneAttach(PScene scene) Matrix4 PrimitiveComponent::getRenderMatrix() { - return getTransform().toMatrix(); + return getAbsoluteTransform().toMatrix(); } diff --git a/src/Engine/Scene/Scene.cpp b/src/Engine/Scene/Scene.cpp index 82680c9..2ca134e 100644 --- a/src/Engine/Scene/Scene.cpp +++ b/src/Engine/Scene/Scene.cpp @@ -19,12 +19,12 @@ Scene::Scene(Gfx::PGraphics graphics) lightEnv.directionalLights[0].intensity = Vector4(1, 1, 1, 1); lightEnv.numDirectionalLights = 1; srand((unsigned int)time(NULL)); - for(uint32 i = 0; i < 256; ++i) + for(uint32 i = 0; i < 16; ++i) { lightEnv.pointLights[i].colorRange = Vector4(frand(), frand(), frand(), frand() * 300); lightEnv.pointLights[i].positionWS = Vector4(frand() * 100-50, frand(), frand() * 100-50, 1); } - lightEnv.numPointLights = 256; + lightEnv.numPointLights = 16; lightEnv.pointLights[0].colorRange = Vector4(1, 0, 1, 1000); lightEnv.pointLights[0].positionWS = Vector4(0, 10, 0, 1); } @@ -41,19 +41,28 @@ void Scene::start() } } +static float lastUpdate; +static uint64 numUpdates; + Job Scene::beginUpdate(double deltaTime) { //std::cout << "Scene::beginUpdate" << std::endl; + auto startTime = std::chrono::high_resolution_clock::now(); Array jobs; for(auto actor : rootActors) { jobs.addAll(actor->launchTick(static_cast(deltaTime))); } co_await Job::all(jobs); - //std::cout << "Scene::beginUpdate finished waiting" << std::endl; - for(auto job : jobs) + auto endTime = std::chrono::high_resolution_clock::now(); + float delta = std::chrono::duration_cast(endTime - startTime).count(); + lastUpdate += delta; + numUpdates++; + if(lastUpdate > 1.0f) { - assert(job.done()); + lastUpdate -= 1.0f; + std::cout << numUpdates << " updates per second" << std::endl; + numUpdates = 0; } } diff --git a/src/Engine/Scene/Scene.h b/src/Engine/Scene/Scene.h index 25749e7..e653eb7 100644 --- a/src/Engine/Scene/Scene.h +++ b/src/Engine/Scene/Scene.h @@ -19,6 +19,7 @@ struct DirectionalLight struct PointLight { Vector4 positionWS; + //Vector4 positionVS; Vector4 colorRange; }; diff --git a/src/Engine/Scene/Util.h b/src/Engine/Scene/Util.h index 15cd902..ca47268 100644 --- a/src/Engine/Scene/Util.h +++ b/src/Engine/Scene/Util.h @@ -123,7 +123,7 @@ public: void update() { // lock should not be necessary, but lets keep it for now - std::scoped_lock lock(dataLock); + //std::scoped_lock lock(dataLock); data = toBeWritten; dirty = false; } diff --git a/src/Engine/ThreadPool.cpp b/src/Engine/ThreadPool.cpp index e4c72a0..7c2f780 100644 --- a/src/Engine/ThreadPool.cpp +++ b/src/Engine/ThreadPool.cpp @@ -3,7 +3,6 @@ using namespace Seele; -std::atomic_uint64_t Seele::globalCounter; Event::Event() : flag(std::make_shared()) @@ -16,11 +15,20 @@ Event::Event(nullptr_t) } Event::Event(const std::string &name) - : name(name) - , flag(std::make_shared()) + : flag(std::make_shared()) { + flag->name = name; } + +Event::Event(const std::source_location &location) + : flag(std::make_shared()) +{ + flag->name = location.function_name(); + flag->location = location; +} + + void Event::raise() { std::scoped_lock lock(flag->lock); @@ -50,43 +58,34 @@ ThreadPool::ThreadPool(uint32 threadCount) running.store(true); for (uint32 i = 0; i < threadCount; ++i) { - workers[i] = std::thread(&ThreadPool::threadLoop, this, false); + workers[i] = std::thread(&ThreadPool::threadLoop, this); + workers[i].detach(); } } ThreadPool::~ThreadPool() { - cleanup(); + workers.clear(); } -void ThreadPool::cleanup() +void ThreadPool::waitIdle() { - bool temp = true; - running.compare_exchange_strong(temp, false); - if(!temp) - return; + while(true) { - std::scoped_lock lock(jobQueueLock); - jobQueueCV.notify_all(); + std::unique_lock lock(numIdlingLock); + numIdlingIncr.wait(lock); + if(numIdling == workers.size()) + { + return; + } } - { - std::scoped_lock lock(mainJobLock); - mainJobCV.notify_all(); - } - for (auto &thread : workers) - { - thread.join(); - } - workers.clear(); - waitingJobs.clear(); - waitingMainJobs.clear(); } void ThreadPool::enqueueWaiting(Event &event, Promise* job) { assert(!job->done()); std::scoped_lock lock(waitingLock); //std::cout << "Job " << job->finishedEvent.name << " waiting on event " << event.name << std::endl; - waitingJobs[event].push_back(job); + waitingJobs[event].add(job); job->addRef(); } void ThreadPool::enqueueWaiting(Event &event, MainPromise* job) @@ -94,15 +93,15 @@ void ThreadPool::enqueueWaiting(Event &event, MainPromise* job) assert(!job->done()); std::scoped_lock lock(waitingMainLock); //std::cout << job->finishedEvent.name << " waiting on event " << event.name << std::endl; - waitingMainJobs[event].push_back(job); + waitingMainJobs[event].add(job); job->addRef(); } void ThreadPool::scheduleJob(Promise* job) { assert(!job->done()); std::scoped_lock lock(jobQueueLock); - //std::cout << "Queueing job " << job->finishedEvent.name << std::endl; - jobQueue.push_back(job); + //std::cout << "Queueing job " << job->finishedEvent << std::endl; + jobQueue.add(job); jobQueueCV.notify_one(); job->addRef(); } @@ -110,8 +109,8 @@ void ThreadPool::scheduleJob(MainPromise* job) { assert(!job->done()); std::scoped_lock lock(mainJobLock); - //std::cout << "Queueing job " << job->finishedEvent.name << std::endl; - mainJobs.push_back(job); + //std::cout << "Queueing job " << job->finishedEvent << std::endl; + mainJobs.add(job); mainJobCV.notify_one(); job->addRef(); } @@ -120,79 +119,86 @@ void ThreadPool::notify(Event &event) //std::cout << "Event " << event.name << " raised" << std::endl; { std::scoped_lock lock(jobQueueLock, waitingLock); - std::list jobs = std::move(waitingJobs[event]); + List jobs = std::move(waitingJobs[event]); waitingJobs.erase(event); for (auto &job : jobs) { //assert(job.id != -1ull); //std::cout << "Waking up " << job->finishedEvent.name << std::endl; job->state = Promise::State::SCHEDULED; - jobQueue.push_back(job); + jobQueue.add(job); jobQueueCV.notify_one(); } } { std::scoped_lock lock(mainJobLock, waitingMainLock); - std::list jobs = std::move(waitingMainJobs[event]); + List jobs = std::move(waitingMainJobs[event]); waitingMainJobs.erase(event); for (auto &job : jobs) { //assert(job.id != -1ull); //std::cout << "Waking up main " << job->finishedEvent.name << std::endl; job->state = MainPromise::State::SCHEDULED; - mainJobs.push_back(job); + mainJobs.add(job); mainJobCV.notify_one(); } } } -void ThreadPool::threadLoop(const bool mainThread) + +void ThreadPool::mainLoop() { - while (running.load()) + while(true) { - if (mainThread) + MainPromise* job; { - MainPromise* job; + std::unique_lock lock(mainJobLock); + if(mainJobs.empty()) { - std::unique_lock lock(mainJobLock); - if(mainJobs.empty()) - { - mainJobCV.wait(lock); - } - if (!mainJobs.empty()) - { - job = mainJobs.front(); - mainJobs.pop_front(); - } - else - { - continue; - } + mainJobCV.wait(lock); } + job = mainJobs.front(); + mainJobs.popFront(); + } + job->resume(); + job->removeRef(); + } +} + +void ThreadPool::threadLoop() +{ + List localQueue; + while (true) + { + [[likely]] + if(!localQueue.empty()) + { + Promise* job = localQueue.retrieve(); job->resume(); job->removeRef(); } else { - Promise* job; + std::unique_lock lock(jobQueueLock); + if (jobQueue.empty()) { - std::unique_lock lock(jobQueueLock); - if (jobQueue.empty()) { - jobQueueCV.wait(lock); + std::unique_lock lock2(numIdlingLock); + numIdling++; + numIdlingIncr.notify_one(); } - if (!jobQueue.empty()) + jobQueueCV.wait(lock); { - job = jobQueue.front(); - jobQueue.pop_front(); - } - else - { - continue; + std::unique_lock lock2(numIdlingLock); + numIdling--; } } - //std::cout << "Starting job " << job.id << std::endl; - job->resume(); - job->removeRef(); + // take 1/numThreads jobs, maybe make this a parameter that + // adjusts based on past workload + uint32 numTaken = std::max(jobQueue.size() / workers.size(), 1ull); + while (!jobQueue.empty() && localQueue.size() < numTaken) + { + localQueue.add(jobQueue.retrieve()); + } } } } diff --git a/src/Engine/ThreadPool.h b/src/Engine/ThreadPool.h index 5e36630..93a53dc 100644 --- a/src/Engine/ThreadPool.h +++ b/src/Engine/ThreadPool.h @@ -17,6 +17,7 @@ public: Event(); Event(nullptr_t); Event(const std::string& name); + Event(const std::source_location& location); ~Event() = default; auto operator<=>(const Event& other) const { @@ -36,6 +37,19 @@ public: return flag->data; } + friend std::ostream& operator<<(std::ostream& stream, const Event& event) + { + stream + << event.flag->location.file_name() + << "(" + << event.flag->location.line() + << ":" + << event.flag->location.column() + << "): " + << event.flag->location.function_name(); + return stream; + } + void raise(); void reset(); bool await_ready(); @@ -43,17 +57,17 @@ public: constexpr void await_suspend(std::coroutine_handle> h); constexpr void await_resume() {} private: - std::string name; struct StateStore { std::mutex lock; + std::string name; + std::source_location location; bool data; }; std::shared_ptr flag; friend class ThreadPool; }; -extern std::atomic_uint64_t globalCounter; template struct JobBase; template @@ -70,8 +84,7 @@ struct JobPromiseBase JobPromiseBase(const std::source_location& location = std::source_location::current()) { handle = std::coroutine_handle>::from_promise(*this); - id = globalCounter++; - finishedEvent = Event(std::string(location.file_name()).append(": ").append(location.function_name())); + finishedEvent = Event(location); } ~JobPromiseBase() {} @@ -81,9 +94,10 @@ struct JobPromiseBase inline auto final_suspend() noexcept; void return_void() noexcept {} - void unhandled_exception() noexcept { - std::cerr << "Unhandled exception! Exiting" << std::endl; - exit(1); + void unhandled_exception() { + std::exception_ptr exception = std::current_exception(); + std::cerr << "Unhandled exception!" << std::endl; + throw exception; }; void resume() @@ -165,16 +179,22 @@ struct JobPromiseBase } void removeRef() { - if(--numRefs < 1 && done()) + if(--numRefs < 1) { - handle.destroy(); - } + if(done()) + { + handle.destroy(); + } + else + { + schedule(); + } + } } std::mutex promiseLock; std::coroutine_handle handle; JobPromiseBase* continuation = nullptr; - uint64 id; std::atomic_uint64_t numRefs = 0; Event finishedEvent; State state = State::READY; @@ -210,7 +230,7 @@ public: { if(promise) { - promise->schedule(); + //promise->schedule(); promise->removeRef(); } } @@ -253,19 +273,25 @@ public: { return promise->done(); } - void finalize() - { - promise->finalize(); - } Event operator co_await() const { - // the co_await operator keeps a reference to this, we it won't + // the co_await operator keeps a reference to this, it won't // be scheduled from the destructor promise->schedule(); return promise->finishedEvent; } static JobBase all() = delete; - template + template + requires std::same_as, JobBase> + static JobBase all(Iterable collection) + { + getGlobalThreadPool().scheduleBatch(collection); + for(auto it : collection) + { + co_await it; + } + } + template static JobBase all(Iterable collection) { for(auto it : collection) @@ -278,14 +304,17 @@ public: { return JobBase::all(Array{jobs...}); } - template - static JobBase launchJobs(JobFunc&& func, IterableParams params) + template + requires std::invocable> + static JobBase launchJobs(JobFunc&& func, Iterable params) { - List jobs; + Array jobs; for(auto&& param : params) { - jobs.add(func(param)); + JobBase base = func(param); + jobs.add(base); } + getGlobalThreadPool().scheduleBatch(jobs); for(auto job : jobs) { co_await job; @@ -293,6 +322,7 @@ public: } private: JobPromiseBase* promise; + friend class ThreadPool; }; using MainJob = JobBase; @@ -305,32 +335,64 @@ class ThreadPool public: ThreadPool(uint32 threadCount = std::thread::hardware_concurrency()); virtual ~ThreadPool(); - void cleanup(); + void waitIdle(); // Adds a job to the waiting queue for event void enqueueWaiting(Event& event, Promise* job); // Adds a job to the waiting queue for event void enqueueWaiting(Event& event, MainPromise* job); void scheduleJob(Promise* job); void scheduleJob(MainPromise* job); + template + requires std::same_as, MainJob> + void scheduleBatch(Iterable jobs) + { + std::scoped_lock lock(mainJobLock); + for(auto job : jobs) + { + job.promise->addRef(); + job.promise->state = JobPromiseBase::State::SCHEDULED; + mainJobs.add(job.promise); + } + mainJobCV.notify_one(); + } + template + requires std::same_as, Job> + void scheduleBatch(Iterable jobs) + { + std::scoped_lock lock(jobQueueLock); + for(auto job : jobs) + { + job.promise->addRef(); + job.promise->state = JobPromiseBase::State::SCHEDULED; + jobQueue.add(job.promise); + } + jobQueueCV.notify_all(); + } void notify(Event& event); - void threadLoop(const bool isMainThread); + void mainLoop(); + void threadLoop(); private: std::atomic_bool running; - std::vector workers; + std::mutex numIdlingLock; + std::condition_variable numIdlingIncr; + uint32 numIdling; + Array workers; - std::list mainJobs; + List mainJobs; std::mutex mainJobLock; std::condition_variable mainJobCV; - std::list jobQueue; + List jobQueue; std::mutex jobQueueLock; std::condition_variable jobQueueCV; - std::map> waitingMainJobs; + Map> waitingMainJobs; std::mutex waitingMainLock; - std::map> waitingJobs; + Map> waitingJobs; std::mutex waitingLock; + + uint32 maxLocalQueueSize = 50; }; template @@ -349,18 +411,6 @@ inline auto JobPromiseBase::initial_suspend() noexcept template inline auto JobPromiseBase::final_suspend() noexcept { - /*struct JobAwaitable - { - constexpr bool await_ready() const noexcept { return false; } - constexpr auto await_suspend(std::coroutine_handle> h) const noexcept - { - auto continuation = h.promise().continuation; - h.destroy(); - - } - constexpr void await_resume() const noexcept {} - }; - return JobAwaitable{};*/ markDone(); return std::suspend_always{}; } diff --git a/src/Engine/Window/SceneView.cpp b/src/Engine/Window/SceneView.cpp index dce72ce..3026efd 100644 --- a/src/Engine/Window/SceneView.cpp +++ b/src/Engine/Window/SceneView.cpp @@ -32,15 +32,15 @@ Seele::SceneView::SceneView(Gfx::PGraphics graphics, PWindow owner, const Viewpo AssetRegistry::importFile("C:\\Users\\Dynamitos\\TestSeeleProject\\Assets\\Plane\\plane.fbx"); PPrimitiveComponent ayaka = new PrimitiveComponent(AssetRegistry::findMesh("Ayaka")); - ayaka->addWorldTranslation(Vector(0, 0, 0)); - ayaka->setWorldScale(Vector(10, 10, 10)); + ayaka->setRelativeLocation(Vector(0, 0, 0)); + ayaka->setRelativeScale(Vector(10, 10, 10)); //scene->addPrimitiveComponent(ayaka); PPrimitiveComponent plane = new PrimitiveComponent(AssetRegistry::findMesh("plane")); - plane->setWorldScale(Vector(100, 100, 100)); + plane->setRelativeScale(Vector(100, 100, 100)); scene->addPrimitiveComponent(plane); - for(uint32 i = 0; i < 1; ++i) + for(uint32 i = 0; i < 100000; ++i) { PMyComponent myComp = new MyComponent(); PMyOtherComponent myOtherComp = new MyOtherComponent(); @@ -97,32 +97,46 @@ void SceneView::prepareRender() MainJob SceneView::render() { - return MainJob::all( - depthPrepass.beginFrame(), - lightCullingPass.beginFrame(), - basePass.beginFrame()) + return depthPrepass.beginFrame() + .then(lightCullingPass.beginFrame()) + .then(basePass.beginFrame()) .then(depthPrepass.render()) .then(lightCullingPass.render()) .then(basePass.render()) - .then( - MainJob::all( - depthPrepass.endFrame(), - lightCullingPass.endFrame(), - basePass.endFrame()) - ); + .then(depthPrepass.endFrame()) + .then(lightCullingPass.endFrame()) + .then(basePass.endFrame()); } -void SceneView::keyCallback(KeyCode code, InputAction action, KeyModifier) +static float cameraSpeed = 1; + +void SceneView::keyCallback(KeyCode code, InputAction action, KeyModifier mod) { + if((KeyModifierFlags)mod & (KeyModifierFlags)KeyModifier::MOD_SHIFT) + { + cameraSpeed = 5; + } + else + { + cameraSpeed = 1; + } if(action != InputAction::RELEASE) { if(code == KeyCode::KEY_W) { - activeCamera->getCameraComponent()->moveOrigin(1); + activeCamera->getCameraComponent()->moveX(1); } if(code == KeyCode::KEY_S) { - activeCamera->getCameraComponent()->moveOrigin(-1); + activeCamera->getCameraComponent()->moveX(-1); + } + if(code == KeyCode::KEY_A) + { + activeCamera->getCameraComponent()->moveY(1); + } + if(code == KeyCode::KEY_D) + { + activeCamera->getCameraComponent()->moveY(-1); } } } @@ -144,7 +158,7 @@ void SceneView::mouseMoveCallback(double xPos, double yPos) void SceneView::mouseButtonCallback(MouseButton button, InputAction action, KeyModifier) { - if(button == MouseButton::MOUSE_BUTTON_1 && action != InputAction::RELEASE) + if(button == MouseButton::MOUSE_BUTTON_2 && action != InputAction::RELEASE) { mouseDown = true; } diff --git a/src/Engine/Window/Window.cpp b/src/Engine/Window/Window.cpp index 49775ef..4f54a68 100644 --- a/src/Engine/Window/Window.cpp +++ b/src/Engine/Window/Window.cpp @@ -27,16 +27,14 @@ void Window::addView(PView view) MainJob Window::render() { gfxHandle->beginFrame(); - Array jobs; for(auto& windowView : views) { { std::scoped_lock lock(windowView->workerMutex); windowView->view->prepareRender(); } - jobs.add(windowView->view->render()); + co_await windowView->view->render(); } - co_await MainJob::all(jobs); gfxHandle->endFrame(); if(owner->isActive()) { diff --git a/src/Engine/Window/WindowManager.cpp b/src/Engine/Window/WindowManager.cpp index 762184f..ba50548 100644 --- a/src/Engine/Window/WindowManager.cpp +++ b/src/Engine/Window/WindowManager.cpp @@ -41,6 +41,6 @@ void WindowManager::notifyWindowClosed(PWindow window) windows.remove(windows.find(window)); if(windows.empty()) { - getGlobalThreadPool().cleanup(); + exit(0); } } diff --git a/src/Engine/main.cpp b/src/Engine/main.cpp index 87a4b3f..4c29747 100644 --- a/src/Engine/main.cpp +++ b/src/Engine/main.cpp @@ -34,9 +34,9 @@ int main() //PInspectorView inspectorView = new InspectorView(windowManager->getGraphics(), window, inspectorViewInfo); //window->addView(inspectorView); sceneView->setFocused(); - + window->render(); - getGlobalThreadPool().threadLoop(true); + getGlobalThreadPool().mainLoop(); return 0; } \ No newline at end of file diff --git a/test/Engine/EngineTest.h b/test/Engine/EngineTest.h index 5054fa9..e2b46c5 100644 --- a/test/Engine/EngineTest.h +++ b/test/Engine/EngineTest.h @@ -1,5 +1,5 @@ #pragma once -//#include +#include #include "ThreadPool.h" namespace Seele @@ -12,7 +12,7 @@ namespace Seele } ~GlobalFixture() { - getGlobalThreadPool().cleanup(); + getGlobalThreadPool().waitIdle(); } void setup() { diff --git a/test/Engine/ThreadPool.cpp b/test/Engine/ThreadPool.cpp index e3c9d7b..e3b1416 100644 --- a/test/Engine/ThreadPool.cpp +++ b/test/Engine/ThreadPool.cpp @@ -1,6 +1,9 @@ #include "EngineTest.h" #include "ThreadPool.h" #include +#include + +using namespace std::chrono_literals; BOOST_AUTO_TEST_SUITE(ThreadPool) @@ -9,18 +12,21 @@ uint64 basicAwaitState = 0; Job basicAwaitFirst() { BOOST_REQUIRE_EQUAL(basicAwaitState, 5); + std::this_thread::sleep_for(500ms); basicAwaitState = 10; co_return; } Job basicAwaitSecond() { BOOST_REQUIRE_EQUAL(basicAwaitState, 15); + std::this_thread::sleep_for(500ms); basicAwaitState = 20; co_return; } Job basicAwaitThird() { BOOST_REQUIRE_EQUAL(basicAwaitState, 25); + std::this_thread::sleep_for(500ms); basicAwaitState = 30; co_return; } @@ -48,18 +54,21 @@ uint64 basicThenState = 5; Job basicThenFirst() { BOOST_REQUIRE_EQUAL(basicThenState, 5); + std::this_thread::sleep_for(500ms); basicThenState = 10; co_return; } Job basicThenSecond() { BOOST_REQUIRE_EQUAL(basicThenState, 15); + std::this_thread::sleep_for(500ms); basicThenState = 20; co_return; } Job basicThenThird() { BOOST_REQUIRE_EQUAL(basicThenState, 25); + std::this_thread::sleep_for(500ms); basicThenState = 30; co_return; } @@ -70,6 +79,7 @@ BOOST_AUTO_TEST_CASE(basic_thenchain) .then([]() -> Job { BOOST_REQUIRE_EQUAL(basicThenState, 10); + std::this_thread::sleep_for(500ms); basicThenState = 15; co_return; }) @@ -77,6 +87,7 @@ BOOST_AUTO_TEST_CASE(basic_thenchain) .then([]() -> Job { BOOST_REQUIRE_EQUAL(basicThenState, 20); + std::this_thread::sleep_for(500ms); basicThenState = 25; co_return; }) @@ -92,11 +103,13 @@ uint64 basicAllState1 = 0; uint64 basicAllState2 = 0; Job basicAllFirst() { + std::this_thread::sleep_for(500ms); basicAllState1 = 10; co_return; } Job basicAllSecond() { + std::this_thread::sleep_for(500ms); basicAllState2 = 10; co_return; } @@ -112,10 +125,41 @@ BOOST_AUTO_TEST_CASE(basic_all) Job::all(basicAllFirst(), basicAllSecond()).then(basicAllThen()); } +uint64 allThenState = 0; + +Job allThenInitial() +{ + std::this_thread::sleep_for(500ms); + allThenState = 10; + co_return; +} + +Job allThenIntermediate() +{ + std::this_thread::sleep_for(500ms); + BOOST_REQUIRE_EQUAL(allThenState, 10); + allThenState = 20; + co_return; +} + +Job allThenFinal() +{ + BOOST_REQUIRE_EQUAL(allThenState, 20); + co_return; +} + +BOOST_AUTO_TEST_CASE(all_then_interaction) +{ + Job::all(allThenInitial()) + .then(allThenIntermediate()) + .then(Job::all(allThenFinal())); +} + uint64 basicCallable = 0; Job basicCallableFunc() { + std::this_thread::sleep_for(500ms); basicCallable = 10; co_return; } @@ -130,4 +174,44 @@ BOOST_AUTO_TEST_CASE(basic_callable) }); } +struct Payload +{ + StaticArray data; + uint64 result = 0; +}; + +Job worker(Payload& payload) +{ + for(uint32 i = 0; i < 100000; ++i) + { + payload.result = std::accumulate(payload.data.begin(), payload.data.end(), (uint64)1, std::multiplies()); + } + co_return; +} + +Job launchStressTest() +{ + Array payloads(100); + Array jobs; + for(auto& payload : payloads) + { + for(uint64 i = 0; i < payload.data.size(); ++i) + { + payload.data[i] = i; + } + } + auto startTime = std::chrono::high_resolution_clock::now(); + std::cout << "Starting up" << std::endl; + co_await Job::launchJobs(&worker, payloads); + std::cout << "Finished waiting" << std::endl; + auto endTime = std::chrono::high_resolution_clock::now(); + float delta = std::chrono::duration_cast(endTime - startTime).count(); + std::cout << "Update took " << delta << " seconds"; +} + +BOOST_AUTO_TEST_CASE(stress_test) +{ + //launchStressTest(); +} + BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file