diff --git a/sandbox/tests/drawcalls/index.html b/sandbox/tests/drawcalls/index.html index 5cb34648..5ea50b41 100644 --- a/sandbox/tests/drawcalls/index.html +++ b/sandbox/tests/drawcalls/index.html @@ -13,7 +13,7 @@
# Items:0
- + \ No newline at end of file diff --git a/src/engine/Collision/Colliders/ClosestLineJumpTable.ts b/src/engine/Collision/Colliders/ClosestLineJumpTable.ts index 4fe9a905..e866cfff 100644 --- a/src/engine/Collision/Colliders/ClosestLineJumpTable.ts +++ b/src/engine/Collision/Colliders/ClosestLineJumpTable.ts @@ -4,6 +4,7 @@ import { Ray } from '../../Math/ray'; import { PolygonCollider } from './PolygonCollider'; import { EdgeCollider } from './EdgeCollider'; import { CircleCollider } from './CircleCollider'; +import { Profiler } from '../../Profiler'; /** * Finds the closes line between 2 line segments, were the magnitude of u, v are the lengths of each segment @@ -102,6 +103,8 @@ export function ClosestLine(p0: Vector, u: Vector, q0: Vector, v: Vector) { export const ClosestLineJumpTable = { PolygonPolygonClosestLine(polygonA: PolygonCollider, polygonB: PolygonCollider) { + try { + Profiler.start('PolygonPolygonClosestLine') // Find the 2 closest faces on each polygon const otherWorldPos = polygonB.worldPos; const otherDirection = otherWorldPos.sub(polygonA.worldPos); @@ -125,6 +128,9 @@ export const ClosestLineJumpTable = { const v = otherFace.face.getEdge(); return ClosestLine(p0, u, q0, v); + } finally { + Profiler.end(); + } }, PolygonEdgeClosestLine(polygon: PolygonCollider, edge: EdgeCollider) { diff --git a/src/engine/Collision/Colliders/CollisionJumpTable.ts b/src/engine/Collision/Colliders/CollisionJumpTable.ts index 84d57b80..752b385a 100644 --- a/src/engine/Collision/Colliders/CollisionJumpTable.ts +++ b/src/engine/Collision/Colliders/CollisionJumpTable.ts @@ -7,9 +7,12 @@ import { LineSegment } from '../../Math/line-segment'; import { Vector } from '../../Math/vector'; import { TransformComponent } from '../../EntityComponentSystem'; import { Pair } from '../Detection/Pair'; +import { Profiler } from '../../Profiler'; export const CollisionJumpTable = { CollideCircleCircle(circleA: CircleCollider, circleB: CircleCollider): CollisionContact[] { + try { + Profiler.start('CollideCircleCircle'); const circleAPos = circleA.worldPos; const circleBPos = circleB.worldPos; const combinedRadius = circleA.radius + circleB.radius; @@ -38,6 +41,9 @@ export const CollisionJumpTable = { }; return [new CollisionContact(circleA, circleB, mvt, normal, tangent, [point], [local], info)]; + } finally { + Profiler.end(); + } }, CollideCirclePolygon(circle: CircleCollider, polygon: PolygonCollider): CollisionContact[] { @@ -213,6 +219,8 @@ export const CollisionJumpTable = { }, CollidePolygonPolygon(polyA: PolygonCollider, polyB: PolygonCollider): CollisionContact[] { + try { + Profiler.start('CollidePolygonPolygon'); // Multi contact from SAT // https://gamedev.stackexchange.com/questions/111390/multiple-contacts-for-sat-collision-detection // do a SAT test to find a min axis if it exists @@ -274,9 +282,15 @@ export const CollisionJumpTable = { return [new CollisionContact(polyA, polyB, normal.scale(-separation.separation), normal, tangent, points, localPoints, separation)]; } return []; + } finally { + Profiler.end(); + } }, FindContactSeparation(contact: CollisionContact, localPoint: Vector) { + try { + + Profiler.start('FindContactSeparation'); const shapeA = contact.colliderA; const txA = contact.colliderA.owner?.get(TransformComponent) ?? new TransformComponent(); const shapeB = contact.colliderB; @@ -355,5 +369,8 @@ export const CollisionJumpTable = { } return 0; + } finally { + Profiler.end(); + } } }; diff --git a/src/engine/Collision/Solver/RealisticSolver.ts b/src/engine/Collision/Solver/RealisticSolver.ts index e25cf079..38aa5772 100644 --- a/src/engine/Collision/Solver/RealisticSolver.ts +++ b/src/engine/Collision/Solver/RealisticSolver.ts @@ -8,6 +8,7 @@ import { Physics } from '../Physics'; import { CollisionSolver } from './Solver'; import { BodyComponent, DegreeOfFreedom } from '../BodyComponent'; import { CollisionJumpTable } from '../Colliders/CollisionJumpTable'; +import { profile } from '../../Profiler'; export class RealisticSolver implements CollisionSolver { lastFrameContacts: Map = new Map(); @@ -38,6 +39,7 @@ export class RealisticSolver implements CollisionSolver { return contacts; } + @profile() preSolve(contacts: CollisionContact[]) { const epsilon = .0001; for (const contact of contacts) { @@ -153,6 +155,7 @@ export class RealisticSolver implements CollisionSolver { } } + @profile() postSolve(contacts: CollisionContact[]) { for (const contact of contacts) { const bodyA = contact.colliderA.owner.get(BodyComponent); @@ -197,6 +200,7 @@ export class RealisticSolver implements CollisionSolver { * Warm up body's based on previous frame contact points * @param contacts */ + @profile() warmStart(contacts: CollisionContact[]) { for (const contact of contacts) { const bodyA = contact.colliderA.owner?.get(BodyComponent); @@ -224,6 +228,7 @@ export class RealisticSolver implements CollisionSolver { * Iteratively solve the position overlap constraint * @param contacts */ + @profile() solvePosition(contacts: CollisionContact[]) { for (let i = 0; i < Physics.positionIterations; i++) { for (const contact of contacts) { @@ -288,6 +293,7 @@ export class RealisticSolver implements CollisionSolver { } } + @profile() solveVelocity(contacts: CollisionContact[]) { for (let i = 0; i < Physics.velocityIterations; i++) { for (const contact of contacts) { diff --git a/src/engine/Graphics/Context/ExcaliburGraphicsContextWebGL.ts b/src/engine/Graphics/Context/ExcaliburGraphicsContextWebGL.ts index fdae4d65..1a7f1bf1 100644 --- a/src/engine/Graphics/Context/ExcaliburGraphicsContextWebGL.ts +++ b/src/engine/Graphics/Context/ExcaliburGraphicsContextWebGL.ts @@ -34,6 +34,7 @@ import { AffineMatrix } from '../../Math/affine-matrix'; import { Material, MaterialOptions } from './material'; import { MaterialRenderer } from './material-renderer/material-renderer'; import { Shader, ShaderOptions } from './shader'; +import { Profiler, profile } from '../../Profiler'; export const pixelSnapEpsilon = 0.0001; @@ -516,13 +517,15 @@ export class ExcaliburGraphicsContextWebGL implements ExcaliburGraphicsContext { /** * Flushes all batched rendering to the screen */ + @profile() flush() { const gl = this.__gl; - + Profiler.start('render target'); // render target captures all draws and redirects to the render target this._renderTarget.use(); if (this.useDrawSorting) { + Profiler.start('sort'); // sort draw calls // Find the original order of the first instance of the draw call const originalSort = new Map(); @@ -543,10 +546,12 @@ export class ExcaliburGraphicsContextWebGL implements ExcaliburGraphicsContext { } return zIndex; }); + Profiler.end(); const oldTransform = this._transform.current; const oldState = this._state.current; + Profiler.start('batch draws'); if (this._drawCalls.length) { let currentRendererName = this._drawCalls[0].renderer; let currentRenderer = this._renderers.get(currentRendererName); @@ -569,14 +574,17 @@ export class ExcaliburGraphicsContextWebGL implements ExcaliburGraphicsContext { currentRenderer.flush(); } } + Profiler.end(); // reset state this._transform.current = oldTransform; this._state.current = oldState; + Profiler.start('pool cleanup'); // reclaim draw calls this._drawCallPool.done(); this._drawCalls.length = 0; + Profiler.end(); } else { // This is the final flush at the moment to draw any leftover pending draw for (const renderer of this._renderers.values()) { @@ -587,7 +595,8 @@ export class ExcaliburGraphicsContextWebGL implements ExcaliburGraphicsContext { } this._renderTarget.disable(); - + Profiler.end(); + Profiler.start('postprocessing'); // post process step const source = this._renderTarget.toRenderSource(); source.use(); @@ -602,5 +611,6 @@ export class ExcaliburGraphicsContextWebGL implements ExcaliburGraphicsContext { // passing null switches rendering back to the canvas gl.bindFramebuffer(gl.FRAMEBUFFER, null); this._screenRenderer.renderToScreen(); + Profiler.end(); } } diff --git a/src/engine/Graphics/Context/circle-renderer/circle-renderer.ts b/src/engine/Graphics/Context/circle-renderer/circle-renderer.ts index 9e508e92..00621b04 100644 --- a/src/engine/Graphics/Context/circle-renderer/circle-renderer.ts +++ b/src/engine/Graphics/Context/circle-renderer/circle-renderer.ts @@ -1,5 +1,6 @@ import { Color } from '../../../Color'; import { vec, Vector } from '../../../Math/vector'; +import { profile } from '../../../Profiler'; import { GraphicsDiagnostics } from '../../GraphicsDiagnostics'; import { ExcaliburGraphicsContextWebGL, pixelSnapEpsilon } from '../ExcaliburGraphicsContextWebGL'; import { QuadIndexBuffer } from '../quad-index-buffer'; @@ -179,6 +180,7 @@ export class CircleRenderer implements RendererPlugin { return this._circleCount !== 0; } + @profile() flush(): void { // nothing to draw early exit if (this._circleCount === 0) { diff --git a/src/engine/Graphics/Context/image-renderer/image-renderer.ts b/src/engine/Graphics/Context/image-renderer/image-renderer.ts index e822d01c..cd96fe9a 100644 --- a/src/engine/Graphics/Context/image-renderer/image-renderer.ts +++ b/src/engine/Graphics/Context/image-renderer/image-renderer.ts @@ -1,4 +1,5 @@ import { vec } from '../../../Math/vector'; +import { profile } from '../../../Profiler'; import { ImageFiltering } from '../../Filtering'; import { GraphicsDiagnostics } from '../../GraphicsDiagnostics'; import { HTMLImageSource } from '../ExcaliburGraphicsContext'; @@ -269,6 +270,7 @@ export class ImageRenderer implements RendererPlugin { return this._imageCount !== 0; } + @profile() flush(): void { // nothing to draw early exit if (this._imageCount === 0) { diff --git a/src/engine/Graphics/Context/line-renderer/line-renderer.ts b/src/engine/Graphics/Context/line-renderer/line-renderer.ts index 8211d46e..cb3c2d77 100644 --- a/src/engine/Graphics/Context/line-renderer/line-renderer.ts +++ b/src/engine/Graphics/Context/line-renderer/line-renderer.ts @@ -6,6 +6,7 @@ import { ExcaliburGraphicsContextWebGL } from '../ExcaliburGraphicsContextWebGL' import { RendererPlugin } from '../renderer'; import { Shader, VertexBuffer, VertexLayout } from '../..'; import { GraphicsDiagnostics } from '../../GraphicsDiagnostics'; +import { profile } from '../../../Profiler'; export class LineRenderer implements RendererPlugin { public readonly type = 'ex.line'; @@ -90,6 +91,7 @@ export class LineRenderer implements RendererPlugin { return this._lineCount !== 0; } + @profile() flush(): void { // nothing to draw early exit if (this._lineCount === 0) { diff --git a/src/engine/Graphics/Context/material-renderer/material-renderer.ts b/src/engine/Graphics/Context/material-renderer/material-renderer.ts index 75873462..2edff93d 100644 --- a/src/engine/Graphics/Context/material-renderer/material-renderer.ts +++ b/src/engine/Graphics/Context/material-renderer/material-renderer.ts @@ -1,4 +1,5 @@ import { vec } from '../../../Math/vector'; +import { profile } from '../../../Profiler'; import { ImageFiltering } from '../../Filtering'; import { HTMLImageSource } from '../ExcaliburGraphicsContext'; import { ExcaliburGraphicsContextWebGL } from '../ExcaliburGraphicsContextWebGL'; @@ -43,6 +44,7 @@ export class MaterialRenderer implements RendererPlugin { this._quads = new QuadIndexBuffer(gl, 1, true); } + @profile() draw(image: HTMLImageSource, sx: number, sy: number, diff --git a/src/engine/Graphics/Context/point-renderer/point-renderer.ts b/src/engine/Graphics/Context/point-renderer/point-renderer.ts index ac76b273..07c15fbc 100644 --- a/src/engine/Graphics/Context/point-renderer/point-renderer.ts +++ b/src/engine/Graphics/Context/point-renderer/point-renderer.ts @@ -8,6 +8,7 @@ import { Shader } from '../shader'; import { VertexBuffer } from '../vertex-buffer'; import { VertexLayout } from '../vertex-layout'; import { GraphicsDiagnostics } from '../../GraphicsDiagnostics'; +import { profile } from '../../../Profiler'; export class PointRenderer implements RendererPlugin { public readonly type = 'ex.point'; @@ -89,6 +90,7 @@ export class PointRenderer implements RendererPlugin { return this._pointCount !== 0; } + @profile() flush(): void { // nothing to draw early exit if (this._pointCount === 0) { diff --git a/src/engine/Graphics/Context/rectangle-renderer/rectangle-renderer.ts b/src/engine/Graphics/Context/rectangle-renderer/rectangle-renderer.ts index 52bbc214..8b574100 100644 --- a/src/engine/Graphics/Context/rectangle-renderer/rectangle-renderer.ts +++ b/src/engine/Graphics/Context/rectangle-renderer/rectangle-renderer.ts @@ -1,5 +1,6 @@ import { Color } from '../../../Color'; import { vec, Vector } from '../../../Math/vector'; +import { profile } from '../../../Profiler'; import { GraphicsDiagnostics } from '../../GraphicsDiagnostics'; import { ExcaliburGraphicsContextWebGL, pixelSnapEpsilon } from '../ExcaliburGraphicsContextWebGL'; import { QuadIndexBuffer } from '../quad-index-buffer'; @@ -332,6 +333,7 @@ export class RectangleRenderer implements RendererPlugin { return this._rectangleCount !== 0; } + @profile() flush(): void { // nothing to draw early exit if (this._rectangleCount === 0) { diff --git a/src/engine/Graphics/GraphicsComponent.ts b/src/engine/Graphics/GraphicsComponent.ts index 037c3ee8..6b157601 100644 --- a/src/engine/Graphics/GraphicsComponent.ts +++ b/src/engine/Graphics/GraphicsComponent.ts @@ -6,6 +6,7 @@ import { Logger } from '../Util/Log'; import { BoundingBox } from '../Collision/Index'; import { Component } from '../EntityComponentSystem/Component'; import { Material } from './Context/material'; +import { profile } from '../Profiler'; /** * Type guard for checking if a Graphic HasTick (used for graphics that change over time like animations) @@ -422,6 +423,7 @@ export class GraphicsComponent extends Component<'ex.graphics'> { this._localBounds = bounds; } + @profile() public recalculateBounds() { let bb = new BoundingBox(); for (const layer of this.layers.get()) { @@ -455,6 +457,7 @@ export class GraphicsComponent extends Component<'ex.graphics'> { * @param elapsed * @internal */ + @profile() public update(elapsed: number, idempotencyToken: number = 0) { for (const layer of this.layers.get()) { for (const { graphic } of layer.graphics) { diff --git a/src/engine/Graphics/OffscreenSystem.ts b/src/engine/Graphics/OffscreenSystem.ts index 1d8614bd..fb959969 100644 --- a/src/engine/Graphics/OffscreenSystem.ts +++ b/src/engine/Graphics/OffscreenSystem.ts @@ -10,6 +10,7 @@ import { ParallaxComponent } from './ParallaxComponent'; import { Vector } from '../Math/vector'; import { CoordPlane } from '../Math/coord-plane'; import { BoundingBox } from '../Collision/BoundingBox'; +import { profile } from '../Profiler'; export class OffscreenSystem extends System { public readonly types = ['ex.transform', 'ex.graphics'] as const; @@ -58,6 +59,7 @@ export class OffscreenSystem extends System 1) { const frame = Profiler.stack.pop(); frame.value = now - frame.value; // store the total time - // console.log(frame.value); + frame.duration = frame.value; } else { Profiler.stack[0].value = now - Profiler.stack[0].value; + Profiler.stack[0].duration = Profiler.stack[0].value; } }