Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions experiments/vmath_simd.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
when not defined(amd64):
{.error: "experiments/vmath_simd.nim is an amd64 SIMD-only experiment".}

when defined(gcc) or defined(clang):
{.passc: "-msse4.1 -march=native -mtune=native -ffast-math".}

import nimsimd/sse41

type
Vec3* = M128

template vec3*[T: SomeNumber](x, y, z: T): Vec3 =
mm_set_ps(float32(z), float32(z), float32(y), float32(x))

template vec3*[T: SomeNumber](v: T): Vec3 =
vec3(v, v, v)

template vec3*(): Vec3 =
vec3(0'f32)

template x*(a: Vec3): float32 =
mm_cvtss_f32(a)

template y*(a: Vec3): float32 =
mm_cvtss_f32(mm_shuffle_ps(a, a, MM_SHUFFLE(1, 1, 1, 1)))

template z*(a: Vec3): float32 =
mm_cvtss_f32(mm_shuffle_ps(a, a, MM_SHUFFLE(2, 2, 2, 2)))

template `+`*(a, b: Vec3): Vec3 =
mm_add_ps(a, b)

template `-`*(a, b: Vec3): Vec3 =
mm_sub_ps(a, b)

template `-`*(a: Vec3): Vec3 =
mm_sub_ps(mm_setzero_ps(), a)

template `*`*(a, b: Vec3): Vec3 =
mm_mul_ps(a, b)

template `*`*(a: Vec3, b: float32): Vec3 =
mm_mul_ps(a, mm_set1_ps(b))

template `*`*(a: float32, b: Vec3): Vec3 =
b * a

template `/`*(a: Vec3, b: float32): Vec3 =
mm_div_ps(a, mm_set1_ps(b))

template dot*(a, b: Vec3): float32 =
mm_cvtss_f32(mm_dp_ps(a, b, 0x7f))

template lengthSq*(a: Vec3): float32 =
a.dot(a)

template length*(a: Vec3): float32 =
mm_cvtss_f32(mm_sqrt_ss(mm_dp_ps(a, a, 0x7f)))

template normalize*(a: Vec3): Vec3 =
mm_div_ps(a, mm_sqrt_ps(mm_dp_ps(a, a, 0x7f)))

template cross*(a, b: Vec3): Vec3 =
block:
var t1 = mm_shuffle_ps(b, b, MM_SHUFFLE(0, 0, 2, 1))
t1 = mm_mul_ps(t1, a)
var t2 = mm_shuffle_ps(a, a, MM_SHUFFLE(0, 0, 2, 1))
t2 = mm_mul_ps(t2, b)
let t3 = mm_sub_ps(t1, t2)
mm_shuffle_ps(t3, t3, MM_SHUFFLE(0, 0, 2, 1))
32 changes: 17 additions & 15 deletions tests/bench_raytracer.nim
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import
std/math,
benchy, chroma, pixie, vmath

{.push inline, noinit, checks: off.}
{.push inline, checks: off.}

type
SurfaceType = enum
Expand All @@ -21,7 +21,7 @@ type
Ray = object
start, dir: Vec3

Thing = ref object
Thing = object
surfaceType: SurfaceType
case objectType: ObjectType
of Sphere:
Expand All @@ -32,15 +32,15 @@ type
offset: float32

Intersection = object
thing: Thing
thingIdx: int
ray: Ray
dist: float32

Light = object
pos: Vec3
color: Color

Scene = ref object
Scene = object
maxDepth: int
things: seq[Thing]
lights: seq[Light]
Expand Down Expand Up @@ -84,6 +84,8 @@ proc getNormal(obj: Thing, pos: Vec3): Vec3 =
return obj.normal

proc objectIntersect(obj: Thing, ray: Ray): Intersection =
result.thingIdx = -1
result.dist = 0.0
case obj.objectType:
of Sphere:
let
Expand All @@ -95,14 +97,12 @@ proc objectIntersect(obj: Thing, ray: Ray): Intersection =
if disc >= 0:
dist = v - sqrt(disc)
if dist != 0.0:
result.thing = obj
result.ray = ray
result.dist = dist
of Plane:
let denom = obj.normal.dot(ray.dir)
if denom <= 0:
result.dist = (obj.normal.dot(ray.start) + obj.offset) / (-denom)
result.thing = obj
result.ray = ray

proc newSphere(center: Vec3, radius: float32, surfaceType: SurfaceType): Thing =
Expand Down Expand Up @@ -132,7 +132,6 @@ proc getSurfaceProperties(obj: Thing, pos: Vec3): SurfaceProperties =
result.roughness = 150.0

proc newScene(): Scene =
result = Scene()
result.maxDepth = 5
result.things = @[
newPlane(vec3(0.0, 1.0, 0.0), 0.0, CheckerBoardSurface),
Expand All @@ -149,24 +148,26 @@ proc newScene(): Scene =

proc intersections(scene: Scene, ray: Ray): Intersection =
var closest: float32 = farAway
result.thing = nil
for thing in scene.things:
result.thingIdx = -1
result.dist = 0.0
for i, thing in scene.things:
let intersect = objectIntersect(thing, ray)
if (not isNil(intersect.thing)) and (intersect.dist < closest):
if intersect.dist != 0.0 and intersect.dist < closest:
result = intersect
result.thingIdx = i
closest = intersect.dist

proc testRay(scene: Scene, ray: Ray): float32 =
let intersection = scene.intersections(ray)
if not isNil(intersection.thing):
if intersection.thingIdx >= 0:
return intersection.dist
return NaN

proc shade(scene: Scene, intersection: Intersection, depth: int): Color

proc traceRay(scene: Scene, ray: Ray, depth: int): Color =
let intersection = intersections(scene, ray)
if not isNil(intersection.thing):
if intersection.thingIdx >= 0:
return scene.shade(intersection, depth)
return background

Expand Down Expand Up @@ -213,19 +214,20 @@ proc getNaturalColor(scene: Scene, thing: Thing, pos, norm,
result = result + lightColor + specularColor

proc shade(scene: Scene, intersection: Intersection, depth: int): Color =
let thing = scene.things[intersection.thingIdx]
var
dir = intersection.ray.dir
scaled = dir * intersection.dist
pos = scaled + intersection.ray.start
normal = intersection.thing.getNormal(pos)
normal = thing.getNormal(pos)
reflectDir = dir - (normal * normal.dot(dir) * 2)
naturalColor = background + getNaturalColor(scene, intersection.thing,
naturalColor = background + getNaturalColor(scene, thing,
pos, normal, reflectDir)
reflectedColor: Color
if depth >= scene.maxDepth:
reflectedColor = grey
else:
reflectedColor = getReflectionColor(scene, intersection.thing, pos, normal,
reflectedColor = getReflectionColor(scene, thing, pos, normal,
reflectDir, depth)
return naturalColor + reflectedColor

Expand Down
32 changes: 17 additions & 15 deletions tests/bench_raytracer_glm.nim
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ from pixie import Image, newImage, writeFile, dataIndex

type Vec3 = glm.Vec3[float32]

{.push inline, noinit, checks: off.}
{.push inline, checks: off.}

type
SurfaceType = enum
Expand All @@ -24,7 +24,7 @@ type
Ray = object
start, dir: Vec3

Thing = ref object
Thing = object
surfaceType: SurfaceType
case objectType: ObjectType
of Sphere:
Expand All @@ -35,15 +35,15 @@ type
offset: float32

Intersection = object
thing: Thing
thingIdx: int
ray: Ray
dist: float32

Light = object
pos: Vec3
color: Color

Scene = ref object
Scene = object
maxDepth: int
things: seq[Thing]
lights: seq[Light]
Expand Down Expand Up @@ -87,6 +87,8 @@ proc getNormal(obj: Thing, pos: Vec3): Vec3 =
return obj.normal

proc objectIntersect(obj: Thing, ray: Ray): Intersection =
result.thingIdx = -1
result.dist = 0.0
case obj.objectType:
of Sphere:
let
Expand All @@ -98,14 +100,12 @@ proc objectIntersect(obj: Thing, ray: Ray): Intersection =
if disc >= 0:
dist = v - sqrt(disc)
if dist != 0.0:
result.thing = obj
result.ray = ray
result.dist = dist
of Plane:
let denom = obj.normal.dot(ray.dir)
if denom <= 0:
result.dist = (obj.normal.dot(ray.start) + obj.offset) / (-denom)
result.thing = obj
result.ray = ray

proc newSphere(center: Vec3, radius: float32, surfaceType: SurfaceType): Thing =
Expand Down Expand Up @@ -135,7 +135,6 @@ proc getSurfaceProperties(obj: Thing, pos: Vec3): SurfaceProperties =
result.roughness = 150.0

proc newScene(): Scene =
result = Scene()
result.maxDepth = 5
result.things = @[
newPlane(vec3(0.0f, 1.0f, 0.0f), 0.0, CheckerBoardSurface),
Expand All @@ -152,24 +151,26 @@ proc newScene(): Scene =

proc intersections(scene: Scene, ray: Ray): Intersection =
var closest: float32 = farAway
result.thing = nil
for thing in scene.things:
result.thingIdx = -1
result.dist = 0.0
for i, thing in scene.things:
let intersect = objectIntersect(thing, ray)
if (not isNil(intersect.thing)) and (intersect.dist < closest):
if intersect.dist != 0.0 and intersect.dist < closest:
result = intersect
result.thingIdx = i
closest = intersect.dist

proc testRay(scene: Scene, ray: Ray): float32 =
let intersection = scene.intersections(ray)
if not isNil(intersection.thing):
if intersection.thingIdx >= 0:
return intersection.dist
return NaN

proc shade(scene: Scene, intersection: Intersection, depth: int): Color

proc traceRay(scene: Scene, ray: Ray, depth: int): Color =
let intersection = intersections(scene, ray)
if not isNil(intersection.thing):
if intersection.thingIdx >= 0:
return scene.shade(intersection, depth)
return background

Expand Down Expand Up @@ -216,19 +217,20 @@ proc getNaturalColor(scene: Scene, thing: Thing, pos, norm,
result = result + lightColor + specularColor

proc shade(scene: Scene, intersection: Intersection, depth: int): Color =
let thing = scene.things[intersection.thingIdx]
var
dir = intersection.ray.dir
scaled = dir * intersection.dist
pos = scaled + intersection.ray.start
normal = intersection.thing.getNormal(pos)
normal = thing.getNormal(pos)
reflectDir = dir - (normal * normal.dot(dir) * 2)
naturalColor = background + getNaturalColor(scene, intersection.thing,
naturalColor = background + getNaturalColor(scene, thing,
pos, normal, reflectDir)
reflectedColor: Color
if depth >= scene.maxDepth:
reflectedColor = grey
else:
reflectedColor = getReflectionColor(scene, intersection.thing, pos, normal,
reflectedColor = getReflectionColor(scene, thing, pos, normal,
reflectDir, depth)
return naturalColor + reflectedColor

Expand Down
Loading
Loading