Compare commits
9 Commits
44b53e4099
...
193ba0b4a5
Author | SHA1 | Date | |
---|---|---|---|
|
193ba0b4a5 | ||
|
952a773875 | ||
|
7807619d58 | ||
|
3429e09d15 | ||
|
ecc283d091 | ||
|
67ce1832a4 | ||
|
1098e6551d | ||
|
efa3391dbd | ||
|
f2020f7463 |
@ -37,7 +37,8 @@ pub fn RectSIMD(comptime T: type) type {
|
||||
### Assembly ###
|
||||
This is produced by godbolt, which apparently has AVX512 extensions, so, it's extremely compact.
|
||||
|
||||
note: SysV prelude and outro are omitted, with inlining you can expect it looking similarly.
|
||||
Note: Calling prelude and outro are omitted, with inlining you can expect it looking similarly.
|
||||
Zig calling convention is used, which is roughly equal to C's static marked procedure.
|
||||
|
||||
For 32bit floating point:
|
||||
```asm
|
||||
@ -148,9 +149,8 @@ For 32bit signed integers it fares amazing too:
|
||||
|
||||
AVX512 makes it so that there's no big penalty for double precision types, which is nice.
|
||||
|
||||
Note that permutation masks are also supplied along side code which increase binary size.
|
||||
With inlining it could be quite substantial if per object %rip relative addressing is used.
|
||||
|
||||
### Edits ###
|
||||
- Reordered to use packed vectors without swizzling when possible.
|
||||
- Eliminated redundant computations.
|
||||
- Calling convention notice.
|
||||
|
||||
|
141
articles/vector-pi-rotation/page.mmd
Normal file
141
articles/vector-pi-rotation/page.mmd
Normal file
@ -0,0 +1,141 @@
|
||||
Title: Optimized Vector Rotation
|
||||
Brief: Specialized rotation methods over Pi and Pi/2 in 2D and 3D.
|
||||
Date: 1699548646
|
||||
Tags: Programming, Zig, Optimization
|
||||
CSS: /style.css
|
||||
|
||||
Came up with some useful optimization for 90 and 180 degree rotations while making a grid walker,
|
||||
below implementations are given, ripped straight from source, lol.
|
||||
|
||||
Compared to generic cos/sin method of rotation it's magnitudes of times less work in many cases, especially if glibc implementation is used.
|
||||
|
||||
Note: Given example assumes coordinate system where Y grows downwards and X to the right.
|
||||
|
||||
## Two dimensions
|
||||
|
||||
```zig
|
||||
pub fn rotateByHalfPiClockwise(self: Self) Self {
|
||||
return .{ .components = .{ -self.y(), self.x() } };
|
||||
}
|
||||
|
||||
pub fn rotateByHalfPiCounterClockwise(self: Self) Self {
|
||||
return .{ .components = .{ self.y(), -self.x() } };
|
||||
}
|
||||
|
||||
pub fn rotateByPi(self: Self) Self {
|
||||
return .{ .components = .{ -self.x(), -self.y() } };
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Three dimensions
|
||||
|
||||
```zig
|
||||
pub fn rotateByHalfPiClockwiseAroundAxis(self: Self, axis: Axis3) Self {
|
||||
return .{ .components = switch (axis) {
|
||||
.x => .{ self.x(), -self.z(), self.y() },
|
||||
.y => .{ -self.z(), self.y(), self.x() },
|
||||
.z => .{ -self.y(), self.x(), self.z() },
|
||||
} };
|
||||
}
|
||||
|
||||
pub fn rotateByHalfPiCounterClockwiseAroundAxis(self: Self, axis: Axis3) Self {
|
||||
return .{ .components = switch (axis) {
|
||||
.x => .{ self.x(), self.z(), -self.y() },
|
||||
.y => .{ self.z(), self.y(), -self.x() },
|
||||
.z => .{ self.y(), -self.x(), self.z() },
|
||||
} };
|
||||
}
|
||||
|
||||
pub fn rotateByPiAroundAxis(self: Self, axis: Axis3) Self {
|
||||
return .{ .components = switch (axis) {
|
||||
.x => .{ self.x(), -self.x(), -self.y() },
|
||||
.y => .{ -self.x(), self.y(), -self.z() },
|
||||
.z => .{ -self.x(), -self.y(), self.z() },
|
||||
} };
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Generated amd64 assembly
|
||||
Note: Procedure prelude/epilogue is omitted. Zig's calling convention is used, which is roughly equivalent to C's static marked function in effect.
|
||||
|
||||
Note: It's for vectors stored packed for use in SSE, array/separate scalar passing produces worse result, at least when not inlined.
|
||||
|
||||
### rotateByHalfPiClockwise
|
||||
Notice how it's one instruction longer than coutner-clockwise case,
|
||||
so, choice of coordinate system effects costs of particular direction to rotate around.
|
||||
|
||||
```asm
|
||||
vmovlpd qword ptr [rsp], xmm0
|
||||
vmovshdup xmm1, xmm0
|
||||
vpbroadcastd xmm2, dword ptr [rip + .LCPI2_0]
|
||||
vpxor xmm1, xmm1, xmm2
|
||||
vbroadcastss xmm0, xmm0
|
||||
vblendps xmm0, xmm0, xmm1, 1
|
||||
```
|
||||
### rotateByHalfPiCounterClockwise
|
||||
|
||||
```asm
|
||||
vmovlpd qword ptr [rsp], xmm0
|
||||
vpbroadcastd xmm1, dword ptr [rip + .LCPI1_0]
|
||||
vpxor xmm1, xmm0, xmm1
|
||||
vmovshdup xmm0, xmm0
|
||||
vinsertps xmm0, xmm0, xmm1, 16
|
||||
```
|
||||
|
||||
### rotateByPi
|
||||
```asm
|
||||
vmovlpd qword ptr [rsp], xmm0
|
||||
vpermilps xmm0, xmm0, 212
|
||||
vpbroadcastd xmm1, dword ptr [rip + .LCPI3_0]
|
||||
vpxor xmm0, xmm0, xmm1
|
||||
```
|
||||
|
||||
### rotateByHalfPiClockwiseAroundAxis (X)
|
||||
```asm
|
||||
sub rsp, 24
|
||||
vmovq qword ptr [rsp], xmm0
|
||||
vpermilpd xmm1, xmm0, 1
|
||||
vmovaps xmm2, xmm1
|
||||
vmovss dword ptr [rsp + 8], xmm2
|
||||
vpbroadcastd xmm2, dword ptr [rip + .LCPI4_0]
|
||||
vpxor xmm1, xmm1, xmm2
|
||||
vpermilps xmm0, xmm0, 212
|
||||
vinsertps xmm0, xmm0, xmm1, 16
|
||||
add rsp, 24
|
||||
```
|
||||
|
||||
### rotateByHalfPiCounterClockwiseAroundAxis (X)
|
||||
Again, one instruction shorter.
|
||||
|
||||
```asm
|
||||
sub rsp, 24
|
||||
vextractps dword ptr [rsp + 8], xmm0, 2
|
||||
vmovq qword ptr [rsp], xmm0
|
||||
vmovshdup xmm1, xmm0
|
||||
vpbroadcastd xmm2, dword ptr [rip + .LCPI5_0]
|
||||
vpxor xmm1, xmm1, xmm2
|
||||
vpermilps xmm0, xmm0, 232
|
||||
vinsertps xmm0, xmm0, xmm1, 32
|
||||
add rsp, 24
|
||||
```
|
||||
|
||||
### rotateByPiAroundAxis (X)
|
||||
Now it's more work.
|
||||
|
||||
```asm
|
||||
sub rsp, 24
|
||||
vmovq qword ptr [rsp], xmm0
|
||||
vpermilpd xmm1, xmm0, 1
|
||||
vmovaps xmm2, xmm1
|
||||
vmovss dword ptr [rsp + 8], xmm2
|
||||
vmovshdup xmm2, xmm0
|
||||
vbroadcastss xmm3, dword ptr [rip + .LCPI6_0]
|
||||
vpxor xmm2, xmm2, xmm3
|
||||
vpxor xmm1, xmm1, xmm3
|
||||
vinsertps xmm0, xmm0, xmm2, 16
|
||||
vinsertps xmm0, xmm0, xmm1, 32
|
||||
add rsp, 24
|
||||
```
|
||||
|
@ -1,11 +0,0 @@
|
||||
Title: .xm Tracks
|
||||
Brief: .xm track listing with playback.
|
||||
Date: 1684868476
|
||||
Tags: Meta, Music, Js
|
||||
CSS: /style.css
|
||||
|
||||
Today is the day of .xm archival and in-browser playback addition.
|
||||
It's achieved with help of [jsxm](https://github.com/a1k0n/jsxm).
|
||||
It lacks support for some things though, might need to contribute to it.
|
||||
|
||||
Could be neat to make some small program that would generate waveforms pngs next.
|
@ -24,5 +24,3 @@ for d in ./articles/*/; do
|
||||
done
|
||||
|
||||
./tools/feed_generator.py ./articles/ https://mjestecko.neocities.org/ > ./html/feed.xml
|
||||
|
||||
./tools/track_listing_generator.py html/tracks > html/tracks.html
|
||||
|
@ -1,8 +1,26 @@
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--bg-color: #111;
|
||||
--fg-color: #fff;
|
||||
--link-color: dodgerblue;
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
color: var(--fg-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--link-color);
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 20px;
|
||||
font-family: "Charter","Georgia",'Times New Roman',serif;
|
||||
}
|
||||
body {
|
||||
background-color: var(--bg-color);
|
||||
line-height: 1.3;
|
||||
}
|
||||
article, .container {
|
||||
@ -29,7 +47,7 @@ html {
|
||||
margin: 0.9em 0px 0.9em;
|
||||
}
|
||||
pre, code {
|
||||
background-color: #eeeeff;
|
||||
background-color: var(--bg-color);
|
||||
line-height: normal;
|
||||
overflow: auto;
|
||||
font-size: 0.8em;
|
||||
@ -46,7 +64,7 @@ html {
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
font-size: 0.8em;
|
||||
background-color: #f0f0f0;
|
||||
background-color: var(--bg-color);
|
||||
border: 1px solid #bbbbdd;
|
||||
}
|
||||
nav li:first-child {
|
||||
@ -66,10 +84,10 @@ html {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
nav a:link {
|
||||
color: #44d;
|
||||
color: var(--link-color);
|
||||
}
|
||||
nav a:visited {
|
||||
color: #44d;
|
||||
color: var(--link-color);
|
||||
}
|
||||
nav a.here {
|
||||
background-color: #e0e0e0;
|
||||
|
@ -25,18 +25,23 @@ page = f"""Personal blog of one {choice(ADJECTIVES)} Veclav Talica.
|
||||
|
||||
"""
|
||||
|
||||
# todo: Sort by date first.
|
||||
artciles = {}
|
||||
for root, dirs, _ in walk(argv[1]):
|
||||
for d in dirs:
|
||||
metadata = parse_metadata(path.abspath(root + '/' + d + "/page.mmd"))
|
||||
article = urllib.parse.quote(d)
|
||||
artciles[article] = {
|
||||
"metadata": metadata
|
||||
}
|
||||
break
|
||||
|
||||
for title in sorted(artciles.keys(), key=lambda a: artciles[a]["metadata"].get("Date", time.gmtime(0)), reverse=True):
|
||||
article = artciles[title]
|
||||
metadata = article["metadata"]
|
||||
page += (
|
||||
f"""[{metadata.get("Title", "No title given! What a clusterfuck!")}](/articles/{article}.html)\n\n"""
|
||||
f""">{metadata.get("Brief", "")}\n\n"""
|
||||
)
|
||||
if "Tags" in metadata:
|
||||
page += f""">*{','.join(metadata["Tags"])}*\n---\n"""
|
||||
break
|
||||
|
||||
curtime = time.gmtime(int(time.time()))
|
||||
page += f"Last compiled: *{MONTHS[curtime.tm_mon]} {curtime.tm_mday}, {curtime.tm_year} {curtime.tm_hour}:{curtime.tm_min:02d} UTC*\n\n"
|
||||
|
@ -2,23 +2,21 @@
|
||||
HEAD_EMBED = """
|
||||
|
||||
<div class="container">
|
||||
<header>
|
||||
<nav>
|
||||
<strong>mjestečko</strong> /
|
||||
<a href="/">main</a> /
|
||||
<a href="https://git.poto.cafe/veclavtalica/mjestecko">source</a> /
|
||||
<a href="/tracks.html">tracks</a> /
|
||||
<a href="/feed.xml">rss</a> /
|
||||
<a href="/articles/mjestečko.html">about</a>
|
||||
<nav class="custom-nav">
|
||||
<ul>
|
||||
<li><a href="/"><strong>mjestečko</strong></a></li>
|
||||
<li><a href="https://git.poto.cafe/veclavtalica/mjestecko">source</a></li>
|
||||
<li><a href="/feed.xml">rss</a></li>
|
||||
<li><a href="/articles/mjestečko.html">about</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
"""
|
||||
|
||||
NOTICE = """
|
||||
---
|
||||
*Remember, - all you see here is free for use for any purpose benefiting the humanity as a whole.*
|
||||
<footer>
|
||||
<a href="#top">Take me home ↑</a>
|
||||
</footer>
|
||||
|
||||
"""
|
||||
|
||||
@ -55,5 +53,11 @@ WEEKDAYS = {
|
||||
6: "Sunday"
|
||||
}
|
||||
|
||||
def mixin_tag(content: str, tag: str) -> str:
|
||||
return f"""<{tag}>
|
||||
{content}</{tag}>
|
||||
|
||||
"""
|
||||
|
||||
def wrap_page(page: str) -> str:
|
||||
return HEAD_EMBED + page + NOTICE + TAIL_EMBED
|
||||
return HEAD_EMBED + mixin_tag(page, "main") + NOTICE + TAIL_EMBED
|
||||
|
@ -1,92 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
from sys import argv, exit
|
||||
from os import walk, path
|
||||
|
||||
from page_shares import HEAD_EMBED, TAIL_EMBED
|
||||
|
||||
if len(argv) <= 1:
|
||||
print("No directory was supplied")
|
||||
exit(-1)
|
||||
|
||||
page = """<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Tracks</title>
|
||||
<link type="text/css" rel="stylesheet" href="/style.css"/>
|
||||
<script type="text/javascript" src="/xm.js"></script>
|
||||
<script type="text/javascript">
|
||||
(function (window, document) {
|
||||
if (!window.XMPlayer)
|
||||
window.XMPlayer = {};
|
||||
|
||||
var XMPlayer = window.XMPlayer;
|
||||
var was_init = false
|
||||
|
||||
// https://stackoverflow.com/questions/16245767/creating-a-blob-from-a-base64-string-in-javascript
|
||||
function b64toBlob(base64) {
|
||||
const decoded = atob(base64);
|
||||
const uInt8Array = new Uint8Array(decoded.length);
|
||||
for (let i = 0; i < decoded.length; ++i)
|
||||
uInt8Array[i] = decoded.charCodeAt(i);
|
||||
return new Blob([uInt8Array]);
|
||||
}
|
||||
|
||||
async function decompressGzippedBase64(str) {
|
||||
const ds = new DecompressionStream(`gzip`);
|
||||
const decompressedStream = b64toBlob(str).stream().pipeThrough(ds);
|
||||
return new Response(decompressedStream).blob();
|
||||
}
|
||||
|
||||
window.loadAndPlayTrack = function(url) {
|
||||
if (!was_init) {
|
||||
XMPlayer.init();
|
||||
was_init = true;
|
||||
}
|
||||
var request = new XMLHttpRequest();
|
||||
request.responseType = `text`;
|
||||
request.open('GET', url);
|
||||
request.send();
|
||||
request.onload = async(_) => {
|
||||
if (request.readyState === 4 && request.status === 200) {
|
||||
XMPlayer.stop();
|
||||
XMPlayer.load(await (await decompressGzippedBase64(request.response)).arrayBuffer());
|
||||
XMPlayer.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
})(window, document)
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
"""
|
||||
page += HEAD_EMBED
|
||||
|
||||
page += """
|
||||
<h3 id="articles">Tracks</h3>
|
||||
<p>.xm module tracks of my own. Btw, they're playable in browser :3</p>
|
||||
<p>Note that some files are rendered incorrectly.</p>
|
||||
<hr/>
|
||||
"""
|
||||
|
||||
for _, _, files in walk(argv[1]):
|
||||
files.sort()
|
||||
for f in files:
|
||||
# note: Base64 gzip encoded data is expected.
|
||||
if not f.endswith('.xm.txt'):
|
||||
continue
|
||||
page += (
|
||||
f""" <div><p style="display: inline;">{f[:-4]}</p><button style="float: right;" onclick="window.loadAndPlayTrack('/tracks/{f}')">play</button></div>\n"""
|
||||
" <hr/>\n"
|
||||
)
|
||||
break
|
||||
|
||||
page += TAIL_EMBED
|
||||
|
||||
page += """</div>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
print(page)
|
Loading…
Reference in New Issue
Block a user