Somewhat working camera

This commit is contained in:
Dynamitos
2022-03-19 22:45:30 +01:00
parent 84049a762c
commit cd28e433cc
41 changed files with 602 additions and 496 deletions
+2
View File
@@ -55,6 +55,7 @@
"environment": [], "environment": [],
"symbolSearchPath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.25.28610\\lib\\x64", "symbolSearchPath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.25.28610\\lib\\x64",
"requireExactSource": false, "requireExactSource": false,
"visualizerFile": "${workspaceRoot}/Seele.natvis",
"logging": { "logging": {
"moduleLoad": false, "moduleLoad": false,
"exceptions": true, "exceptions": true,
@@ -82,6 +83,7 @@
"stopAtEntry": false, "stopAtEntry": false,
"console": "internalConsole", "console": "internalConsole",
"cwd": "${workspaceRoot}/bin/Debug", "cwd": "${workspaceRoot}/bin/Debug",
"visualizerFile": "${workspaceRoot}/Seele.natvis",
"environment": [], "environment": [],
}, },
] ]
+1 -1
View File
@@ -31,7 +31,7 @@
</Expand> </Expand>
</Type> </Type>
<Type Name="Seele::Map&lt;*&gt;"> <Type Name="Seele::Map&lt;*&gt;">
<DisplayString>{{size={_size}}</DisplayString> <DisplayString>{{ size={_size} }</DisplayString>
<Expand> <Expand>
<Item Name="[size]">_size</Item> <Item Name="[size]">_size</Item>
<Item Name="[comp]">comp</Item> <Item Name="[comp]">comp</Item>
+1 -1
+8 -8
View File
@@ -28,10 +28,10 @@ void computeFrustums(ComputeShaderInput in)
float4 screenSpace[4]; float4 screenSpace[4];
screenSpace[0] = float4(in.dispatchThreadID.xy * 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[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[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[3] = float4(float2(in.dispatchThreadID.x + 1, in.dispatchThreadID.y + 1) * BLOCK_SIZE, -1.0f, 1.0f);
//Convert to viewSpace //Convert to viewSpace
float3 viewSpace[4]; float3 viewSpace[4];
@@ -44,10 +44,10 @@ void computeFrustums(ComputeShaderInput in)
//Compute frustum //Compute frustum
Frustum frustum; Frustum frustum;
frustum.planes[0] = computePlane(eyePos, viewSpace[0], viewSpace[2]); frustum.planes[0] = computePlane(eyePos, viewSpace[2], viewSpace[0]);
frustum.planes[1] = computePlane(eyePos, viewSpace[3], viewSpace[1]); frustum.planes[1] = computePlane(eyePos, viewSpace[1], viewSpace[3]);
frustum.planes[2] = computePlane(eyePos, viewSpace[1], viewSpace[0]); frustum.planes[2] = computePlane(eyePos, viewSpace[0], viewSpace[1]);
frustum.planes[3] = computePlane(eyePos, viewSpace[2], viewSpace[3]); frustum.planes[3] = computePlane(eyePos, viewSpace[3], viewSpace[2]);
if(in.dispatchThreadID.x < numThreads.x && in.dispatchThreadID.y < numThreads.y) if(in.dispatchThreadID.x < numThreads.x && in.dispatchThreadID.y < numThreads.y)
{ {
+7 -6
View File
@@ -32,9 +32,9 @@ VertexStageOutput vertexMain(
float4 clipSpacePosition; float4 clipSpacePosition;
float3x3 tangentToLocal = cache.getTangentToLocal(); float3x3 tangentToLocal = cache.getTangentToLocal();
MaterialVertexParameter vertexParams = input.getMaterialVertexParameters(cache, worldPosition, tangentToLocal);
float4 viewSpacePosition = mul(gViewParams.viewMatrix, float4(worldPosition, 1)); float4 viewSpacePosition = mul(gViewParams.viewMatrix, float4(worldPosition, 1));
MaterialVertexParameter vertexParams = input.getMaterialVertexParameters(cache, worldPosition, viewSpacePosition.xyz, tangentToLocal);
clipSpacePosition = mul(gViewParams.projectionMatrix, viewSpacePosition); clipSpacePosition = mul(gViewParams.projectionMatrix, viewSpacePosition);
output.position = clipSpacePosition; output.position = clipSpacePosition;
output.shaderAttributeInterpolation = input.getInterpolants(cache, vertexParams); output.shaderAttributeInterpolation = input.getInterpolants(cache, vertexParams);
@@ -66,12 +66,13 @@ float4 fragmentMain(
uint startOffset = gridValue.x; uint startOffset = gridValue.x;
uint lightCount = gridValue.y; uint lightCount = gridValue.y;
for (int j = 0; j < lightCount; ++j) for (int j = 0; j < numPointLights; ++j)
{ {
uint lightIndex = lightIndexList[startOffset + j]; //uint lightIndex = lightIndexList[startOffset + j];
PointLight pointLight = pointLights[lightIndex]; PointLight pointLight = pointLights[j];
if(pointLight.colorRange.w < length(pointLight.getViewPos() - input.viewPosition)) continue;
result += pointLight.illuminate(materialParams, brdf, viewDir); result += pointLight.illuminate(materialParams, brdf, viewDir);
} }
return float4(result, 0.1f); return float4(result, 1.0f);
} }
+30 -30
View File
@@ -4,18 +4,18 @@ import Common;
interface ILightEnv interface ILightEnv
{ {
float3 illuminate<B:IBRDF>(MaterialFragmentParameter input, B brdf, float3 wo); float3 illuminate<B:IBRDF>(MaterialFragmentParameter input, B brdf, float3 wo);
}; };
struct DirectionalLight : ILightEnv struct DirectionalLight : ILightEnv
{ {
float4 color; float4 color;
float4 direction; float4 direction;
float4 intensity; float4 intensity;
float3 illuminate<B:IBRDF>(MaterialFragmentParameter input, B brdf, float3 wo) float3 illuminate<B:IBRDF>(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; float4 colorRange;
float3 illuminate<B:IBRDF>(MaterialFragmentParameter input, B brdf, float3 viewDir) float3 illuminate<B:IBRDF>(MaterialFragmentParameter input, B brdf, float3 viewDir)
{ {
float3 lightVec = positionWS.xyz - input.worldPosition; float3 lightVec = positionWS.xyz - input.worldPosition;
float d = length(lightVec); float d = length(lightVec);
float3 direction = normalize(lightVec); float3 direction = normalize(lightVec);
float illuminance = max(1 - d / colorRange.w, 0); 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; 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; bool result = true;
if(getViewPos().z - colorRange.w > zNear || getViewPos().z + colorRange.w < zFar) if(getViewPos().z - colorRange.w > zNear || getViewPos().z + colorRange.w < zFar)
{ {
result = false; //result = false;
} }
for(int i = 0; i < 4 && result; ++i) for(int i = 0; i < 4 && result; ++i)
{ {
if(insidePlane(frustum.planes[i])) if(insidePlane(frustum.planes[i]))
{ {
result = false; //result = false;
} }
} }
return result; return result;
} }
float3 getViewPos() float3 getViewPos()
{ {
return mul(gViewParams.viewMatrix, positionWS).xyz; return mul(gViewParams.viewMatrix, positionWS).xyz;
} }
}; };
layout(set = INDEX_LIGHT_ENV, binding = 0, std430) layout(set = INDEX_LIGHT_ENV, binding = 0, std430)
+1
View File
@@ -1,6 +1,7 @@
struct MaterialVertexParameter struct MaterialVertexParameter
{ {
float3 worldPosition; float3 worldPosition;
float3 viewPosition;
float3x3 tangentToWorld; float3x3 tangentToWorld;
#if NUM_MATERIAL_TEXCOORDS #if NUM_MATERIAL_TEXCOORDS
float2 texCoords[NUM_MATERIAL_TEXCOORDS]; float2 texCoords[NUM_MATERIAL_TEXCOORDS];
+4 -1
View File
@@ -45,6 +45,7 @@ struct VertexValueCache
struct ShaderAttributeInterpolation struct ShaderAttributeInterpolation
{ {
float3 worldPosition; float3 worldPosition;
float3 viewPosition;
float3 normal; float3 normal;
float3 tangent; float3 tangent;
float3 biTangent; float3 biTangent;
@@ -158,10 +159,11 @@ struct VertexShaderInput
return cache; return cache;
} }
MaterialVertexParameter getMaterialVertexParameters(VertexValueCache cache, float3 worldPosition, float3x3 tangentToLocal) MaterialVertexParameter getMaterialVertexParameters(VertexValueCache cache, float3 worldPosition, float3 viewPosition, float3x3 tangentToLocal)
{ {
MaterialVertexParameter result; MaterialVertexParameter result;
result.worldPosition = worldPosition; result.worldPosition = worldPosition;
result.viewPosition = viewPosition;
result.vertexColor = cache.color; result.vertexColor = cache.color;
result.tangentToWorld = cache.getTangentToWorld(); result.tangentToWorld = cache.getTangentToWorld();
// TODO instancing // TODO instancing
@@ -186,6 +188,7 @@ struct VertexShaderInput
result.biTangent = mul(gSceneData.localToWorld, float4(biTangent, 0.0f)).xyz; result.biTangent = mul(gSceneData.localToWorld, float4(biTangent, 0.0f)).xyz;
result.color = color; result.color = color;
result.worldPosition = vertexParams.worldPosition; result.worldPosition = vertexParams.worldPosition;
result.viewPosition = vertexParams.viewPosition;
for(int i = 0; i < NUM_MATERIAL_TEXCOORDS; ++i) for(int i = 0; i < NUM_MATERIAL_TEXCOORDS; ++i)
{ {
if(i % 2) if(i % 2)
+2 -1
View File
@@ -27,7 +27,8 @@ void AssetRegistry::importFile(const std::string &filePath)
std::filesystem::path fsPath = std::filesystem::path(filePath); std::filesystem::path fsPath = std::filesystem::path(filePath);
std::string extension = fsPath.extension().string(); std::string extension = fsPath.extension().string();
if (extension.compare(".fbx") == 0 if (extension.compare(".fbx") == 0
|| extension.compare(".obj") == 0) || extension.compare(".obj") == 0
|| extension.compare(".blend") == 0)
{ {
get().importMesh(fsPath); get().importMesh(fsPath);
} }
-5
View File
@@ -3,11 +3,6 @@
namespace Seele namespace Seele
{ {
template<typename A>
concept iterable = requires(A&& a)
{
a.begin(); a.end();
};
template<class F, class... Args> template<class F, class... Args>
concept invocable = std::invocable<F, Args...>; concept invocable = std::invocable<F, Args...>;
} }
+1 -1
View File
@@ -148,7 +148,7 @@ enum class InputAction
REPEAT = 2 REPEAT = 2
}; };
enum class KeyModifier enum class KeyModifier : uint32
{ {
MOD_SHIFT = 0x0001, MOD_SHIFT = 0x0001,
MOD_CONTROL = 0x0002, MOD_CONTROL = 0x0002,
+1 -1
View File
@@ -20,7 +20,7 @@ BasePassMeshProcessor::~BasePassMeshProcessor()
{ {
} }
Job BasePassMeshProcessor::processMeshBatch( MainJob BasePassMeshProcessor::processMeshBatch(
const MeshBatch& batch, const MeshBatch& batch,
// const PPrimitiveComponent primitiveComponent, // const PPrimitiveComponent primitiveComponent,
const Gfx::PRenderPass& renderPass, const Gfx::PRenderPass& renderPass,
+1 -1
View File
@@ -11,7 +11,7 @@ public:
BasePassMeshProcessor(Gfx::PViewport viewport, Gfx::PGraphics graphics, uint8 translucentBasePass); BasePassMeshProcessor(Gfx::PViewport viewport, Gfx::PGraphics graphics, uint8 translucentBasePass);
virtual ~BasePassMeshProcessor(); virtual ~BasePassMeshProcessor();
virtual Job processMeshBatch( virtual MainJob processMeshBatch(
const MeshBatch& batch, const MeshBatch& batch,
// const PPrimitiveComponent primitiveComponent, // const PPrimitiveComponent primitiveComponent,
const Gfx::PRenderPass& renderPass, const Gfx::PRenderPass& renderPass,
@@ -18,7 +18,7 @@ DepthPrepassMeshProcessor::~DepthPrepassMeshProcessor()
{ {
} }
Job DepthPrepassMeshProcessor::processMeshBatch( MainJob DepthPrepassMeshProcessor::processMeshBatch(
const MeshBatch& batch, const MeshBatch& batch,
// const PPrimitiveComponent primitiveComponent, // const PPrimitiveComponent primitiveComponent,
const Gfx::PRenderPass& renderPass, const Gfx::PRenderPass& renderPass,
@@ -11,7 +11,7 @@ public:
DepthPrepassMeshProcessor(Gfx::PViewport viewport, Gfx::PGraphics graphics); DepthPrepassMeshProcessor(Gfx::PViewport viewport, Gfx::PGraphics graphics);
virtual ~DepthPrepassMeshProcessor(); virtual ~DepthPrepassMeshProcessor();
virtual Job processMeshBatch( virtual MainJob processMeshBatch(
const MeshBatch& batch, const MeshBatch& batch,
const Gfx::PRenderPass& renderPass, const Gfx::PRenderPass& renderPass,
Gfx::PPipelineLayout pipelineLayout, Gfx::PPipelineLayout pipelineLayout,
@@ -98,7 +98,7 @@ MainJob LightCullingPass::render()
computeCommand->bindPipeline(cullingPipeline); computeCommand->bindPipeline(cullingPipeline);
Array<Gfx::PDescriptorSet> descriptorSets = {cullingDescriptorSet, lightEnvDescriptorSet}; Array<Gfx::PDescriptorSet> descriptorSets = {cullingDescriptorSet, lightEnvDescriptorSet};
computeCommand->bindDescriptor(descriptorSets); 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<Gfx::PComputeCommand> commands = {computeCommand}; Array<Gfx::PComputeCommand> commands = {computeCommand};
graphics->executeCommands(commands); graphics->executeCommands(commands);
depthAttachment->changeLayout(Gfx::SE_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); depthAttachment->changeLayout(Gfx::SE_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
@@ -17,7 +17,7 @@ public:
protected: protected:
PScene scene; PScene scene;
Gfx::PGraphics graphics; Gfx::PGraphics graphics;
virtual Job processMeshBatch( virtual MainJob processMeshBatch(
const MeshBatch& batch, const MeshBatch& batch,
// const PPrimitiveComponent primitiveComponent, // const PPrimitiveComponent primitiveComponent,
const Gfx::PRenderPass& renderPass, const Gfx::PRenderPass& renderPass,
@@ -81,7 +81,7 @@ void CmdBuffer::executeCommands(const Array<Gfx::PRenderCommand>& commands)
assert(state == State::RenderPassActive); assert(state == State::RenderPassActive);
if(commands.size() == 0) if(commands.size() == 0)
{ {
std::cout << "No commands provided" << std::endl; //std::cout << "No commands provided" << std::endl;
return; return;
} }
std::scoped_lock lock(handleLock); std::scoped_lock lock(handleLock);
+1 -2
View File
@@ -106,11 +106,10 @@ void MaterialAsset::load()
std::string defaultString = defaultValue.value().get<std::string>(); std::string defaultString = defaultValue.value().get<std::string>();
p->data = AssetRegistry::findTexture(defaultString); p->data = AssetRegistry::findTexture(defaultString);
} }
else if(p->data == nullptr)
{ {
p->data = AssetRegistry::findTexture(""); // this will return placeholder texture p->data = AssetRegistry::findTexture(""); // this will return placeholder texture
} }
assert(p->data != nullptr);
parameters.add(p); parameters.add(p);
} }
else if(type.compare("SamplerState") == 0) else if(type.compare("SamplerState") == 0)
+31 -4
View File
@@ -4,7 +4,7 @@
using namespace Seele; using namespace Seele;
Transform::Transform() 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) : position(other.position), rotation(other.rotation), scale(other.scale)
{ {
other.position = Vector4(0, 0, 0, 0); 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); other.scale = Vector4(0, 0, 0, 0);
} }
@@ -22,7 +22,7 @@ Transform::Transform(const Transform &other)
} }
Transform::Transform(Vector position) 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) Transform::Transform(Vector position, Quaternion rotation)
@@ -144,6 +144,19 @@ Vector Transform::getScale() const
return Vector(scale); 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) bool Transform::equals(const Transform &other, float tolerance)
{ {
if (abs(position - other.position).length() > 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->position = b->rotation * (b->scale * a->position) + b->position;
outTransform->scale = b->scale * a->scale; 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) Transform &Transform::operator=(const Transform &other)
{ {
@@ -189,11 +209,18 @@ Transform &Transform::operator=(Transform &&other)
rotation = other.rotation; rotation = other.rotation;
scale = other.scale; scale = other.scale;
other.position = Vector4(0, 0, 0, 0); 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); other.scale = Vector4(0, 0, 0, 0);
return *this; 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 Transform::operator*(const Transform &other) const
{ {
Transform outTransform; Transform outTransform;
+5
View File
@@ -23,12 +23,17 @@ public:
Vector getPosition() const; Vector getPosition() const;
Quaternion getRotation() const; Quaternion getRotation() const;
Vector getScale() const; Vector getScale() const;
Vector getForward() const;
Vector getRight() const;
Vector getUp() const;
bool equals(const Transform &other, float tolerance = 0.000000001f); bool equals(const Transform &other, float tolerance = 0.000000001f);
static void multiply(Transform *outTransform, const Transform *a, const Transform *b); 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=(const Transform &other);
Transform &operator=(Transform &&other); Transform &operator=(Transform &&other);
Transform operator+(const Transform& other) const;
Transform operator*(const Transform &other) const; Transform operator*(const Transform &other) const;
private: private:
-24
View File
@@ -64,30 +64,6 @@ static inline float normalizeRotatorAxis(float angle)
return angle; return angle;
} }
static inline Quaternion toQuaternion(const Vector &other)
{
Quaternion result;
const float DEG_TO_RAD = glm::pi<float>() / (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) static inline Vector toRotator(const Quaternion &other)
{ {
+35 -23
View File
@@ -74,23 +74,23 @@ void Actor::detachChild(PActor child)
child->setParent(nullptr); child->setParent(nullptr);
child->notifySceneAttach(nullptr); child->notifySceneAttach(nullptr);
} }
void Actor::setWorldLocation(Vector location) //void Actor::setAbsoluteLocation(Vector location)
{ //{
rootComponent->setWorldLocation(location); // rootComponent->setWorldLocation(location);
} //}
//
void Actor::setWorldRotation(Quaternion rotation) //void Actor::setAbsoluteRotation(Quaternion rotation)
{ //{
rootComponent->setWorldRotation(rotation); // rootComponent->setAbsoluteRotation(rotation);
} //}
void Actor::setWorldRotation(Vector rotation) //void Actor::setAbsoluteRotation(Vector rotation)
{ //{
rootComponent->setWorldRotation(rotation); // rootComponent->setAbsoluteRotation(rotation);
} //}
void Actor::setWorldScale(Vector scale) //void Actor::setWorldScale(Vector scale)
{ //{
rootComponent->setWorldScale(scale); // rootComponent->setWorldScale(scale);
} //}
void Actor::setRelativeLocation(Vector location) void Actor::setRelativeLocation(Vector location)
{ {
rootComponent->setRelativeLocation(location); rootComponent->setRelativeLocation(location);
@@ -107,17 +107,29 @@ void Actor::setRelativeScale(Vector scale)
{ {
rootComponent->setRelativeScale(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() PComponent Actor::getRootComponent()
{ {
+11 -7
View File
@@ -26,19 +26,23 @@ public:
void addChild(PActor child); void addChild(PActor child);
void detachChild(PActor child); void detachChild(PActor child);
Array<PActor> getChildren(); Array<PActor> getChildren();
void setWorldLocation(Vector location); //void setAbsoluteLocation(Vector location);
void setWorldRotation(Quaternion rotation); //void setAbsoluteRotation(Quaternion rotation);
void setWorldRotation(Vector rotation); //void setAbsoluteRotation(Vector rotation);
void setWorldScale(Vector scale); //void setWorldScale(Vector scale);
void setRelativeLocation(Vector location); void setRelativeLocation(Vector location);
void setRelativeRotation(Quaternion rotation); void setRelativeRotation(Quaternion rotation);
void setRelativeRotation(Vector rotation); void setRelativeRotation(Vector rotation);
void setRelativeScale(Vector scale); void setRelativeScale(Vector scale);
void addWorldTranslation(Vector translation); //void addAbsoluteTranslation(Vector translation);
void addWorldRotation(Quaternion rotation); //void addAbsoluteRotation(Quaternion rotation);
void addWorldRotation(Vector rotation); //void addAbsoluteRotation(Vector rotation);
void addRelativeLocation(Vector translation);
void addRelativeRotation(Quaternion rotation);
void addRelativeRotation(Vector rotation);
PComponent getRootComponent(); PComponent getRootComponent();
void setRootComponent(PComponent newRoot); void setRootComponent(PComponent newRoot);
-2
View File
@@ -14,8 +14,6 @@ CameraActor::CameraActor()
cameraComponent->aspectRatio = 1.777778f; cameraComponent->aspectRatio = 1.777778f;
cameraComponent->setParent(sceneComponent); cameraComponent->setParent(sceneComponent);
cameraComponent->setOwner(this); cameraComponent->setOwner(this);
addWorldTranslation(Vector(0, 0, 50));
addWorldRotation(Vector(0, -100, 0));
} }
CameraActor::~CameraActor() CameraActor::~CameraActor()
+36 -41
View File
@@ -6,19 +6,16 @@
using namespace Seele; using namespace Seele;
CameraComponent::CameraComponent() CameraComponent::CameraComponent()
: aspectRatio(0) : aspectRatio(0)
, fieldOfView(0) , fieldOfView(0)
, bNeedsViewBuild(true) , bNeedsViewBuild(true)
, bNeedsProjectionBuild(true) , bNeedsProjectionBuild(true)
, originPoint(0, 0, 0) , projectionMatrix(Matrix4())
, cameraPosition(0, 0, 50) , viewMatrix(Matrix4())
, eye(Vector())
, projectionMatrix(Matrix4())
, viewMatrix(Matrix4())
{ {
distance = 50;
rotationX = 0; rotationX = 0;
rotationY = -1.f; rotationY = 0;
setRelativeLocation(Vector(0, 10, -50));
} }
CameraComponent::~CameraComponent() CameraComponent::~CameraComponent()
@@ -27,54 +24,52 @@ CameraComponent::~CameraComponent()
void CameraComponent::mouseMove(float deltaX, float deltaY) void CameraComponent::mouseMove(float deltaX, float deltaY)
{ {
//0.01 mouse sensitivity rotationX -= deltaX / 1000.f;
rotationX += deltaX/500.f; rotationY += deltaY / 1000.f;
rotationY += deltaY/500.f; //std::cout << "X:" << rotationX << " Y: " << rotationY << std::endl;
rotationY = std::clamp(rotationY, -1.5f, 1.5f); setRelativeRotation(Vector(rotationY, rotationX, 0));
getParent()->setWorldRotation(glm::rotate(glm::quat(), rotationX, Vector(0, 1, 0))); bNeedsViewBuild = true;
getParent()->setWorldRotation(glm::rotate(glm::quat(), rotationY, Vector(1, 0, 0)));
bNeedsViewBuild = true;
} }
void CameraComponent::mouseScroll(double x) void CameraComponent::mouseScroll(float x)
{ {
distance -= static_cast<float>(x); addRelativeLocation(getTransform().getForward()*x);
distance = std::max(distance, 1.f); bNeedsViewBuild = true;
getParent()->addWorldTranslation(Vector(0, 0, x));
bNeedsViewBuild = true;
} }
void CameraComponent::moveOrigin(float up) void CameraComponent::moveX(float amount)
{ {
originPoint.y += up; addRelativeLocation(getTransform().getForward()*amount);
getParent()->addWorldTranslation(Vector(0, up, 0)); bNeedsViewBuild = true;
bNeedsViewBuild = true; }
void CameraComponent::moveY(float amount)
{
addRelativeLocation(getTransform().getRight()*amount);
bNeedsViewBuild = true;
} }
void CameraComponent::buildViewMatrix() void CameraComponent::buildViewMatrix()
{ {
Matrix4 rotation = glm::rotate(Matrix4(1.0f), rotationX, Vector(0, 1, 0)); Vector eyePos = getTransform().getPosition();
rotation = glm::rotate(rotation, rotationY, Vector(1, 0, 0)); Vector lookAt = eyePos + getTransform().getForward();
Vector4 translation(0, 0, distance, 1); std::cout << "Eye: " << eyePos << " lookAt: " << lookAt << std::endl;
translation = rotation * translation; viewMatrix = glm::lookAt(eyePos, lookAt, Vector(0, 1, 0));
cameraPosition = originPoint + Vector(translation); bNeedsViewBuild = false;
viewMatrix = glm::lookAt(cameraPosition, originPoint, Vector(0, 1, 0));
bNeedsViewBuild = false;
} }
void CameraComponent::buildProjectionMatrix() void CameraComponent::buildProjectionMatrix()
{ {
projectionMatrix = glm::perspective(fieldOfView, aspectRatio, 1.0f, 1000.f); projectionMatrix = glm::perspective(fieldOfView, aspectRatio, 1.0f, 1000.f);
static Matrix4 correctionMatrix = static Matrix4 correctionMatrix =
Matrix4( Matrix4(
Vector4(1, 0, 0, 0), Vector4(1, 0, 0, 0),
Vector4(0, 1, 0, 0), Vector4(0, 1, 0, 0),
Vector4(0, 0, 0.5f, 0), Vector4(0, 0, 0.5f, 0),
Vector4(0, 0, 0.5f, 1)); Vector4(0, 0, 0.5f, 1));
projectionMatrix = correctionMatrix * projectionMatrix; projectionMatrix = correctionMatrix * projectionMatrix;
bNeedsProjectionBuild = false; bNeedsProjectionBuild = false;
} }
+34 -42
View File
@@ -10,51 +10,43 @@ public:
CameraComponent(); CameraComponent();
virtual ~CameraComponent(); virtual ~CameraComponent();
Matrix4 getViewMatrix() Matrix4 getViewMatrix()
{ {
if (bNeedsViewBuild) if (bNeedsViewBuild)
{ {
buildViewMatrix(); buildViewMatrix();
} }
return viewMatrix; return viewMatrix;
} }
Matrix4 getProjectionMatrix() Matrix4 getProjectionMatrix()
{ {
if (bNeedsProjectionBuild) if (bNeedsProjectionBuild)
{ {
buildProjectionMatrix(); buildProjectionMatrix();
} }
return projectionMatrix; return projectionMatrix;
} }
Vector getCameraPosition() Vector getCameraPosition()
{ {
if(bNeedsViewBuild) return getTransform().getPosition();
{ }
buildViewMatrix(); void mouseMove(float deltaX, float deltaY);
} void mouseScroll(float x);
return cameraPosition; void moveX(float amount);
} void moveY(float amount);
void mouseMove(float deltaX, float deltaY); float aspectRatio;
void mouseScroll(double x); float fieldOfView;
void moveOrigin(float up);
float aspectRatio;
float fieldOfView;
private: private:
bool bNeedsViewBuild; bool bNeedsViewBuild;
bool bNeedsProjectionBuild; bool bNeedsProjectionBuild;
void buildViewMatrix(); void buildViewMatrix();
void buildProjectionMatrix(); void buildProjectionMatrix();
float rotationX; //Transforms relative to actor
float rotationY; Matrix4 viewMatrix;
float distance; Matrix4 projectionMatrix;
float rotationX;
Vector eye; float rotationY;
Vector originPoint;
Vector cameraPosition;
//Transforms relative to actor
Matrix4 viewMatrix;
Matrix4 projectionMatrix;
}; };
DEFINE_REF(CameraComponent) DEFINE_REF(CameraComponent)
} // namespace Seele } // namespace Seele
+70 -134
View File
@@ -6,9 +6,6 @@ using namespace Seele;
Component::Component() Component::Component()
{ {
relativeLocation = Vector(0);
relativeRotation = Vector(0);
relativeScale = Vector(1, 1, 1);
} }
Component::~Component() Component::~Component()
{ {
@@ -89,162 +86,101 @@ void Component::notifySceneAttach(PScene scene)
child->notifySceneAttach(scene); child->notifySceneAttach(scene);
} }
} }
void Component::setWorldLocation(Vector location)
{ //void Component::setAbsoluteLocation(Vector location)
Vector newRelLocation = location; //{
if (parent != nullptr) // Vector newRelLocation = location;
{ // if (parent != nullptr)
Transform parentToWorld = getParent()->getTransform(); // {
newRelLocation = parentToWorld.inverseTransformPosition(location); // Transform parentToWorld = getParent()->getTransform();
} // newRelLocation = parentToWorld.inverseTransformPosition(location);
setRelativeLocation(newRelLocation); // }
} // setRelativeLocation(newRelLocation);
void Component::setWorldRotation(Vector rotation) //}
{ //void Component::setAbsoluteRotation(Vector rotation)
Vector newRelRotator = rotation; //{
if (parent == nullptr) // Vector newRelRotator = rotation;
{ // if (parent == nullptr)
setRelativeRotation(rotation); // {
} // setRelativeRotation(rotation);
else // }
{ // else
setWorldRotation(toQuaternion(newRelRotator)); // {
} // setAbsoluteRotation(toQuaternion(newRelRotator));
} // }
void Component::setWorldRotation(Quaternion rotation) //}
{ //void Component::setAbsoluteRotation(Quaternion rotation)
Quaternion newRelRotation = getRelativeWorldRotation(rotation); //{
setRelativeRotation(newRelRotation); // Quaternion newRelRotation = getRelativeWorldRotation(rotation);
} // setRelativeRotation(newRelRotation);
void Component::setWorldScale(Vector scale) //}
{ //void Component::setWorldScale(Vector scale)
Vector newRelScale = scale; //{
if (parent != nullptr) // Vector newRelScale = scale;
{ // if (parent != nullptr)
Transform parentToWorld = parent->getTransform(); // {
newRelScale = scale * parentToWorld.getSafeScaleReciprocal(Vector4(parentToWorld.getScale(), 0)); // Transform parentToWorld = parent->getTransform();
} // newRelScale = scale * parentToWorld.getSafeScaleReciprocal(Vector4(parentToWorld.getScale(), 0));
setRelativeScale(newRelScale); // }
} // setRelativeScale(newRelScale);
//}
void Component::setRelativeLocation(Vector location) void Component::setRelativeLocation(Vector location)
{ {
setRelativeLocationAndRotation(location, relativeRotation); transform = Transform(location, transform.getRotation(), transform.getScale());
} }
void Component::setRelativeRotation(Vector rotation) void Component::setRelativeRotation(Vector rotation)
{ {
setRelativeLocationAndRotation(relativeLocation, toQuaternion(rotation)); transform = Transform(transform.getPosition(), Quaternion(rotation), transform.getScale());
} }
void Component::setRelativeRotation(Quaternion rotation) void Component::setRelativeRotation(Quaternion rotation)
{ {
setRelativeLocationAndRotation(relativeLocation, rotation); transform = Transform(transform.getPosition(), rotation, transform.getScale());
} }
void Component::setRelativeScale(Vector scale) void Component::setRelativeScale(Vector scale)
{ {
if (scale != relativeScale) transform = Transform(transform.getPosition(), transform.getRotation(), scale);
{
relativeScale = scale;
updateComponentTransform(relativeRotation);
}
} }
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(); transform = Transform(transform.getPosition() + translation, transform.getRotation(), transform.getScale());
setWorldLocation(newWorldLocation);
} }
void Component::addWorldRotation(Vector rotation) void Component::addRelativeRotation(Vector rotation)
{ {
const Quaternion newWorldRotation = toQuaternion(rotation) * getTransform().getRotation(); transform = Transform(transform.getPosition(), transform.getRotation() + Quaternion(rotation), transform.getScale());
setWorldRotation(newWorldRotation);
} }
void Component::addWorldRotation(Quaternion rotation) void Component::addRelativeRotation(Quaternion rotation)
{ {
const Quaternion newWorldRotation = rotation * getTransform().getRotation(); transform = Transform(transform.getPosition(), transform.getRotation(), transform.getScale());
setWorldRotation(newWorldRotation);
} }
Transform Component::getTransform() const Transform Component::getTransform() const
{ {
return transform; 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) if(parent != nullptr)
{ {
newTransform = relTransform * parent->getTransform(); return transform + parent->getAbsoluteTransform();
}
else
{
newTransform = relTransform;
}
bool bHasChanged = !getTransform().equals(newTransform);
if (bHasChanged)
{
transform = newTransform;
propagateTransformUpdate();
} }
} return transform;
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());
} }
+13 -16
View File
@@ -28,27 +28,33 @@ public:
void addChildComponent(PComponent component); void addChildComponent(PComponent component);
virtual void notifySceneAttach(PScene scene); virtual void notifySceneAttach(PScene scene);
void setWorldLocation(Vector location); //void setAbsoluteLocation(Vector location);
void setWorldRotation(Vector rotation); //void setAbsoluteRotation(Vector rotation);
void setWorldRotation(Quaternion rotation); //void setAbsoluteRotation(Quaternion rotation);
void setWorldScale(Vector scale); //void setWorldScale(Vector scale);
void setRelativeLocation(Vector location); void setRelativeLocation(Vector location);
void setRelativeRotation(Vector rotation); void setRelativeRotation(Vector rotation);
void setRelativeRotation(Quaternion rotation); void setRelativeRotation(Quaternion rotation);
void setRelativeScale(Vector scale); void setRelativeScale(Vector scale);
void addWorldTranslation(Vector translation); //void addAbsoluteTranslation(Vector translation);
void addWorldRotation(Vector rotation); //void addAbsoluteRotation(Vector rotation);
void addWorldRotation(Quaternion rotation); //void addAbsoluteRotation(Quaternion rotation);
void addRelativeLocation(Vector translation);
void addRelativeRotation(Vector rotation);
void addRelativeRotation(Quaternion rotation);
Transform getTransform() const; Transform getTransform() const;
Transform getAbsoluteTransform() const;
template<typename ComponentType> template<typename ComponentType>
RefPtr<ComponentType> getComponent() RefPtr<ComponentType> getComponent()
{ {
return tryFindComponent<ComponentType>(); return tryFindComponent<ComponentType>();
} }
private: private:
template<typename ComponentType> template<typename ComponentType>
RefPtr<ComponentType> tryFindComponent() RefPtr<ComponentType> tryFindComponent()
@@ -68,15 +74,6 @@ private:
} }
return nullptr; 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; Transform transform;
PScene owningScene; PScene owningScene;
PActor owner; PActor owner;
@@ -50,5 +50,5 @@ void PrimitiveComponent::notifySceneAttach(PScene scene)
Matrix4 PrimitiveComponent::getRenderMatrix() Matrix4 PrimitiveComponent::getRenderMatrix()
{ {
return getTransform().toMatrix(); return getAbsoluteTransform().toMatrix();
} }
+14 -5
View File
@@ -19,12 +19,12 @@ Scene::Scene(Gfx::PGraphics graphics)
lightEnv.directionalLights[0].intensity = Vector4(1, 1, 1, 1); lightEnv.directionalLights[0].intensity = Vector4(1, 1, 1, 1);
lightEnv.numDirectionalLights = 1; lightEnv.numDirectionalLights = 1;
srand((unsigned int)time(NULL)); 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].colorRange = Vector4(frand(), frand(), frand(), frand() * 300);
lightEnv.pointLights[i].positionWS = Vector4(frand() * 100-50, frand(), frand() * 100-50, 1); 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].colorRange = Vector4(1, 0, 1, 1000);
lightEnv.pointLights[0].positionWS = Vector4(0, 10, 0, 1); 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) Job Scene::beginUpdate(double deltaTime)
{ {
//std::cout << "Scene::beginUpdate" << std::endl; //std::cout << "Scene::beginUpdate" << std::endl;
auto startTime = std::chrono::high_resolution_clock::now();
Array<Job> jobs; Array<Job> jobs;
for(auto actor : rootActors) for(auto actor : rootActors)
{ {
jobs.addAll(actor->launchTick(static_cast<float>(deltaTime))); jobs.addAll(actor->launchTick(static_cast<float>(deltaTime)));
} }
co_await Job::all(jobs); co_await Job::all(jobs);
//std::cout << "Scene::beginUpdate finished waiting" << std::endl; auto endTime = std::chrono::high_resolution_clock::now();
for(auto job : jobs) float delta = std::chrono::duration_cast<std::chrono::seconds>(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;
} }
} }
+1
View File
@@ -19,6 +19,7 @@ struct DirectionalLight
struct PointLight struct PointLight
{ {
Vector4 positionWS; Vector4 positionWS;
//Vector4 positionVS;
Vector4 colorRange; Vector4 colorRange;
}; };
+1 -1
View File
@@ -123,7 +123,7 @@ public:
void update() void update()
{ {
// lock should not be necessary, but lets keep it for now // lock should not be necessary, but lets keep it for now
std::scoped_lock lock(dataLock); //std::scoped_lock lock(dataLock);
data = toBeWritten; data = toBeWritten;
dirty = false; dirty = false;
} }
+71 -65
View File
@@ -3,7 +3,6 @@
using namespace Seele; using namespace Seele;
std::atomic_uint64_t Seele::globalCounter;
Event::Event() Event::Event()
: flag(std::make_shared<StateStore>()) : flag(std::make_shared<StateStore>())
@@ -16,11 +15,20 @@ Event::Event(nullptr_t)
} }
Event::Event(const std::string &name) Event::Event(const std::string &name)
: name(name) : flag(std::make_shared<StateStore>())
, flag(std::make_shared<StateStore>())
{ {
flag->name = name;
} }
Event::Event(const std::source_location &location)
: flag(std::make_shared<StateStore>())
{
flag->name = location.function_name();
flag->location = location;
}
void Event::raise() void Event::raise()
{ {
std::scoped_lock lock(flag->lock); std::scoped_lock lock(flag->lock);
@@ -50,43 +58,34 @@ ThreadPool::ThreadPool(uint32 threadCount)
running.store(true); running.store(true);
for (uint32 i = 0; i < threadCount; ++i) 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() ThreadPool::~ThreadPool()
{ {
cleanup(); workers.clear();
} }
void ThreadPool::cleanup() void ThreadPool::waitIdle()
{ {
bool temp = true; while(true)
running.compare_exchange_strong(temp, false);
if(!temp)
return;
{ {
std::scoped_lock lock(jobQueueLock); std::unique_lock lock(numIdlingLock);
jobQueueCV.notify_all(); 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) void ThreadPool::enqueueWaiting(Event &event, Promise* job)
{ {
assert(!job->done()); assert(!job->done());
std::scoped_lock lock(waitingLock); std::scoped_lock lock(waitingLock);
//std::cout << "Job " << job->finishedEvent.name << " waiting on event " << event.name << std::endl; //std::cout << "Job " << job->finishedEvent.name << " waiting on event " << event.name << std::endl;
waitingJobs[event].push_back(job); waitingJobs[event].add(job);
job->addRef(); job->addRef();
} }
void ThreadPool::enqueueWaiting(Event &event, MainPromise* job) void ThreadPool::enqueueWaiting(Event &event, MainPromise* job)
@@ -94,15 +93,15 @@ void ThreadPool::enqueueWaiting(Event &event, MainPromise* job)
assert(!job->done()); assert(!job->done());
std::scoped_lock lock(waitingMainLock); std::scoped_lock lock(waitingMainLock);
//std::cout << job->finishedEvent.name << " waiting on event " << event.name << std::endl; //std::cout << job->finishedEvent.name << " waiting on event " << event.name << std::endl;
waitingMainJobs[event].push_back(job); waitingMainJobs[event].add(job);
job->addRef(); job->addRef();
} }
void ThreadPool::scheduleJob(Promise* job) void ThreadPool::scheduleJob(Promise* job)
{ {
assert(!job->done()); assert(!job->done());
std::scoped_lock lock(jobQueueLock); std::scoped_lock lock(jobQueueLock);
//std::cout << "Queueing job " << job->finishedEvent.name << std::endl; //std::cout << "Queueing job " << job->finishedEvent << std::endl;
jobQueue.push_back(job); jobQueue.add(job);
jobQueueCV.notify_one(); jobQueueCV.notify_one();
job->addRef(); job->addRef();
} }
@@ -110,8 +109,8 @@ void ThreadPool::scheduleJob(MainPromise* job)
{ {
assert(!job->done()); assert(!job->done());
std::scoped_lock lock(mainJobLock); std::scoped_lock lock(mainJobLock);
//std::cout << "Queueing job " << job->finishedEvent.name << std::endl; //std::cout << "Queueing job " << job->finishedEvent << std::endl;
mainJobs.push_back(job); mainJobs.add(job);
mainJobCV.notify_one(); mainJobCV.notify_one();
job->addRef(); job->addRef();
} }
@@ -120,79 +119,86 @@ void ThreadPool::notify(Event &event)
//std::cout << "Event " << event.name << " raised" << std::endl; //std::cout << "Event " << event.name << " raised" << std::endl;
{ {
std::scoped_lock lock(jobQueueLock, waitingLock); std::scoped_lock lock(jobQueueLock, waitingLock);
std::list<Promise*> jobs = std::move(waitingJobs[event]); List<Promise*> jobs = std::move(waitingJobs[event]);
waitingJobs.erase(event); waitingJobs.erase(event);
for (auto &job : jobs) for (auto &job : jobs)
{ {
//assert(job.id != -1ull); //assert(job.id != -1ull);
//std::cout << "Waking up " << job->finishedEvent.name << std::endl; //std::cout << "Waking up " << job->finishedEvent.name << std::endl;
job->state = Promise::State::SCHEDULED; job->state = Promise::State::SCHEDULED;
jobQueue.push_back(job); jobQueue.add(job);
jobQueueCV.notify_one(); jobQueueCV.notify_one();
} }
} }
{ {
std::scoped_lock lock(mainJobLock, waitingMainLock); std::scoped_lock lock(mainJobLock, waitingMainLock);
std::list<MainPromise*> jobs = std::move(waitingMainJobs[event]); List<MainPromise*> jobs = std::move(waitingMainJobs[event]);
waitingMainJobs.erase(event); waitingMainJobs.erase(event);
for (auto &job : jobs) for (auto &job : jobs)
{ {
//assert(job.id != -1ull); //assert(job.id != -1ull);
//std::cout << "Waking up main " << job->finishedEvent.name << std::endl; //std::cout << "Waking up main " << job->finishedEvent.name << std::endl;
job->state = MainPromise::State::SCHEDULED; job->state = MainPromise::State::SCHEDULED;
mainJobs.push_back(job); mainJobs.add(job);
mainJobCV.notify_one(); 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); mainJobCV.wait(lock);
if(mainJobs.empty())
{
mainJobCV.wait(lock);
}
if (!mainJobs.empty())
{
job = mainJobs.front();
mainJobs.pop_front();
}
else
{
continue;
}
} }
job = mainJobs.front();
mainJobs.popFront();
}
job->resume();
job->removeRef();
}
}
void ThreadPool::threadLoop()
{
List<Promise*> localQueue;
while (true)
{
[[likely]]
if(!localQueue.empty())
{
Promise* job = localQueue.retrieve();
job->resume(); job->resume();
job->removeRef(); job->removeRef();
} }
else 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(); std::unique_lock lock2(numIdlingLock);
jobQueue.pop_front(); numIdling--;
}
else
{
continue;
} }
} }
//std::cout << "Starting job " << job.id << std::endl; // take 1/numThreads jobs, maybe make this a parameter that
job->resume(); // adjusts based on past workload
job->removeRef(); uint32 numTaken = std::max(jobQueue.size() / workers.size(), 1ull);
while (!jobQueue.empty() && localQueue.size() < numTaken)
{
localQueue.add(jobQueue.retrieve());
}
} }
} }
} }
+90 -40
View File
@@ -17,6 +17,7 @@ public:
Event(); Event();
Event(nullptr_t); Event(nullptr_t);
Event(const std::string& name); Event(const std::string& name);
Event(const std::source_location& location);
~Event() = default; ~Event() = default;
auto operator<=>(const Event& other) const auto operator<=>(const Event& other) const
{ {
@@ -36,6 +37,19 @@ public:
return flag->data; 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 raise();
void reset(); void reset();
bool await_ready(); bool await_ready();
@@ -43,17 +57,17 @@ public:
constexpr void await_suspend(std::coroutine_handle<JobPromiseBase<MainJob>> h); constexpr void await_suspend(std::coroutine_handle<JobPromiseBase<MainJob>> h);
constexpr void await_resume() {} constexpr void await_resume() {}
private: private:
std::string name;
struct StateStore struct StateStore
{ {
std::mutex lock; std::mutex lock;
std::string name;
std::source_location location;
bool data; bool data;
}; };
std::shared_ptr<StateStore> flag; std::shared_ptr<StateStore> flag;
friend class ThreadPool; friend class ThreadPool;
}; };
extern std::atomic_uint64_t globalCounter;
template<bool MainJob> template<bool MainJob>
struct JobBase; struct JobBase;
template<bool MainJob> template<bool MainJob>
@@ -70,8 +84,7 @@ struct JobPromiseBase
JobPromiseBase(const std::source_location& location = std::source_location::current()) JobPromiseBase(const std::source_location& location = std::source_location::current())
{ {
handle = std::coroutine_handle<JobPromiseBase<MainJob>>::from_promise(*this); handle = std::coroutine_handle<JobPromiseBase<MainJob>>::from_promise(*this);
id = globalCounter++; finishedEvent = Event(location);
finishedEvent = Event(std::string(location.file_name()).append(": ").append(location.function_name()));
} }
~JobPromiseBase() ~JobPromiseBase()
{} {}
@@ -81,9 +94,10 @@ struct JobPromiseBase
inline auto final_suspend() noexcept; inline auto final_suspend() noexcept;
void return_void() noexcept {} void return_void() noexcept {}
void unhandled_exception() noexcept { void unhandled_exception() {
std::cerr << "Unhandled exception! Exiting" << std::endl; std::exception_ptr exception = std::current_exception();
exit(1); std::cerr << "Unhandled exception!" << std::endl;
throw exception;
}; };
void resume() void resume()
@@ -165,16 +179,22 @@ struct JobPromiseBase
} }
void removeRef() void removeRef()
{ {
if(--numRefs < 1 && done()) if(--numRefs < 1)
{ {
handle.destroy(); if(done())
{
handle.destroy();
}
else
{
schedule();
}
} }
} }
std::mutex promiseLock; std::mutex promiseLock;
std::coroutine_handle<JobPromiseBase> handle; std::coroutine_handle<JobPromiseBase> handle;
JobPromiseBase* continuation = nullptr; JobPromiseBase* continuation = nullptr;
uint64 id;
std::atomic_uint64_t numRefs = 0; std::atomic_uint64_t numRefs = 0;
Event finishedEvent; Event finishedEvent;
State state = State::READY; State state = State::READY;
@@ -210,7 +230,7 @@ public:
{ {
if(promise) if(promise)
{ {
promise->schedule(); //promise->schedule();
promise->removeRef(); promise->removeRef();
} }
} }
@@ -253,19 +273,25 @@ public:
{ {
return promise->done(); return promise->done();
} }
void finalize()
{
promise->finalize();
}
Event operator co_await() const 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 // be scheduled from the destructor
promise->schedule(); promise->schedule();
return promise->finishedEvent; return promise->finishedEvent;
} }
static JobBase all() = delete; static JobBase all() = delete;
template<iterable Iterable> template<std::ranges::range Iterable>
requires std::same_as<std::ranges::range_value_t<Iterable>, JobBase>
static JobBase all(Iterable collection)
{
getGlobalThreadPool().scheduleBatch(collection);
for(auto it : collection)
{
co_await it;
}
}
template<std::ranges::range Iterable>
static JobBase all(Iterable collection) static JobBase all(Iterable collection)
{ {
for(auto it : collection) for(auto it : collection)
@@ -278,14 +304,17 @@ public:
{ {
return JobBase::all(Array{jobs...}); return JobBase::all(Array{jobs...});
} }
template<std::invocable JobFunc, iterable IterableParams> template<typename JobFunc, std::ranges::input_range Iterable>
static JobBase launchJobs(JobFunc&& func, IterableParams params) requires std::invocable<JobFunc, std::ranges::range_reference_t<Iterable>>
static JobBase launchJobs(JobFunc&& func, Iterable params)
{ {
List<JobBase> jobs; Array<JobBase> jobs;
for(auto&& param : params) for(auto&& param : params)
{ {
jobs.add(func(param)); JobBase base = func(param);
jobs.add(base);
} }
getGlobalThreadPool().scheduleBatch(jobs);
for(auto job : jobs) for(auto job : jobs)
{ {
co_await job; co_await job;
@@ -293,6 +322,7 @@ public:
} }
private: private:
JobPromiseBase<MainJob>* promise; JobPromiseBase<MainJob>* promise;
friend class ThreadPool;
}; };
using MainJob = JobBase<true>; using MainJob = JobBase<true>;
@@ -305,32 +335,64 @@ class ThreadPool
public: public:
ThreadPool(uint32 threadCount = std::thread::hardware_concurrency()); ThreadPool(uint32 threadCount = std::thread::hardware_concurrency());
virtual ~ThreadPool(); virtual ~ThreadPool();
void cleanup(); void waitIdle();
// Adds a job to the waiting queue for event // Adds a job to the waiting queue for event
void enqueueWaiting(Event& event, Promise* job); void enqueueWaiting(Event& event, Promise* job);
// Adds a job to the waiting queue for event // Adds a job to the waiting queue for event
void enqueueWaiting(Event& event, MainPromise* job); void enqueueWaiting(Event& event, MainPromise* job);
void scheduleJob(Promise* job); void scheduleJob(Promise* job);
void scheduleJob(MainPromise* job); void scheduleJob(MainPromise* job);
template<std::ranges::range Iterable>
requires std::same_as<std::ranges::range_value_t<Iterable>, MainJob>
void scheduleBatch(Iterable jobs)
{
std::scoped_lock lock(mainJobLock);
for(auto job : jobs)
{
job.promise->addRef();
job.promise->state = JobPromiseBase<true>::State::SCHEDULED;
mainJobs.add(job.promise);
}
mainJobCV.notify_one();
}
template<std::ranges::range Iterable>
requires std::same_as<std::ranges::range_value_t<Iterable>, Job>
void scheduleBatch(Iterable jobs)
{
std::scoped_lock lock(jobQueueLock);
for(auto job : jobs)
{
job.promise->addRef();
job.promise->state = JobPromiseBase<false>::State::SCHEDULED;
jobQueue.add(job.promise);
}
jobQueueCV.notify_all();
}
void notify(Event& event); void notify(Event& event);
void threadLoop(const bool isMainThread); void mainLoop();
void threadLoop();
private: private:
std::atomic_bool running; std::atomic_bool running;
std::vector<std::thread> workers; std::mutex numIdlingLock;
std::condition_variable numIdlingIncr;
uint32 numIdling;
Array<std::thread> workers;
std::list<MainPromise*> mainJobs; List<MainPromise*> mainJobs;
std::mutex mainJobLock; std::mutex mainJobLock;
std::condition_variable mainJobCV; std::condition_variable mainJobCV;
std::list<Promise*> jobQueue; List<Promise*> jobQueue;
std::mutex jobQueueLock; std::mutex jobQueueLock;
std::condition_variable jobQueueCV; std::condition_variable jobQueueCV;
std::map<Event, std::list<MainPromise*>> waitingMainJobs; Map<Event, List<MainPromise*>> waitingMainJobs;
std::mutex waitingMainLock; std::mutex waitingMainLock;
std::map<Event, std::list<Promise*>> waitingJobs; Map<Event, List<Promise*>> waitingJobs;
std::mutex waitingLock; std::mutex waitingLock;
uint32 maxLocalQueueSize = 50;
}; };
template<bool MainJob> template<bool MainJob>
@@ -349,18 +411,6 @@ inline auto JobPromiseBase<MainJob>::initial_suspend() noexcept
template<bool MainJob> template<bool MainJob>
inline auto JobPromiseBase<MainJob>::final_suspend() noexcept inline auto JobPromiseBase<MainJob>::final_suspend() noexcept
{ {
/*struct JobAwaitable
{
constexpr bool await_ready() const noexcept { return false; }
constexpr auto await_suspend(std::coroutine_handle<JobPromiseBase<MainJob>> h) const noexcept
{
auto continuation = h.promise().continuation;
h.destroy();
}
constexpr void await_resume() const noexcept {}
};
return JobAwaitable{};*/
markDone(); markDone();
return std::suspend_always{}; return std::suspend_always{};
} }
+32 -18
View File
@@ -32,15 +32,15 @@ Seele::SceneView::SceneView(Gfx::PGraphics graphics, PWindow owner, const Viewpo
AssetRegistry::importFile("C:\\Users\\Dynamitos\\TestSeeleProject\\Assets\\Plane\\plane.fbx"); AssetRegistry::importFile("C:\\Users\\Dynamitos\\TestSeeleProject\\Assets\\Plane\\plane.fbx");
PPrimitiveComponent ayaka = new PrimitiveComponent(AssetRegistry::findMesh("Ayaka")); PPrimitiveComponent ayaka = new PrimitiveComponent(AssetRegistry::findMesh("Ayaka"));
ayaka->addWorldTranslation(Vector(0, 0, 0)); ayaka->setRelativeLocation(Vector(0, 0, 0));
ayaka->setWorldScale(Vector(10, 10, 10)); ayaka->setRelativeScale(Vector(10, 10, 10));
//scene->addPrimitiveComponent(ayaka); //scene->addPrimitiveComponent(ayaka);
PPrimitiveComponent plane = new PrimitiveComponent(AssetRegistry::findMesh("plane")); PPrimitiveComponent plane = new PrimitiveComponent(AssetRegistry::findMesh("plane"));
plane->setWorldScale(Vector(100, 100, 100)); plane->setRelativeScale(Vector(100, 100, 100));
scene->addPrimitiveComponent(plane); scene->addPrimitiveComponent(plane);
for(uint32 i = 0; i < 1; ++i) for(uint32 i = 0; i < 100000; ++i)
{ {
PMyComponent myComp = new MyComponent(); PMyComponent myComp = new MyComponent();
PMyOtherComponent myOtherComp = new MyOtherComponent(); PMyOtherComponent myOtherComp = new MyOtherComponent();
@@ -97,32 +97,46 @@ void SceneView::prepareRender()
MainJob SceneView::render() MainJob SceneView::render()
{ {
return MainJob::all( return depthPrepass.beginFrame()
depthPrepass.beginFrame(), .then(lightCullingPass.beginFrame())
lightCullingPass.beginFrame(), .then(basePass.beginFrame())
basePass.beginFrame())
.then(depthPrepass.render()) .then(depthPrepass.render())
.then(lightCullingPass.render()) .then(lightCullingPass.render())
.then(basePass.render()) .then(basePass.render())
.then( .then(depthPrepass.endFrame())
MainJob::all( .then(lightCullingPass.endFrame())
depthPrepass.endFrame(), .then(basePass.endFrame());
lightCullingPass.endFrame(),
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(action != InputAction::RELEASE)
{ {
if(code == KeyCode::KEY_W) if(code == KeyCode::KEY_W)
{ {
activeCamera->getCameraComponent()->moveOrigin(1); activeCamera->getCameraComponent()->moveX(1);
} }
if(code == KeyCode::KEY_S) 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) 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; mouseDown = true;
} }
+1 -3
View File
@@ -27,16 +27,14 @@ void Window::addView(PView view)
MainJob Window::render() MainJob Window::render()
{ {
gfxHandle->beginFrame(); gfxHandle->beginFrame();
Array<MainJob> jobs;
for(auto& windowView : views) for(auto& windowView : views)
{ {
{ {
std::scoped_lock lock(windowView->workerMutex); std::scoped_lock lock(windowView->workerMutex);
windowView->view->prepareRender(); windowView->view->prepareRender();
} }
jobs.add(windowView->view->render()); co_await windowView->view->render();
} }
co_await MainJob::all(jobs);
gfxHandle->endFrame(); gfxHandle->endFrame();
if(owner->isActive()) if(owner->isActive())
{ {
+1 -1
View File
@@ -41,6 +41,6 @@ void WindowManager::notifyWindowClosed(PWindow window)
windows.remove(windows.find(window)); windows.remove(windows.find(window));
if(windows.empty()) if(windows.empty())
{ {
getGlobalThreadPool().cleanup(); exit(0);
} }
} }
+1 -1
View File
@@ -37,6 +37,6 @@ int main()
window->render(); window->render();
getGlobalThreadPool().threadLoop(true); getGlobalThreadPool().mainLoop();
return 0; return 0;
} }
+2 -2
View File
@@ -1,5 +1,5 @@
#pragma once #pragma once
//#include <vld.h> #include <vld.h>
#include "ThreadPool.h" #include "ThreadPool.h"
namespace Seele namespace Seele
@@ -12,7 +12,7 @@ namespace Seele
} }
~GlobalFixture() ~GlobalFixture()
{ {
getGlobalThreadPool().cleanup(); getGlobalThreadPool().waitIdle();
} }
void setup() void setup()
{ {
+84
View File
@@ -1,6 +1,9 @@
#include "EngineTest.h" #include "EngineTest.h"
#include "ThreadPool.h" #include "ThreadPool.h"
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <numeric>
using namespace std::chrono_literals;
BOOST_AUTO_TEST_SUITE(ThreadPool) BOOST_AUTO_TEST_SUITE(ThreadPool)
@@ -9,18 +12,21 @@ uint64 basicAwaitState = 0;
Job basicAwaitFirst() Job basicAwaitFirst()
{ {
BOOST_REQUIRE_EQUAL(basicAwaitState, 5); BOOST_REQUIRE_EQUAL(basicAwaitState, 5);
std::this_thread::sleep_for(500ms);
basicAwaitState = 10; basicAwaitState = 10;
co_return; co_return;
} }
Job basicAwaitSecond() Job basicAwaitSecond()
{ {
BOOST_REQUIRE_EQUAL(basicAwaitState, 15); BOOST_REQUIRE_EQUAL(basicAwaitState, 15);
std::this_thread::sleep_for(500ms);
basicAwaitState = 20; basicAwaitState = 20;
co_return; co_return;
} }
Job basicAwaitThird() Job basicAwaitThird()
{ {
BOOST_REQUIRE_EQUAL(basicAwaitState, 25); BOOST_REQUIRE_EQUAL(basicAwaitState, 25);
std::this_thread::sleep_for(500ms);
basicAwaitState = 30; basicAwaitState = 30;
co_return; co_return;
} }
@@ -48,18 +54,21 @@ uint64 basicThenState = 5;
Job basicThenFirst() Job basicThenFirst()
{ {
BOOST_REQUIRE_EQUAL(basicThenState, 5); BOOST_REQUIRE_EQUAL(basicThenState, 5);
std::this_thread::sleep_for(500ms);
basicThenState = 10; basicThenState = 10;
co_return; co_return;
} }
Job basicThenSecond() Job basicThenSecond()
{ {
BOOST_REQUIRE_EQUAL(basicThenState, 15); BOOST_REQUIRE_EQUAL(basicThenState, 15);
std::this_thread::sleep_for(500ms);
basicThenState = 20; basicThenState = 20;
co_return; co_return;
} }
Job basicThenThird() Job basicThenThird()
{ {
BOOST_REQUIRE_EQUAL(basicThenState, 25); BOOST_REQUIRE_EQUAL(basicThenState, 25);
std::this_thread::sleep_for(500ms);
basicThenState = 30; basicThenState = 30;
co_return; co_return;
} }
@@ -70,6 +79,7 @@ BOOST_AUTO_TEST_CASE(basic_thenchain)
.then([]() -> Job .then([]() -> Job
{ {
BOOST_REQUIRE_EQUAL(basicThenState, 10); BOOST_REQUIRE_EQUAL(basicThenState, 10);
std::this_thread::sleep_for(500ms);
basicThenState = 15; basicThenState = 15;
co_return; co_return;
}) })
@@ -77,6 +87,7 @@ BOOST_AUTO_TEST_CASE(basic_thenchain)
.then([]() -> Job .then([]() -> Job
{ {
BOOST_REQUIRE_EQUAL(basicThenState, 20); BOOST_REQUIRE_EQUAL(basicThenState, 20);
std::this_thread::sleep_for(500ms);
basicThenState = 25; basicThenState = 25;
co_return; co_return;
}) })
@@ -92,11 +103,13 @@ uint64 basicAllState1 = 0;
uint64 basicAllState2 = 0; uint64 basicAllState2 = 0;
Job basicAllFirst() Job basicAllFirst()
{ {
std::this_thread::sleep_for(500ms);
basicAllState1 = 10; basicAllState1 = 10;
co_return; co_return;
} }
Job basicAllSecond() Job basicAllSecond()
{ {
std::this_thread::sleep_for(500ms);
basicAllState2 = 10; basicAllState2 = 10;
co_return; co_return;
} }
@@ -112,10 +125,41 @@ BOOST_AUTO_TEST_CASE(basic_all)
Job::all(basicAllFirst(), basicAllSecond()).then(basicAllThen()); 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; uint64 basicCallable = 0;
Job basicCallableFunc() Job basicCallableFunc()
{ {
std::this_thread::sleep_for(500ms);
basicCallable = 10; basicCallable = 10;
co_return; co_return;
} }
@@ -130,4 +174,44 @@ BOOST_AUTO_TEST_CASE(basic_callable)
}); });
} }
struct Payload
{
StaticArray<uint64, 1000> 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<uint64>());
}
co_return;
}
Job launchStressTest()
{
Array<Payload> payloads(100);
Array<Job> 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<std::chrono::seconds>(endTime - startTime).count();
std::cout << "Update took " << delta << " seconds";
}
BOOST_AUTO_TEST_CASE(stress_test)
{
//launchStressTest();
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()