vault backup: 2025-04-18 22:10:50
This commit is contained in:
124
PERSONAL PROJECTS/PS1 Vblank.md
Normal file
124
PERSONAL PROJECTS/PS1 Vblank.md
Normal file
@@ -0,0 +1,124 @@
|
||||
### **VBlank (Vertical Blanking) в PlayStation 1**
|
||||
|
||||
**VBlank** (вертикальное гашение) — это критически важный механизм синхронизации в PS1, связанный с выводом изображения на экран. Он используется для корректного обновления кадров, предотвращения артефактов рендеринга и эффективного управления ресурсами системы.
|
||||
|
||||
---
|
||||
|
||||
## **1. Что такое VBlank?**
|
||||
### **Физическая основа**
|
||||
- ЭЛТ-мониторы (как и TV, для которых создавалась PS1) рисуют изображение **построчно**, сверху вниз.
|
||||
- **VBlank** — это промежуток времени между окончанием вывода последней строки кадра и началом вывода первой строки следующего кадра.
|
||||
- В PS1 длительность VBlank:
|
||||
- **NTSC**: ~1.23 мс (каждые 16.68 мс при 60 Гц).
|
||||
- **PAL**: ~1.25 мс (каждые 20 мс при 50 Гц).
|
||||
|
||||
---
|
||||
|
||||
## **2. Как VBlank используется в PS1?**
|
||||
### **2.1. Синхронизация вывода изображения**
|
||||
- GPU PS1 рисует кадр в **кадровый буфер** (часть VRAM).
|
||||
- Во время VBlank видеоконтроллер **переключается на готовый кадр**, избегая "разрывов" (tearing).
|
||||
|
||||
### **2.2. Безопасное обновление графики**
|
||||
- Любые изменения VRAM (загрузка текстур, обновление спрайтов) должны выполняться **только во время VBlank**, иначе:
|
||||
- Возникают артефакты (мелькание, частичное обновление).
|
||||
- Возможны конфликты доступа к VRAM между GPU и CPU.
|
||||
|
||||
### **2.3. Оптимизация работы CPU**
|
||||
- Игры используют VBlank как **метку времени** для:
|
||||
- Обновления игровой логики (физика, AI).
|
||||
- Загрузки данных с CD-ROM.
|
||||
- Подготовки следующего кадра.
|
||||
|
||||
---
|
||||
|
||||
## **3. Техническая реализация VBlank**
|
||||
### **3.1. Прерывание VBlank**
|
||||
- При наступлении VBlank генерируется **прерывание (IRQ0)**.
|
||||
- CPU может обработать его, выполнив критически важные задачи.
|
||||
|
||||
#### **Пример кода (обработка прерывания):**
|
||||
```asm
|
||||
; Установка обработчика VBlank
|
||||
la t0, vblank_handler ; Адрес обработчика
|
||||
sw t0, 0x10000080 ; Запись в вектор прерываний
|
||||
|
||||
; Включение прерываний
|
||||
mfc0 t1, $12 ; Статусный регир COP0
|
||||
ori t1, 0x01 ; Разрешить IRQ0
|
||||
mtc0 t1, $12
|
||||
```
|
||||
|
||||
### **3.2. Регистры, связанные с VBlank**
|
||||
| Адрес | Назначение |
|
||||
|---------------|----------------------------------------------------------------------------|
|
||||
| **0x1F801070** | **I_STAT** — Флаги прерываний (бит 0 = VBlank). |
|
||||
| **0x1F801100** | **GPU STATUS** — Содержит флаг `VRAM_READY` (можно ли обновлять VRAM). |
|
||||
|
||||
### **3.3. Ожидание VBlank в коде**
|
||||
```c
|
||||
#include <libgte.h>
|
||||
#include <libgpu.h>
|
||||
|
||||
void wait_vblank() {
|
||||
VSync(0); // Ожидание следующего VBlank
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## **4. Практическое применение в играх**
|
||||
### **4.1. Двойная буферизация**
|
||||
1. **Буфер A** выводится на экран.
|
||||
2. **Буфер B** рисуется GPU во время кадра.
|
||||
3. Во время VBlank буферы **меняются местами** (через `DrawSync(0)`).
|
||||
|
||||
### **4.2. Загрузка данных**
|
||||
- CD-ROM и DMA активны преимущественно во время VBlank, чтобы не мешать рендерингу.
|
||||
|
||||
### **4.3. Лимит FPS**
|
||||
- Большинство игр PS1 работают на **50/60 FPS** (частота VBlank), так как:
|
||||
- Новый кадр начинается только после VBlank.
|
||||
- Попытка рендерить быстрее бессмысленна (ЭЛТ не успеет отобразить).
|
||||
|
||||
---
|
||||
|
||||
## **5. Пример: Цикл рендеринга с VBlank**
|
||||
```c
|
||||
while (1) {
|
||||
// 1. Ожидаем VBlank
|
||||
VSync(0);
|
||||
|
||||
// 2. Обновляем игровую логику
|
||||
update_game();
|
||||
|
||||
// 3. Готовим кадр в заднем буфере
|
||||
render_frame();
|
||||
|
||||
// 4. Меняем буферы
|
||||
SwapBuffers();
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## **6. Интересные нюансы**
|
||||
- **Режимы видео**:
|
||||
- NTSC (60 Гц) даёт более плавный геймплей, но меньше времени на VBlank.
|
||||
- PAL (50 Гц) имеет более длинный VBlank, но ниже FPS.
|
||||
- **Overclocking**: Некоторые домашние разработчики нарушают синхронизацию для экспериментов (рискуя артефактами).
|
||||
|
||||
---
|
||||
|
||||
## **7. Итог**
|
||||
- **VBlank** — это "пауза" между кадрами, используемая для:
|
||||
- Синхронизации вывода изображения.
|
||||
- Обновления графики без артефактов.
|
||||
- Оптимизации загрузки данных.
|
||||
- **Без VBlank** игры PS1 выглядели бы с глюками (как на многих эмуляторах без корректной синхронизации).
|
||||
|
||||
Для глубокого понимания изучите:
|
||||
- [PSX SPX Technical Reference](http://problemkaputt.de/psx-spx.htm)
|
||||
- **LibGPU Documentation** (PsyQ SDK).
|
||||
|
||||
Это ключ к плавной графике в играх вроде *Crash Bandicoot* или *Tekken 3*! 🎮
|
||||
169
PERSONAL PROJECTS/PSX code - Load texture from SECTOR!.md
Normal file
169
PERSONAL PROJECTS/PSX code - Load texture from SECTOR!.md
Normal file
@@ -0,0 +1,169 @@
|
||||
Вот модифицированная программа для **PlayStation 1**, которая загружает текстуру напрямую из указанного сектора CD-ROM в RAM, а затем выводит её на экран с эффектом плавного появления. Код адаптирован для работы с "сырыми" секторами диска.
|
||||
|
||||
---
|
||||
|
||||
### **1. Изменённый код (`MAIN.C`)**
|
||||
```c
|
||||
#include <sys/types.h>
|
||||
#include <libetc.h>
|
||||
#include <libgte.h>
|
||||
#include <libgpu.h>
|
||||
#include <libcd.h>
|
||||
|
||||
#define SCREEN_WIDTH 320
|
||||
#define SCREEN_HEIGHT 240
|
||||
|
||||
// Параметры текстуры (256x256, 16-бит)
|
||||
#define TEX_WIDTH 256
|
||||
#define TEX_HEIGHT 256
|
||||
#define TEX_SIZE (TEX_WIDTH * TEX_HEIGHT * 2) // 131072 байт (16-бит)
|
||||
#define TEX_SECTORS (TEX_SIZE / 2048) // Размер в секторах CD (1 сектор = 2048 байт)
|
||||
|
||||
// Буфер для текстуры в RAM (выровнен для DMA)
|
||||
uint16_t tex_buffer[TEX_WIDTH * TEX_HEIGHT] __attribute__((aligned(64)));
|
||||
|
||||
// Структура спрайта
|
||||
typedef struct {
|
||||
RECT img_rect; // Размеры текстуры
|
||||
TIM_IMAGE tim; // Данные TIM-формата (не используется, но нужен для LoadImage)
|
||||
int brightness; // Текущая яркость (0-128)
|
||||
int fade_speed; // Скорость изменения яркости
|
||||
} Sprite;
|
||||
|
||||
void init() {
|
||||
ResetGraph(0);
|
||||
InitPad(NULL, 0, NULL, 0);
|
||||
CdInit();
|
||||
SetVideoMode(MODE_NTSC);
|
||||
FntLoad(960, 256);
|
||||
FntOpen(16, 16, 256, 224, 0, 512);
|
||||
}
|
||||
|
||||
void load_texture_from_sector(int start_sector) {
|
||||
// Чтение текстуры из указанного сектора CD-ROM в RAM через DMA
|
||||
CdRead(start_sector, (uint32_t*)tex_buffer, TEX_SECTORS);
|
||||
CdReadSync(0); // Ожидание завершения DMA
|
||||
}
|
||||
|
||||
void draw_sprite(Sprite* sprite) {
|
||||
// Настройка полупрозрачности для эффекта яркости
|
||||
float alpha = (float)sprite->brightness / 128.0f;
|
||||
DR_MODE dr_mode;
|
||||
SetDrawMode(&dr_mode, 0, 0, GetTPage(0, 0, 0, 0), 0);
|
||||
SetSprt16(&sprite->img_rect);
|
||||
SetSemiTrans(&sprite->img_rect, 1);
|
||||
setRGB0(&sprite->img_rect, alpha * 255, alpha * 255, alpha * 255);
|
||||
DrawPrim(&sprite->img_rect);
|
||||
}
|
||||
|
||||
int main() {
|
||||
init();
|
||||
|
||||
// Параметры загрузки (пример: текстура начинается с сектора 1000)
|
||||
int texture_start_sector = 1000; // Замените на реальный сектор!
|
||||
load_texture_from_sector(texture_start_sector);
|
||||
|
||||
// Настройка спрайта
|
||||
Sprite sprite = {
|
||||
.img_rect = {0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, 0},
|
||||
.brightness = 0,
|
||||
.fade_speed = 1
|
||||
};
|
||||
|
||||
// Загрузка текстуры в VRAM (адрес в RAM -> VRAM)
|
||||
RECT vram_rect = {0, 0, TEX_WIDTH, TEX_HEIGHT}; // Куда загружать в VRAM
|
||||
LoadImage(&vram_rect, (uint32_t*)tex_buffer);
|
||||
|
||||
// Главный цикл
|
||||
while (1) {
|
||||
FntPrint("Sector Load Demo\nBrightness: %d\nSector: %d",
|
||||
sprite.brightness, texture_start_sector);
|
||||
|
||||
// Плавное изменение яркости
|
||||
sprite.brightness += sprite.fade_speed;
|
||||
if (sprite.brightness >= 128 || sprite.brightness <= 0)
|
||||
sprite.fade_speed *= -1;
|
||||
|
||||
// Отрисовка
|
||||
draw_sprite(&sprite);
|
||||
FntFlush(-1);
|
||||
VSync(0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### **2. Ключевые изменения**
|
||||
1. **Загрузка из сектора**:
|
||||
- Вместо поиска файла (`CdSearchFile`) используется прямой доступ к сектору:
|
||||
```c
|
||||
CdRead(start_sector, (uint32_t*)tex_buffer, TEX_SECTORS);
|
||||
```
|
||||
- `start_sector` — начальный сектор текстуры на диске (например, `1000`).
|
||||
|
||||
2. **Размер текстуры**:
|
||||
- Рассчитывается автоматически:
|
||||
```c
|
||||
#define TEX_SECTORS (TEX_SIZE / 2048) // 2048 байт = 1 сектор Mode 1
|
||||
```
|
||||
|
||||
3. **Выравнивание в RAM**:
|
||||
- Буфер `tex_buffer` выровнен по 64 байта для эффективного DMA:
|
||||
```c
|
||||
uint16_t tex_buffer[...] __attribute__((aligned(64)));
|
||||
```
|
||||
|
||||
4. **Загрузка в VRAM**:
|
||||
- `LoadImage` копирует данные из `tex_buffer` (RAM) в VRAM:
|
||||
```c
|
||||
LoadImage(&vram_rect, (uint32_t*)tex_buffer);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### **3. Как подготовить диск**
|
||||
1. **Конвертируйте текстуру** в RAW 16-бит (например, через Photoshop или `ffmpeg`):
|
||||
```bash
|
||||
ffmpeg -i texture.png -f rawvideo -pix_fmt rgb565 texture.raw
|
||||
```
|
||||
|
||||
2. **Запишите RAW-данные** на CD в нужный сектор (например, с помощью `mkpsxiso`):
|
||||
```bash
|
||||
mkpsxiso -y -o texture.cue -c "CDROM_DATA" texture.raw
|
||||
```
|
||||
- Узнайте начальный сектор через `cdrdao` или hex-редактор.
|
||||
|
||||
---
|
||||
|
||||
### **4. Важные нюансы**
|
||||
- **Режим CD-ROM**: Данные должны быть записаны в **Mode 1** (2048 байт/сектор).
|
||||
- **Размер текстуры**: Должен быть кратен размеру сектора (иначе чтение "сломает" данные).
|
||||
- **Проверка сектора**: Убедитесь, что сектор не занят другими файлами.
|
||||
|
||||
---
|
||||
|
||||
### **5. Пример для сборки**
|
||||
1. Скомпилируйте:
|
||||
```bash
|
||||
ccpsx MAIN.C -o CD_SECTOR_DEMO.EXE
|
||||
```
|
||||
2. Запишите на диск, указав в `SYSTEM.CNF`:
|
||||
```
|
||||
BOOT = cdrom:\CD_SECTOR_DEMO.EXE;1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### **6. Дополнительная оптимизация**
|
||||
Для работы с **Mode 2 XA** (формат видео) измените:
|
||||
```c
|
||||
CdReadMode(CdMode_CD_XA); // Перед CdRead
|
||||
```
|
||||
и корректируйте размер сектора (2336 байт).
|
||||
|
||||
---
|
||||
|
||||
Этот код идеален для демо-сцен, где нужно напрямую читать графику с CD без файловой системы! 📀
|
||||
171
PERSONAL PROJECTS/PSX code - Texture show from file.md
Normal file
171
PERSONAL PROJECTS/PSX code - Texture show from file.md
Normal file
@@ -0,0 +1,171 @@
|
||||
Вот готовая программа для **PlayStation 1**, которая загружает текстуру с CD-ROM, передаёт её в VRAM и плавно выводит на экран с анимацией яркости (от 0 до 128). Код использует **PsyQ SDK** и разбит на логические блоки.
|
||||
|
||||
---
|
||||
|
||||
### **1. Структура проекта**
|
||||
```
|
||||
texture_demo/
|
||||
├── MAIN.C # Основной код
|
||||
├── TEXTURE.BIN # RAW-текстура 256x256 (16-бит RGB)
|
||||
└── SYSTEM.CNF # Конфигурационный файл
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### **2. Код программы (`MAIN.C`)**
|
||||
```c
|
||||
#include <sys/types.h>
|
||||
#include <libetc.h>
|
||||
#include <libgte.h>
|
||||
#include <libgpu.h>
|
||||
#include <libcd.h>
|
||||
|
||||
#define SCREEN_WIDTH 320
|
||||
#define SCREEN_HEIGHT 240
|
||||
|
||||
// Буфер для текстуры (256x256, 16-бит)
|
||||
#define TEX_SIZE (256 * 256 * 2) // 131072 байт
|
||||
uint16_t tex_buffer[256 * 256] __attribute__((aligned(64))); // Выравнивание для DMA
|
||||
|
||||
// Параметры спрайта
|
||||
typedef struct {
|
||||
RECT img_rect; // Размеры текстуры
|
||||
TIM_IMAGE tim; // Данные TIM-файла
|
||||
int brightness; // Текущая яркость (0-128)
|
||||
int fade_speed; // Скорость изменения яркости
|
||||
} Sprite;
|
||||
|
||||
void init() {
|
||||
// Инициализация системных библиотек
|
||||
ResetGraph(0);
|
||||
InitPad(NULL, 0, NULL, 0);
|
||||
CdInit();
|
||||
|
||||
// Настройка видеорежима (NTSC)
|
||||
SetVideoMode(MODE_NTSC);
|
||||
FntLoad(960, 256);
|
||||
FntOpen(16, 16, 256, 224, 0, 512);
|
||||
}
|
||||
|
||||
void load_texture(const char* filename) {
|
||||
CdlFILE file;
|
||||
uint8_t sector_buffer[2048]; // Буфер для сектора CD
|
||||
|
||||
// Поиск файла на диске
|
||||
if (CdSearchFile(&file, filename) == 0) {
|
||||
FntPrint("Error: File not found!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Чтение текстуры в буфер через DMA
|
||||
CdRead(file.pos, (uint32_t*)tex_buffer, TEX_SIZE / 2048);
|
||||
CdReadSync(0); // Ожидание завершения
|
||||
}
|
||||
|
||||
void draw_sprite(Sprite* sprite) {
|
||||
// Установка яркости (0-128 → 0.0-1.0)
|
||||
float alpha = (float)sprite->brightness / 128.0f;
|
||||
|
||||
// Рисуем полноэкранный спрайт с альфа-смешением
|
||||
DR_MODE dr_mode;
|
||||
SetDrawMode(&dr_mode, 0, 0, GetTPage(0, 0, sprite->tim.prect->x, sprite->tim.prect->y), 0);
|
||||
SetSprt16(&sprite->img_rect); // 16-битный спрайт
|
||||
|
||||
// Применяем яркость через полупрозрачность
|
||||
SetSemiTrans(&sprite->img_rect, 1);
|
||||
setRGB0(&sprite->img_rect, alpha * 255, alpha * 255, alpha * 255);
|
||||
|
||||
// Вывод спрайта
|
||||
DrawPrim(&sprite->img_rect);
|
||||
}
|
||||
|
||||
int main() {
|
||||
init(); // Инициализация
|
||||
|
||||
// Загрузка текстуры
|
||||
load_texture("\\TEXTURE.BIN"); // Путь на CD
|
||||
|
||||
// Настройка спрайта
|
||||
Sprite sprite = {
|
||||
.img_rect = {0, 0, SCREEN_WIDTH, SCREEN_HEIGHT},
|
||||
.brightness = 0,
|
||||
.fade_speed = 1
|
||||
};
|
||||
|
||||
// Загрузка текстуры в VRAM
|
||||
sprite.tim.mode = 0;
|
||||
sprite.tim.prect = (RECT*)tex_buffer;
|
||||
LoadImage(&sprite.tim.prect[0], &sprite.tim.pdata[0]);
|
||||
|
||||
// Главный цикл
|
||||
while (1) {
|
||||
FntPrint("Fade Demo: Brightness = %d\n", sprite.brightness);
|
||||
|
||||
// Плавное увеличение яркости
|
||||
sprite.brightness += sprite.fade_speed;
|
||||
if (sprite.brightness >= 128 || sprite.brightness <= 0)
|
||||
sprite.fade_speed *= -1; // Меняем направление
|
||||
|
||||
// Отрисовка
|
||||
draw_sprite(&sprite);
|
||||
FntFlush(-1);
|
||||
|
||||
// Синхронизация с VBlank
|
||||
VSync(0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### **3. Как это работает?**
|
||||
1. **Инициализация**:
|
||||
- Настраивается видеорежим (NTSC 320x240).
|
||||
- Инициализируются CD-ROM и геймпад.
|
||||
|
||||
2. **Загрузка текстуры**:
|
||||
- Файл `TEXTURE.BIN` (RAW 256x256, 16-бит) читается с диска через DMA.
|
||||
- Данные копируются в буфер `tex_buffer`.
|
||||
|
||||
3. **Передача в VRAM**:
|
||||
- `LoadImage()` загружает текстуру в VRAM (адрес автоматически выбирается GPU).
|
||||
|
||||
4. **Плавное затемнение**:
|
||||
- В главном цикле меняется параметр `brightness` (0 → 128 → 0).
|
||||
- Яркость применяется через **полупрозрачность** (`SetSemiTrans`).
|
||||
|
||||
5. **Вывод**:
|
||||
- Спрайт рисуется на весь экран с текущей яркостью.
|
||||
|
||||
---
|
||||
|
||||
### **4. Требования к текстуре**
|
||||
- Формат: **RAW 16-бит RGB** (без заголовков).
|
||||
- Размер: **256x256** (можно изменить в коде).
|
||||
- Размещение: корень CD (`TEXTURE.BIN`).
|
||||
|
||||
---
|
||||
|
||||
### **5. Сборка**
|
||||
1. Скомпилируйте через **PsyQ SDK**:
|
||||
```bash
|
||||
ccpsx MAIN.C -o TEXTURE_DEMO.EXE
|
||||
```
|
||||
2. Запишите на диск вместе с `TEXTURE.BIN` и `SYSTEM.CNF`.
|
||||
|
||||
---
|
||||
|
||||
### **6. Демонстрация эффекта**
|
||||
- Текстура плавно "проявляется" (от чёрного к нормальной яркости) и затем исчезает.
|
||||
- Скорость регулируется `fade_speed`.
|
||||
|
||||
---
|
||||
|
||||
### **7. Оптимизации**
|
||||
- Для плавности используется **VSync(0)**.
|
||||
- DMA ускоряет загрузку текстуры.
|
||||
- Полупрозрачность GPU имитирует изменение яркости.
|
||||
|
||||
Этот код можно расширить для загрузки анимаций или сложных эффектов! 🎮
|
||||
Reference in New Issue
Block a user