vault backup: 2025-04-18 23:10:56

This commit is contained in:
sShemet
2025-04-18 23:10:56 +05:00
parent 8f4ceebaf3
commit 491d7fc92a
15 changed files with 421 additions and 17 deletions

View File

@@ -41,12 +41,12 @@
"state": {
"type": "markdown",
"state": {
"file": "PERSONAL PROJECTS/PSX code - modules load and exec.md",
"file": "PERSONAL PROJECTS/PS1 DOCS/PS1 Geometry Transformation Engine.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "PSX code - modules load and exec"
"title": "PS1 Geometry Transformation Engine"
}
}
],
@@ -207,17 +207,21 @@
},
"active": "dd912cc876184c4f",
"lastOpenFiles": [
"PERSONAL PROJECTS/PSX code texture load unpack show and fade.md",
"PERSONAL PROJECTS/PSX code - modules load and exec.md",
"PERSONAL PROJECTS/PS1 Gamepad.md",
"PERSONAL PROJECTS/PSX code - Load texture from SECTOR!.md",
"PERSONAL PROJECTS/PSX code - Texture show from file.md",
"PERSONAL PROJECTS/PS1 Vblank.md",
"PERSONAL PROJECTS/PS1 MDEC.md",
"PERSONAL PROJECTS/PS1 DMA.md",
"PERSONAL PROJECTS/PS1 Gpu-DMA.md",
"PERSONAL PROJECTS/PS1 DMA CD-ROM.md",
"PERSONAL PROJECTS/LZSS C++ Lib.md",
"PERSONAL PROJECTS/PS1 DOCS/LZSS C++ Lib.md",
"PERSONAL PROJECTS/PS1 DOCS/PS1 Geometry Transformation Engine.md",
"PERSONAL PROJECTS/PS1 DOCS/PS1 Ordering table.md",
"PERSONAL PROJECTS/PS1 DOCS",
"PERSONAL PROJECTS/PS1 DOCS/PSX code texture load unpack show and fade.md",
"PERSONAL PROJECTS/PS1 DOCS/PSX code inline asm.md",
"PERSONAL PROJECTS/PS1 DOCS/PSX code - Texture show from file.md",
"PERSONAL PROJECTS/PS1 DOCS/PSX code - modules load and exec.md",
"PERSONAL PROJECTS/PS1 DOCS/PS1 Gamepad.md",
"PERSONAL PROJECTS/PS1 DOCS/PSX code - Load texture from SECTOR!.md",
"PERSONAL PROJECTS/PS1 DOCS/PS1 Vblank.md",
"PERSONAL PROJECTS/PS1 DOCS/PS1 MDEC.md",
"PERSONAL PROJECTS/PS1 DOCS/PS1 DMA.md",
"PERSONAL PROJECTS/PS1 DOCS/PS1 Gpu-DMA.md",
"PERSONAL PROJECTS/PS1 DOCS/PS1 DMA CD-ROM.md",
"WORK & PROJECTS/Mol/Ideas/Все идеи для Моли.md",
"WORK & PROJECTS/Mol/Серверы/mail.mol-soft.ru.md",
"WORK & PROJECTS/Mol/Документы для ТЗ ЛИМС/СМК/КУек_лист_10_ошибок_УД_скачивание.pdf",
@@ -239,18 +243,14 @@
"WORK & PROJECTS/Mol/Планы и диаграммы/Alfa Cloud",
"WORK & PROJECTS/Mol/Серверы/git.moldev.ru.md",
"WORK & PROJECTS/Ulab/передача сформированных заявки и протокола как ссылку или файл.md",
"WORK & PROJECTS/Ulab/Доступы к точкам.md",
"Структура объектов испытаний.png",
"Схема связей юрлиц и адресов.png",
"Структура объектов испытаний.png.0.pdnSave",
"WORK & PROJECTS/Mol/Документы для ТЗ ЛИМС/АФ-01 Альбом форм.pdf",
"WORK & PROJECTS/Mol/Серверы/Схема инфраструктуры.canvas",
"WORK & PROJECTS/Ulab/Московский проект/ACCESS TABLE.md",
"WORK & PROJECTS/Ulab/Автобан/щебень 5-20.xlsx",
"WORK & PROJECTS/Ulab/Автобан/щебень 20-40.xlsx",
"WORK & PROJECTS/Ulab/Автобан/песок природный.xls",
"WORK & PROJECTS/Ulab/Автобан/грунт песчаный.xlsx",
"WORK & PROJECTS/Mol/Серверы/Alfa cloud prod_canvas2doc-data/newdoc-node_f3d0e9a6d4d8e6a7_fromCanvas.md",
"WORK & PROJECTS/Mol/Серверы/Alfa cloud prod.canvas",
"PERSONAL PROJECTS/P2EP/cdRead.canvas",
"P2EP/cdRead.canvas",

View File

@@ -0,0 +1,144 @@
### **Математический процессор (GTE) в PlayStation 1**
**Geometry Transformation Engine (GTE)** — это сопроцессор в PS1, отвечающий за ускорение математических операций, критичных для 3D-графики. Он работает параллельно с основным CPU (R3000A) и оптимизирован для:
1. **Перемножения матриц**
2. **Вращения и трансформации вершин**
3. **Расчёта перспективы и освещения**
---
## **1. Основные функции GTE**
### **1.1. Быстрые матричные операции**
GTE умеет:
- Умножать **матрицу 3×3** на вектор (для поворота объектов).
- Вычислять **матрицу модели-вида** (Model-View).
- Обновлять **нормали объектов** для освещения.
**Пример**: Поворот вершины:
```mips
# Вход: матрица вращения в $a0, вершина (x,y,z) в $a1
lw $t0, 0($a0) # Загружаем элемент матрицы
lw $t1, 0($a1) # Загружаем X вершины
mult $t0, $t1 # Умножаем (GTE делает это за 1 такт)
mflo $t2 # Результат
```
---
### **1.2. Перспективное преобразование**
GTE вычисляет **экранные координаты (X,Y)** из 3D-пространства:
1. Учитывает **камеру** (матрица вида).
2. Применяет **перспективу** (деление на Z).
3. Оптимизирует расчёт **FOV** (поля зрения).
**Формула**:
\[
X_{screen} = \frac{X_{3D} \cdot scale}{Z_{3D}} + center\_x
\]
---
### **1.3. Освещение и цвет**
- GTE рассчитывает **интенсивность света** для вершин.
- Поддерживает **до 3 источников света** (накладывает цвета).
- Работает с **нормалями** (через скалярное произведение).
**Пример**:
```mips
# Нормаль в $a0, свет в $a1
dp $t0, $a0, $a1 # Скалярное произведение (GTE)
sll $t0, 8 # Яркость = 0..255
```
---
## **2. Зачем нужно перемножение матриц?**
Матрицы используются для:
1. **Поворота объектов**
```math
\begin{bmatrix}
\cosθ & -\sinθ & 0 \\
\sinθ & \cosθ & 0 \\
0 & 0 & 1 \\
\end{bmatrix} \cdot
\begin{bmatrix} X \\ Y \\ Z \end{bmatrix}
```
2. **Масштабирования**
```math
\begin{bmatrix}
S_x & 0 & 0 \\
0 & S_y & 0 \\
0 & 0 & S_z \\
\end{bmatrix}
```
3. **Смещения (трансляции)**
```math
\begin{bmatrix} 1 & 0 & T_x \\ 0 & 1 & T_y \\ 0 & 0 & 1 \end{bmatrix}
```
**GTE делает это за 1-2 такта** (вместо 10+ тактов на R3000A).
---
## **3. Пример: поворот куба на PS1**
### **Код на C с ассемблерными вставками**
```c
#include <libgte.h>
typedef struct { short x, y, z; } Vertex;
void rotate_vertex(Vertex *v, int angle) {
MATRIX rot_matrix;
int sin, cos;
// Получаем синус/косинус угла (через GTE)
gte_ldsin(angle, &sin);
gte_ldcos(angle, &cos);
// Заполняем матрицу поворота вокруг Z
rot_matrix.m[0][0] = cos; rot_matrix.m[0][1] = -sin;
rot_matrix.m[1][0] = sin; rot_matrix.m[1][1] = cos;
// Умножаем матрицу на вершину (через GTE)
gte_rtps(v->x, v->y, v->z, &rot_matrix, &v->x, &v->y, &v->z);
}
```
---
## **4. Оптимизации через GTE**
### **4.1. Пакетная обработка**
- GTE может обрабатывать **до 3 вершин за инструкцию** (`rtpt`).
- Пример для треугольника:
```mips
rtpt # Поворот 3 вершин сразу
nop
```
### **4.2. Отложенные вычисления**
- Команды `nclip` и `avsz3` считают **площадь полигона** и **Z-буфер** без CPU.
### **4.3. Интеграция с GPU**
- Результаты GTE (экранные X,Y,Z) передаются в **GPU** через DMA.
- Это ускоряет рендеринг в 5-10 раз.
---
## **5. Сравнение с современными GPU**
| Функция | PS1 (GTE) | Современный GPU |
|-----------------------|----------------|----------------|
| Матричные операции | 1-2 такта | 1 такт |
| Макс. источников света| 3 | 100+ |
| Поддержка шейдеров | Нет | Да |
---
## **6. Итог**
- **GTE** — это «сердце» 3D-графики PS1, отвечающее за:
- Поворот, масштабирование, перспективу.
- Освещение и цвет.
- **Без GTE** игры вроде *Tekken 3* или *Metal Gear Solid* работали бы на **1-2 FPS**.
- Оптимизация под GTE — ключ к плавному рендерингу на PS1.
Для глубокого изучения смотрите [GTE Technical Reference](http://problemkaputt.de/psx-spx.htm#gtegeometrytransformationengine).

View File

@@ -0,0 +1,137 @@
### **Сортировка полигонов на PlayStation 1 (PS1)**
PS1 не имеет аппаратной поддержки **Z-буфера** (depth buffer), поэтому правильный порядок отрисовки полигонов (сортировка) критически важен для корректного отображения 3D-сцен. Вот как это реализовано:
---
## **1. Основные методы сортировки**
### **1.1. Ordering Table (OT)**
**Ordering Table** — это главный механизм сортировки на PS1.
Работает по принципу **связного списка** в VRAM, где полигоны группируются по расстоянию.
#### **Как это работает?**
1. **Инициализация OT**:
- Создаётся массив указателей (например, на 256 или 1024 элемента).
- Каждый элемент соответствует диапазону глубин (Z-значений).
2. **Добавление примитивов**:
- Для каждого полигона вычисляется **Z-координата** (например, средняя точка).
- По Z-значению выбирается **ячейка OT** (чем дальше объект, тем меньше индекс).
- Полигон добавляется в список для этой ячейки.
3. **Рендеринг**:
- OT обрабатывается **от дальних к ближним** ячейкам (от 0 до N).
- Все примитивы в одной ячейке рисуются в порядке добавления.
#### **Пример кода (PsyQ SDK)**
```c
#include <libgpu.h>
#define OT_LEN 256 // Размер Ordering Table
uint32_t ot[OT_LEN]; // Сама таблица
void init_ot() {
ClearOTagR(ot, OT_LEN); // Очистка OT
}
void add_polygon(POLY_F4 *poly, int z) {
// Вычисляем индекс в OT (0 = дальний, OT_LEN-1 = ближний)
int ot_entry = (z >> 8) & (OT_LEN - 1); // Простейшее масштабирование Z
// Добавляем полигон в OT
addPrim(ot + ot_entry, poly);
}
void render_frame() {
DrawOTag(ot + (OT_LEN - 1)); // Рендеринг OT (от ближних к дальним)
}
```
---
### **1.2. Сортировка по Bounding Box**
Для сложных объектов (например, моделей) используется **сортировка по ограничивающему объёму**:
1. Вычисляется **сфера или AABB** (коробка), охватывающая объект.
2. Сортируются **центры сфер** по Z-координате.
#### **Псевдокод**
```c
struct Object {
int center_z;
POLY_F4 *polys;
};
void sort_objects(Object *objs, int count) {
qsort(objs, count, sizeof(Object), compare_by_z);
}
int compare_by_z(const void *a, const void *b) {
return ((Object*)a)->center_z - ((Object*)b)->center_z;
}
```
---
### **1.3. Priority Groups**
Некоторые игры (например, *Crash Bandicoot*) используют **приоритетные группы**:
- Полигоны делятся на **статические** (уровень) и **динамические** (персонажи).
- Статические рисуются через OT, динамические — поверх них.
---
## **2. Оптимизации**
### **2.1. Z-Сортировка только для прозрачных объектов**
- Непрозрачные полигоны рисуются **без сортировки** (через алгоритм художника).
- Прозрачные (с полупрозрачностью) сортируются **строго от дальних к ближним**.
### **2.2. Двойная OT**
- **Одна OT для непрозрачных**, вторая — **для прозрачных** полигонов.
- Позволяет уменьшить накладные расходы.
### **2.3. Субпиксельная корректировка**
- Для борьбы с **Z-файтингом** (мерцание полигонов) используется:
- Случайное смещение Z (`z += rand() % 4`).
- Принудительный порядок для мелких объектов.
---
## **3. Пример для игры**
Допустим, у нас есть:
- **10 коробок** на разных расстояниях.
- **1 полупрозрачный полигон** (вода).
#### **Код рендеринга**
```c
// 1. Инициализация
init_ot();
// 2. Добавление непрозрачных полигонов (коробки)
for (int i = 0; i < 10; i++) {
add_polygon(&boxes[i], boxes[i].z);
}
// 3. Добавление прозрачного полигона (вода)
add_polygon(&water_poly, water_z);
// 4. Рендеринг
render_frame();
```
---
## **4. Проблемы и решения**
| Проблема | Решение |
|------------------------|----------------------------------|
| **Мерцание полигонов** | Субпиксельная корректировка Z. |
| **Низкая производительность** | Уменьшение размера OT. |
| **Неправильный порядок** | Ручная настройка приоритетов. |
---
## **5. Итог**
- **Ordering Table** — основа сортировки на PS1.
- **Для сложных сцен** комбинируют OT, Bounding Box и приоритетные группы.
- **Оптимизации** нужны для борьбы с артефактами.
Этот подход использовался в играх типа *Tekken 3* и *Resident Evil*. Для глубокого понимания изучите [документацию PsyQ](http://psx.arthus.net/sdk/PsyQ/DOCS/).

View File

@@ -0,0 +1,123 @@
Вот готовая программа для **PlayStation 1**, которая использует **MIPS-ассемблерные вставки** для сложения двух чисел через указатели. Результат возвращается в переменную основной программы.
---
### **1. Полный код (MAIN.C)**
```c
#include <stdio.h>
#include <libetc.h>
// Объявляем ассемблерную функцию
int add_numbers_asm(int *a, int *b, int *result);
int main() {
int num1 = 5;
int num2 = 7;
int result = 0;
// Вызываем ассемблерную функцию с указателями
add_numbers_asm(&num1, &num2, &result);
// Выводим результат
FntPrint("Result: %d + %d = %d\n", num1, num2, result);
FntFlush(-1);
while (1) {
VSync(0);
}
return 0;
}
// Реализация на MIPS-ассемблере
int add_numbers_asm(int *a, int *b, int *result) {
int ret;
asm volatile (
"lw $t0, 0(%1) \n" // Загружаем *a в $t0
"lw $t1, 0(%2) \n" // Загружаем *b в $t1
"add $t2, $t0, $t1 \n" // Складываем: $t2 = $t0 + $t1
"sw $t2, 0(%3) \n" // Сохраняем результат по адресу *result
"move %0, $t2 \n" // Возвращаем результат через регистр
: "=r" (ret) // Выходные операнды
: "r" (a), "r" (b), "r" (result) // Входные операнды
: "$t0", "$t1", "$t2" // Разрушаемые регистры
);
return ret;
}
```
---
### **2. Как это работает?**
1. **Передача указателей в ассемблер**
Функция `add_numbers_asm` принимает три указателя:
- `a` — адрес первого числа,
- `b` — адрес второго числа,
- `result` — адрес для сохранения результата.
2. **Ассемблерная вставка** (`asm volatile`):
- `lw` — загружает значения из памяти по указателям.
- `add` — складывает числа.
- `sw` — сохраняет результат по адресу `result`.
- `move` — возвращает значение через регистр.
3. **Доступ к результату**
Результат будет:
- В переменной `result` (через указатель).
- В возвращаемом значении функции (если нужно).
---
### **3. Компиляция и запуск**
1. Скомпилируйте через **PsyQ SDK**:
```bash
ccpsx MAIN.C -o ADD_DEMO.EXE
```
2. Запишите на диск и запустите на эмуляторе или консоли.
На экране появится:
```
Result: 5 + 7 = 12
```
---
### **4. Важные нюансы**
- **Регистры MIPS**:
- `$t0``$t9` — временные регистры (можно использовать без сохранения).
- `$s0``$s7` — должны сохраняться (если используются).
- **Разрушаемые регистры**:
Указаны в конце `asm volatile` (чтобы компилятор не использовал их для оптимизации).
- **Опасность**:
Если передать **неверные указатели**, PS1 уйдёт в **краш** (нет защиты памяти).
---
### **5. Пример с глобальными переменными**
Если нужно работать с глобальными переменными напрямую:
```c
int global_num1 = 10;
int global_num2 = 20;
void add_globals_asm() {
asm volatile (
"la $t0, global_num1 \n" // Загружаем адрес global_num1
"lw $t1, 0($t0) \n" // Читаем значение
"la $t0, global_num2 \n"
"lw $t2, 0($t0) \n"
"add $t1, $t1, $t2 \n"
"sw $t1, 0($t0) \n" // Сохраняем сумму в global_num2
);
}
```
---
### **6. Итог**
- **Ассемблерные вставки** дают полный контроль над железом PS1.
- **Указатели** передаются через регистры (`$a0``$a3` в MIPS).
- **Результат** можно получить через память или возвращаемое значение.
Этот подход используется в оптимизированных частях игр (например, в рендеринге или физике).