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 ###
|
### Assembly ###
|
||||||
This is produced by godbolt, which apparently has AVX512 extensions, so, it's extremely compact.
|
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:
|
For 32bit floating point:
|
||||||
```asm
|
```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.
|
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 ###
|
### Edits ###
|
||||||
- Reordered to use packed vectors without swizzling when possible.
|
- Reordered to use packed vectors without swizzling when possible.
|
||||||
- Eliminated redundant computations.
|
- 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
|
done
|
||||||
|
|
||||||
./tools/feed_generator.py ./articles/ https://mjestecko.neocities.org/ > ./html/feed.xml
|
./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 {
|
html {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-family: "Charter","Georgia",'Times New Roman',serif;
|
font-family: "Charter","Georgia",'Times New Roman',serif;
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
|
background-color: var(--bg-color);
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
}
|
}
|
||||||
article, .container {
|
article, .container {
|
||||||
@ -29,7 +47,7 @@ html {
|
|||||||
margin: 0.9em 0px 0.9em;
|
margin: 0.9em 0px 0.9em;
|
||||||
}
|
}
|
||||||
pre, code {
|
pre, code {
|
||||||
background-color: #eeeeff;
|
background-color: var(--bg-color);
|
||||||
line-height: normal;
|
line-height: normal;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
@ -46,7 +64,7 @@ html {
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
background-color: #f0f0f0;
|
background-color: var(--bg-color);
|
||||||
border: 1px solid #bbbbdd;
|
border: 1px solid #bbbbdd;
|
||||||
}
|
}
|
||||||
nav li:first-child {
|
nav li:first-child {
|
||||||
@ -66,10 +84,10 @@ html {
|
|||||||
background-color: #e0e0e0;
|
background-color: #e0e0e0;
|
||||||
}
|
}
|
||||||
nav a:link {
|
nav a:link {
|
||||||
color: #44d;
|
color: var(--link-color);
|
||||||
}
|
}
|
||||||
nav a:visited {
|
nav a:visited {
|
||||||
color: #44d;
|
color: var(--link-color);
|
||||||
}
|
}
|
||||||
nav a.here {
|
nav a.here {
|
||||||
background-color: #e0e0e0;
|
background-color: #e0e0e0;
|
||||||
|
@ -25,19 +25,24 @@ page = f"""Personal blog of one {choice(ADJECTIVES)} Veclav Talica.
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# todo: Sort by date first.
|
artciles = {}
|
||||||
for root, dirs, _ in walk(argv[1]):
|
for root, dirs, _ in walk(argv[1]):
|
||||||
for d in dirs:
|
for d in dirs:
|
||||||
metadata = parse_metadata(path.abspath(root + '/' + d + "/page.mmd"))
|
metadata = parse_metadata(path.abspath(root + '/' + d + "/page.mmd"))
|
||||||
article = urllib.parse.quote(d)
|
article = urllib.parse.quote(d)
|
||||||
page += (
|
artciles[article] = {
|
||||||
f"""[{metadata.get("Title", "No title given! What a clusterfuck!")}](/articles/{article}.html)\n\n"""
|
"metadata": metadata
|
||||||
f""">{metadata.get("Brief", "")}\n\n"""
|
}
|
||||||
)
|
|
||||||
if "Tags" in metadata:
|
|
||||||
page += f""">*{','.join(metadata["Tags"])}*\n---\n"""
|
|
||||||
break
|
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"""
|
||||||
|
)
|
||||||
|
|
||||||
curtime = time.gmtime(int(time.time()))
|
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"
|
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 = """
|
HEAD_EMBED = """
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<header>
|
<nav class="custom-nav">
|
||||||
<nav>
|
<ul>
|
||||||
<strong>mjestečko</strong> /
|
<li><a href="/"><strong>mjestečko</strong></a></li>
|
||||||
<a href="/">main</a> /
|
<li><a href="https://git.poto.cafe/veclavtalica/mjestecko">source</a></li>
|
||||||
<a href="https://git.poto.cafe/veclavtalica/mjestecko">source</a> /
|
<li><a href="/feed.xml">rss</a></li>
|
||||||
<a href="/tracks.html">tracks</a> /
|
<li><a href="/articles/mjestečko.html">about</a></li>
|
||||||
<a href="/feed.xml">rss</a> /
|
|
||||||
<a href="/articles/mjestečko.html">about</a>
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
NOTICE = """
|
NOTICE = """
|
||||||
---
|
<footer>
|
||||||
*Remember, - all you see here is free for use for any purpose benefiting the humanity as a whole.*
|
<a href="#top">Take me home ↑</a>
|
||||||
|
</footer>
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -55,5 +53,11 @@ WEEKDAYS = {
|
|||||||
6: "Sunday"
|
6: "Sunday"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def mixin_tag(content: str, tag: str) -> str:
|
||||||
|
return f"""<{tag}>
|
||||||
|
{content}</{tag}>
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
def wrap_page(page: str) -> str:
|
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