diff --git a/src/duckstation-qt/duckstation-qt.vcxproj b/src/duckstation-qt/duckstation-qt.vcxproj
index 4f17e2a6c..c2479fb40 100644
--- a/src/duckstation-qt/duckstation-qt.vcxproj
+++ b/src/duckstation-qt/duckstation-qt.vcxproj
@@ -104,6 +104,9 @@
+
+
+
{28F14272-0EC4-41BB-849F-182ADB81AF70}
Win32Proj
diff --git a/src/duckstation-qt/duckstation-qt.vcxproj.filters b/src/duckstation-qt/duckstation-qt.vcxproj.filters
index 525f2f987..38de9472d 100644
--- a/src/duckstation-qt/duckstation-qt.vcxproj.filters
+++ b/src/duckstation-qt/duckstation-qt.vcxproj.filters
@@ -48,4 +48,7 @@
+
+
+
\ No newline at end of file
diff --git a/src/duckstation-qt/qt5.natvis b/src/duckstation-qt/qt5.natvis
new file mode 100644
index 000000000..d7d8854f2
--- /dev/null
+++ b/src/duckstation-qt/qt5.natvis
@@ -0,0 +1,712 @@
+
+
+
+
+
+
+
+ {{ x = {xp}, y = {yp} }}
+
+ - xp
+ - yp
+
+
+
+
+ {{ x = {x1}, y = {y1}, width = {x2 - x1 + 1}, height = {y2 - y1 + 1} }}
+
+ - x1
+ - y1
+ - x2 - x1 + 1
+ - y2 - y1 + 1
+
+
+
+
+ {{ x = {xp}, y = {yp}, width = {w}, height = {h} }}
+
+ - xp
+ - yp
+ - w
+ - h
+
+
+
+
+
+ {{ width = {wd}, height = {ht} }}
+
+ - wd
+ - ht
+
+
+
+
+
+ {{ start point = {pt1}, end point = {pt2} }}
+
+
+ {pt1}
+
+ pt1
+
+
+
+ {pt2}
+
+ pt2
+
+
+
+
+
+
+
+ {{ size = {d->size} }}
+
+ - d->ref.atomic._q_value
+
+ d->size
+ (QPoint*)((reinterpret_cast<char*>(d)) + d->offset)
+
+
+
+
+
+ {{ size = {d->size} }}
+
+ -
+ d->size > 0
+ && ((((QPointF*)((reinterpret_cast<char*>(d)) + d->offset)[0]).xp
+ == (((QPointF*)((reinterpret_cast<char*>(d)) + d->offset)[d->size - 1]).xp)
+ && ((((QPointF*)((reinterpret_cast<char*>(d)) + d->offset)[0]).yp
+ == (((QPointF*)((reinterpret_cast<char*>(d)) + d->offset)[d->size - 1]).yp)
+
+ - d->ref.atomic._q_value
+
+ d->size
+ (QPointF*)((reinterpret_cast<char*>(d)) + d->offset)
+
+
+
+
+
+ {{ x = {xp}, y = {yp} }}
+
+ - xp
+ - yp
+
+
+
+
+ {{ x = {xp}, y = {yp}, z = {zp} }}
+
+ - xp
+ - yp
+ - zp
+
+
+
+
+ {{ x = {xp}, y = {yp}, z = {zp}, w = {wp} }}
+
+ - xp
+ - yp
+ - zp
+ - wp
+
+
+
+
+
+ {{ m11 = {_m11}, m12 = {_m12}, m21 = {_m21}, m22 = {_m22}, ... }}
+
+
+ - _m11
+ - _m12
+ - _m21
+ - _m22
+ - _dx
+ - _dy
+
+
+
+
+
+ {{ m11 = {m[0][0]}, m12 = {m[1][0]}, m13 = {m[2][0]}, m14 = {m[3][0]}, ... }}
+
+
+ - m[0][0]
+ - m[1][0]
+ - m[2][0]
+ - m[3][0]
+ - m[0][1]
+ - m[1][1]
+ - m[2][1]
+ - m[3][1]
+ - m[0][2]
+ - m[1][2]
+ - m[2][2]
+ - m[3][2]
+ - m[0][3]
+ - m[1][3]
+ - m[2][3]
+ - m[3][3]
+
+
+
+
+
+ {{ horizontal = {static_cast<Policy>(bits.horPolicy)}, vertical = {static_cast<Policy>(bits.verPolicy)}, type = {ControlType(1 << bits.ctype)} }}
+
+
+
+ QSizePolicy::Policy::{static_cast<Policy>(bits.verPolicy)}
+
+
+ QSizePolicy::Policy::{static_cast<Policy>(bits.horPolicy)}
+
+
+ QSizePolicy::ControlType::{ControlType(1 << bits.ctype)}
+
+
+
+ Qt::Vertical (2)
+
+
+ Qt::Horizontal (1)
+
+
+ - static_cast<int>(bits.verStretch)
+ - static_cast<int>(bits.horStretch)
+ - bits.hfw == 1
+ - bits.wfh == 1
+
+
+
+
+ {ucs,c}
+ ucs,c
+
+ - ucs > 0xff ? '\0' : char(ucs),c
+ - ucs,c
+
+
+
+
+ {((reinterpret_cast<unsigned short*>(d)) + d->offset / 2),sub}
+ ((reinterpret_cast<unsigned short*>(d)) + d->offset / 2),sub
+
+ - d->size
+ - d->ref.atomic._q_value
+
+ d->size
+ ((reinterpret_cast<unsigned short*>(d)) + d->offset / 2),c
+
+
+
+
+
+ {((reinterpret_cast<char*>(d)) + d->offset),sb}
+ ((reinterpret_cast<char*>(d)) + d->offset),sb
+
+ - d->size
+ - d->ref.atomic._q_value
+
+ d->size
+ ((reinterpret_cast<char*>(d)) + d->offset),c
+
+
+
+
+
+ {{ size = {(d.d->size << 3) - *((reinterpret_cast<char*>(d.d)) + d.d->offset)} }}
+
+ - d.d->ref.atomic._q_value
+
+ (d.d->size << 3) - *((reinterpret_cast<char*>(d.d)) + d.d->offset)
+
+ (*(reinterpret_cast<const unsigned char*>((reinterpret_cast<char*>(d.d)) + d.d->offset) + 1
+ + ($i >> 3)) & (1 << ($i & 7))) != 0
+
+
+
+
+
+
+
+ {{ size = {s} }}
+
+ - a
+
+ s
+ ptr
+
+
+
+
+
+ {{ julian day = {jd} }}
+
+
+
+
+ {{ millisecond = {mds} }}
+ {{ milliseconds = {mds} }}
+
+ - mds / 3600000, d
+ - mds / 3600000, d
+ - (mds % 3600000) / 60000, d
+ - (mds % 3600000) / 60000, d
+ - (mds / 1000) % 60, d
+ - (mds / 1000) % 60, d
+ - mds % 1000, d
+ - mds % 1000, d
+
+
+
+
+ {d.pattern}
+
+
+
+
+ - ref._q_value
+
+
+
+
+ strong reference to shared pointer of type {"$T1"}
+
+ - value == 0
+ - d->weakref._q_value
+ - d->strongref._q_value
+
+
+
+
+ pointer to implicit shared object of type {"$T1"}
+
+ d
+
+
+
+
+ pointer to explicit shared object of type {"$T1"}
+
+ d
+
+
+
+
+ guarded pointer to subclass of QObject of type {"$T1"}
+
+ - wp.d == 0 || wp.d->strongref._q_value == 0 || wp.value == 0
+
+
+
+
+ weak reference to shared pointer of type {"$T1"}
+
+ - d == 0 || d->strongref._q_value == 0 || value == 0
+ - d->weakref._q_value
+ - d->strongref._q_value
+
+
+
+
+ scoped pointer to a dynamically allocated object of type {"$T1"}
+
+ - !d
+
+
+
+
+ scoped pointer to dynamically allocated array of objects of type {"$T1"}
+
+ - !d
+
+
+
+
+ ({first}, {second})
+
+ - first
+ - second
+
+
+
+
+
+ {{ size = {d->size} }}
+
+ - d->ref.atomic._q_value
+
+ d->size
+ ($T1*)((reinterpret_cast<char*>(d)) + d->offset)
+
+
+
+
+
+
+
+ {{ size = {d->end - d->begin} }}
+
+ - d->ref.atomic._q_value
+
+ d->end - d->begin
+ *reinterpret_cast<$T1*>((sizeof($T1) > sizeof(void*))
+ ? reinterpret_cast<Node*>(d->array + d->begin + $i)->v
+ : reinterpret_cast<$T1*>(d->array + d->begin + $i))
+
+
+
+
+
+
+ {{ size = {d->size} }}
+
+ - d->ref.atomic._q_value
+
+ d->size
+ d->n
+ n
+ (*(QLinkedListNode<$T1>*)this).t
+
+
+
+
+
+ ({key}, {value})
+
+ - key
+ - value
+
+
+
+
+
+ {{ size = {d->size} }}
+
+ - d->ref.atomic._q_value
+
+ d->size
+ d->header.left
+ left
+ right
+ *((QMapNode<$T1,$T2>*)this)
+
+
+
+
+
+ (empty)
+ ({key}, {value})
+
+ - key
+ - value
+
+
+
+
+
+ {{ size = {d->size} }}
+
+ - d->ref.atomic._q_value
+
+ d->numBuckets
+ *((QHashNode<$T1,$T2>*)d->buckets[$i])
+
+
+
+
+
+ (empty)
+ ({key})
+
+ - key
+
+
+
+
+ {{ size = {q_hash.d->size} }}
+
+ q_hash
+
+
+
+
+ ({*keyPtr}, {*t})
+
+ - *keyPtr
+ - *t
+
+
+
+
+ {{ size = {hash.d->size} }}
+
+ - mx
+ - total
+ - hash.d->ref.atomic._q_value
+
+ hash.d->size
+ f
+ n
+ *((Node*)this)
+
+
+
+
+
+
+
+ Invalid
+ {d.data.b}
+ {d.data.i}
+ {d.data.u}
+ {d.data.ll}
+ {d.data.ull}
+ {d.data.d}
+ {d.data.c}
+
+ {*((QMap<QString,QVariant>*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))}
+
+
+ {*((QList<QVariant>*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))}
+
+
+ {*((QString*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))}
+
+
+ {*((QStringList*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))}
+
+
+ {*((QByteArray*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))}
+
+
+ {*((QBitArray*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))}
+
+
+ {*((QDate*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))}
+
+
+ {*((QTime*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))}
+
+ DateTime
+ Url
+ Locale
+
+ {*((QRect*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))}
+
+
+ {*((QRectF*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))}
+
+
+ {*((QSize*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))}
+
+
+ {*((QSizeF*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))}
+
+
+ {*((QLine*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))}
+
+
+ {*((QLineF*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))}
+
+
+ {*((QPoint*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))}
+
+
+ {*((QPointF*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))}
+
+ RegExp
+ RegularExpression
+
+ {*((QHash<QString,QVariant>*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))}
+
+ EasingCurve
+ Uuid
+ ModelIndex
+ LastCoreType
+ Font
+ Pixmap
+ Brush
+ Color
+ Palette
+ Image
+ Polygon
+ Region
+ Bitmap
+ Cursor
+ KeySequence
+ Pen
+ TextLength
+ TextFormat
+ Matrix
+ Transform
+ Matrix4x4
+ Vector2D
+ Vector3D
+ Vector4D
+ Quaternion
+ PolygonF
+ Icon
+ LastGuiType
+ SizePolicy
+ UserType
+ LastType
+
+
+
+
+
+ d.data.c
+
+
+ *((QString*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))
+
+
+
+ *((QByteArray*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))
+
+
+
+
+
+
+
+
+ *((QMap<QString,QVariant>*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))
+
+
+ *((QList<QVariant>*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))
+
+
+ *((QString*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))
+
+
+ *((QStringList*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))
+
+
+ *((QByteArray*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))
+
+
+ *((QBitArray*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))
+
+
+ *((QDate*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))
+
+
+ *((QTime*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))
+
+
+ *((QRect*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))
+
+
+ *((QRectF*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))
+
+
+ *((QSize*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))
+
+
+ *((QSizeF*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))
+
+
+ *((QLine*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))
+
+
+ *((QLineF*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))
+
+
+ *((QPoint*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))
+
+
+ *((QPointF*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))
+
+
+ *((QHash<QString,QVariant>*)(d.is_shared ? d.data.shared->ptr
+ : reinterpret_cast<const void *>(&d.data.ptr)))
+
+
+
+
+
+
+