Files
SergObsidian/PERSONAL PROJECTS/PS1 Gpu-DMA.md
2025-04-18 21:40:47 +05:00

134 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

В PlayStation 1 (PS1) передача видеокоманд через DMA в GPU — это ключевой механизм для эффективного рендеринга. Разберём процесс детально, включая работу с памятью.
---
## **1. Как передаются видеокоманды через DMA?**
GPU PS1 не имеет собственного набора инструкций — он выполняет **примитивные команды**, переданные CPU. Эти команды организуются в **цепочку DMA** (Display List), которая указывает, что и как рисовать.
### **1.1. Структура цепочки команд**
Каждая команда в цепочке состоит из:
- **Слова-заголовка** (указывает тип примитива: полигон, спрайт, настройка и т. д.).
- **Данных** (координаты, цвета, текстуры).
Пример команды для отрисовки треугольника:
```c
typedef struct {
uint32_t header; // Тип примитива (например, POLY_F3)
uint16_t x1, y1; // Координаты
uint16_t x2, y2;
uint16_t x3, y3;
uint8_t r, g, b; // Цвет
} GPUPrimitive;
```
### **1.2. Передача через DMA**
1. **CPU формирует цепочку команд** в основной RAM (например, массив структур).
2. **Адрес этой цепочки** передаётся в GPU через DMA.
- Используется порт **`GP0`** (для команд) и **`GP1`** (для управления).
3. **DMA-контроллер** (канал **GPU**) копирует данные из RAM в GPU.
**Код на ассемблере (пример):**
```asm
; Запись адреса цепочки в DMA
li a0, 0x1F8010A0 ; Адрес регистра DMA_GPU (канал 2)
la a1, command_list ; Адрес цепочки команд в RAM
sw a1, 0(a0) ; Записываем адрес
; Настройка DMA
li a0, 0x1F8010A4
li a1, 0x01000200 ; Размер блока + флаги (например, 0x200 байт)
sw a1, 0(a0)
; Запуск DMA
li a0, 0x1F8010A8
li a1, 0x01000001 ; Включить DMA
sw a1, 0(a0)
```
---
## **2. Как GPU читает команды?**
### **2.1. Отсутствие собственной памяти для команд**
У GPU **нет отдельной памяти для хранения команд** (в отличие от современных GPU). Он:
1. **Читает команды напрямую из основной RAM** через DMA.
2. **Интерпретирует их "на лету"** (как потоковый процессор).
### **2.2. Роль FIFO-буфера**
GPU имеет **маленький FIFO-буфер** (32 слова):
- DMA заполняет этот буфер, пока GPU читает данные.
- Если буфер переполняется, DMA приостанавливается.
---
## **3. Где хранятся данные?**
### **3.1. Основная RAM (2 МБ)**
- **Цепочки команд** хранятся здесь.
- **Текстуры** тоже могут быть в RAM (но чаще копируются в VRAM).
### **3.2. Видеопамять (VRAM, 1 МБ)**
- **Кадровый буфер** (Frame Buffer) — хранит пиксели.
- **Текстуры** — загружаются сюда для быстрого доступа.
- **CLUT** (Color Look-Up Table) — палитры для 8-битных текстур.
### **3.3. Как GPU обращается к данным?**
- **Через DMA**: Текстуры/данные копируются из RAM в VRAM перед рендерингом.
- **Прямой доступ**: GPU читает VRAM при отрисовке (например, текстуры).
---
## **4. Пример: полный цикл работы**
1. **Подготовка**:
- CPU создаёт в RAM массив команд (например, `DrawPolygon`, `LoadTexture`).
- Текстуры копируются в VRAM через `GP0` или DMA.
2. **Запуск рендеринга**:
- CPU отправляет адрес цепочки в DMA-контроллер GPU.
- DMA копирует команды из RAM в FIFO GPU.
- GPU выполняет команды, рисуя в кадровый буфер (VRAM).
3. **Вывод изображения**:
- Видеоконтроллер выводит кадр из VRAM на экран.
---
## **5. Критические нюансы**
1. **Синхронизация**:
- Если GPU занят, DMA приостанавливается (проверяется через статусный регистр `GP1`).
2. **Оптимизация**:
- **Связные списки команд** (OT — Ordering Table) позволяют сортировать примитивы.
3. **Ограничения**:
- DMA может работать только с выровненными данными (адреса, кратные 4).
- Переполнение FIFO приводит к "пропущенным кадрам".
---
## **6. Псевдокод для работы с DMA и GPU**
```c
// 1. Загрузка текстуры в VRAM
void LoadTexture(uint16_t x, uint16_t y, void* tex_data) {
GP0_SendCommand(0xA0000000 | (y << 11) | x); // Адрес в VRAM
GP0_SendCommand(0x10000000 | (width * height)); // Размер
DMA_Start(GPU_CHANNEL, tex_data, size); // Копируем через DMA
}
// 2. Формирование цепочки команд
struct CommandList {
uint32_t prim_header;
uint32_t data[10];
} __attribute__((aligned(4))); // Выравнивание для DMA
// 3. Запуск рендеринга
void DrawFrame() {
CommandList list = { ... };
DMA_Start(GPU_CHANNEL, &list, sizeof(list));
GPU_TriggerDMA(); // Запуск выполнения
}
```
---
## **Итог**
- **DMA в PS1** передаёт адрес цепочки команд из RAM в GPU.
- **GPU не имеет своей памяти для команд** — читает их напрямую из RAM через DMA/FIFO.
- **VRAM** используется только для хранения текстур и кадрового буфера.
- **Оптимизация DMA-передач** критична для производительности.
Это объясняет, почему в демосценах PS1 так важны **оптимизированные DMA-цепочки** и ручное управление памятью. Для глубокого понимания изучите **документацию PsyQ SDK** или исходники open-source движков (например, [PSn00bSDK](https://github.com/Lameguy64/psn00bsdk)).