1. Введение
Если есть что-то, что мне нравится больше, чем компьютерная графика, так это быстрая компьютерная графика…
К концу этого поста вы узнаете, как создать и связать Google ANGLE с Raylib, что даст как минимум 3-кратное увеличение исходной частоты кадров на компьютерах Mac с чипами M1/M2. По сути, это та же низкоуровневая графическая библиотека, на которой работает Google Chrome! (И любые браузеры на основе хрома)
Этот учебник предполагает некоторые базовые знания о компиляции программного обеспечения C/C++ и некоторый опыт работы с командной строкой.
Предпосылки
Вам также понадобятся следующие предварительные условия:
- Инструменты командной строки Apple Developer (обязательно)
- Код VS (рекомендуется)
- Домашний пивовар (рекомендуется)
- Ниндзя
brew install ninja
- CMake
brew install cmake
- Python 3 (обязательно)
- Гит (обязательно)
Нетерпеливые могут сразу перейти к Краткой версии в разделе 3, где показано, как украсть
libEGL.dylib
иlibGLESv2.dylib
из Chrome.
Если вам нужно более полное руководство и вы хотите узнать, как создать raylib и ANGLE с нуля и связать их вместе в хороший проект cmake, ознакомьтесь с разделом 4.
2. Зачем вообще использовать ANGLE?
Кажется, в наши дни у каждого есть свой собственный графический API. Microsoft видит будущее в Direct3D. Kronos (разработчик спецификаций OpenGL и Vulkan) считает Vulkan решением следующего поколения. С другой стороны, Apple, верная своей природе создания полнофункциональных, аппаратных и программных продуктов, выбрала свободу и гибкость и решила, что им тоже нужен собственный блестящий ускоренный графический API — Metal
NVidia поддерживает столько, сколько может, они просто хотят продавать оборудование.
Как правило, OpenGL имеет довольно хорошую кроссплатформенную поддержку. И это обычно подходит для чего-либо кроссплатформенного. Но поскольку Apple сосредоточилась на Metal и фактически отказалась от поддержки OpenGL в 2018 году, производительность драйверов OpenGL на Mac не получила большой популярности и, вероятно, не будет в будущем. Хорошая новость заключается в том, что Metal может получить примерно в 10 раз больше вызовов отрисовки, чем OpenGL, особенно на современных чипах M1/M2.
Со всеми этими различными API начинают появляться уровни абстракции. На самом деле, Google разрабатывает такой API, который присутствует во всех браузерах на основе Chromium, и называется ANGLE. Он предоставляет внешний интерфейс, совместимый с OpenGL ES 2.0, с внутренними интерфейсами для всех основных собственных графических API.
Короче говоря, вы можете получить ОГРОМНОЕ увеличение скорости при использовании Metal через ANGLE на платформах MacOS. Частота кадров обычно удваивается, уменьшается или даже больше, чем у решений на основе OpenGL.
3. Быстрый старт (короткая версия с использованием ANGLE из браузера)
Приветствуйте Peter0x44 на Github и сервере Discord Raylib за указание на это, но на самом деле вы можете просто получить ANGLE в виде libEGL.dylib
и libGLESv2.dylib
из браузера на основе Chromium, который у вас, вероятно, уже есть!
Итак, поехали.
Шаг 1. Загрузите libEGL.dylib
и libGLESv2.dylib
из Chrome
Например, используя Chrome, давайте покопаемся в .app
и возьмем эти файлы. Мы будем использовать команду find
:
cd /Applications/Google\ Chrome.app find ./ -name 'libEGL.dylib'
Ваш вывод должен выглядеть примерно так. Сладкий.
.//Contents/Frameworks/Google Chrome Framework.framework/Versions/113.0.5672.126/Libraries/libEGL.dylib .//Contents/Frameworks/Google Chrome Framework.framework/Versions/114.0.5735.90/Libraries/libEGL.dylib
Теперь вы можете найти libGLESv2.dylib
:
find ./ -name 'libGLESv2.dylib'
Бум:
.//Contents/Frameworks/Google Chrome Framework.framework/Versions/113.0.5672.126/Libraries/libGLESv2.dylib .//Contents/Frameworks/Google Chrome Framework.framework/Versions/114.0.5735.90/Libraries/libGLESv2.dylib
Шаг 2. Скопируйте libEGL.dylib
и libGLESv2.dylib
raylib в папку проекта
cd <your project> cp "/Applications/Google Chrome.app/Frameworks/Google Chrome Framework.framework/Versions/114.0.5735.90/Libraries/libGLESv2.dylib" ./ cp "/Applications/Google Chrome.app/Contents/Frameworks/Google Chrome Framework.framework/Versions/114.0.5735.90/Libraries/libEGL.dylib" ./
Шаг 3. Установите связь с raylib
Вот однострочный вариант, если вы используете статическую сборку raylib:
g++ -std=c++14 -I/path/to/raylib/include -o main main.cpp /path/to/raylib.a /path/to/libEGL.dylib /path/to/libGLESv2.dylib
4. Немного более длинная версия
Одна команда g++
или gcc
подходит для небольших проектов, но для большинства проектов вам понадобится система сборки. Мы будем использовать CMake, так как он кажется стандартом де-факто для проектов C/C++.
4.1 Структура папок и настройка
Шаг 1. Настройка папки
Идите вперед и выберите корневой проект на своем компьютере. Я предлагаю что-то вроде ~/code/raylib-angle
или что-нибудь попроще.
Поместите в папку следующее:
. ├── CMakeLists.txt ├── src │ └── main.cpp └── vendor
После того, как мы настроим подмодули git и добавим исходный код, он должен выглядеть примерно так:
. ├── CMakeLists.txt ├── build ├── src │ └── main.cpp └── vendor ├── angle ├── raygui └── raylib
4.2 Подмодули Git
Хотя вы, безусловно, можете связываться со статическими сборками raylib, мне нравится хранить все в комплекте в виде исходного кода, который вы можете скомпилировать без суеты. Итак, давайте добавим raylib
и raygui
, если вам хочется приключений.
Добавить raylib в качестве подмодуля в vender/raylib
git submodule add https://github.com/raysan5/raylib.git vendor/raylib
Добавить raylib в качестве подмодуля в vendor/raygui
git submodule add https://github.com/raysan5/raygui.git vendor/raygui
Добавить ANGLE в качестве подмодуля к vendor/angle
git submodule add https://chromium.googlesource.com/angle/angle vendor/angle
Инициализировать подмодули Это нужно делать только в том случае, если вы клонируете корневой репозиторий, но в качестве напоминания на будущее:
git submodule update --init --recursive
Круто, теперь давайте построим ANGLE
4.2 Угол построения
Я еще не совсем привязал это к своему CMakeLists.txt
, так как Angle использует отдельную систему сборки, ninja
(кстати, она безумно быстрая), поэтому пока мы будем собирать ANGLE отдельно.
Шаг 1. УГОЛ начальной загрузки
cd vendor/angle python3 scripts/bootstrap.py gclient sync
Шаг 2. Создание файлов сборки Ninja
gn gen out/Release --args='is_debug=false'
Здесь мы сгенерировали файлы сборки для релизной (оптимизированной) сборки, но вы можете создать отладочную сборку, удалив --args='is_debug=false' and running
gn gen out/Debug`
Шаг 2.5. (Необязательно) сборка только с металлической серверной частью
Если вы хотите уменьшить размер dylib примерно с 11 МБ до 8 МБ, вы можете отключить серверные части, отличные от Mac, для более компактной сборки.
Отредактируйте out/Release/args.gn
и добавьте следующее содержимое:
angle_enable_d3d9 = false angle_enable_d3d11 = false angle_enable_gl = false angle_enable_null = false angle_enable_metal = true angle_enable_vulkan = false angle_enable_essl = false angle_enable_glsl = true is_debug = false is_component_build = false
Шаг 3. Скомпилируйте угол
Этот шаг займет горячую минуту. На моем Macbook M1 Pro 2021 года это заняло около 10 минут. Отладочная сборка заняла примерно половину этого времени.
ninja -j 10 -k1 -C out/Release
Здесь я использовал все 10 процессоров. Используйте что-то подходящее для вашей системы.
По завершении нужные общие библиотеки (dylib) libEGL.dylib
и libGLESv2.dylib
находятся в vendor/angle/out/Release/
копии корневого каталога вашего проекта: ~/code/raylib-angle
(или любого другого)
4.3 Создание проекта
Теперь давайте быстро настроим CMakeLists.txt
и скомпилируем raylib и связанный с ним код, например glfw
.
Шаг 1. Создайте файл CMakeLists.txt
Добавьте это к <project-root>/CMakeLists.txt
cmake_minimum_required(VERSION 3.16) project(raylib-starter) set(CMAKE_CXX_STANDARD 14) # Add raylib subdir add_subdirectory(vendor/raylib) # Add my sources file(GLOB_RECURSE SOURCES "src/*.cpp") add_executable(${PROJECT_NAME} ${SOURCES}) # Define path to ANGLE libraries set(ANGLE_LIBRARY_DIR vendor/angle/out/Release) # Find ANGLE libraries find_library(ANGLE_GLESv2_LIBRARY libGLESv2.dylib PATHS ${ANGLE_LIBRARY_DIR}) find_library(ANGLE_EGL_LIBRARY libEGL.dylib PATHS ${ANGLE_LIBRARY_DIR}) # Add raylib include directory target_include_directories(${PROJECT_NAME} PRIVATE vendor/raylib/src) # Add raygui include directory target_include_directories(${PROJECT_NAME} PRIVATE vendor/raygui/src) # Add ANGLE include directory target_include_directories(${PROJECT_NAME} PRIVATE vendor/angle/include) # Link against raylib and ANGLE libraries target_link_libraries(${PROJECT_NAME} raylib ${ANGLE_EGL_LIBRARY} ${ANGLE_GLESv2_LIBRARY})
Шаг 2. Создайте <project-root>src/main.cpp
Вот немного кода Hello World raylib:
#include "raylib.h" int main(void) { const int screenWidth = 800; const int screenHeight = 450; InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window"); SetTargetFPS(60); while (!WindowShouldClose()) { BeginDrawing(); ClearBackground(RAYWHITE); DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY); DrawFPS(10, 10); EndDrawing(); } CloseWindow(); return 0; }
Шаг 3. Создание файлов сборки CMake
cmake -DCUSTOMIZE_BUILD=ON -DOPENGL_VERSION="ES 2.0" -B build cmake --build build
Флаги -DCUSTOMIZE_BUILD=ON -DOPENGL_VERSION="ES 2.0"
являются ключевыми. Они говорят Tell raylib искать реализацию OpenGL ES, которую предоставит ANGLE. Вы можете узнать больше о флагах cmake на Raylib Wiki
Шаг 3. Проверка
Здесь вы можете видеть, что наш проект raylib использует реализацию Google OpenGL ES, поддерживаемую Metal.
λ ~/code/projects/raylib-angle-test/ master* ./r INFO: Initializing raylib 4.6-dev INFO: Supported raylib modules: INFO: > rcore:..... loaded (mandatory) INFO: > rlgl:...... loaded (mandatory) INFO: > rshapes:... loaded (optional) INFO: > rtextures:. loaded (optional) INFO: > rtext:..... loaded (optional) INFO: > rmodels:... loaded (optional) INFO: > raudio:.... loaded (optional) INFO: DISPLAY: Device initialized successfully INFO: > Display size: 1920 x 1080 INFO: > Screen size: 800 x 450 INFO: > Render size: 800 x 450 INFO: > Viewport offsets: 0, 0 INFO: GLAD: OpenGL ES2.0 loaded successfully INFO: GL: Supported extensions count: 104 INFO: GL: OpenGL device information: INFO: > Vendor: Google Inc. (Apple) INFO: > Renderer: ANGLE (Apple, Apple M1 Pro, OpenGL 4.1 Metal - 76.3) INFO: > Version: OpenGL ES 3.0.0 (ANGLE 2.1.21199 git hash: b0e9bbd79fb6) INFO: > GLSL: OpenGL ES GLSL ES 3.00 (ANGLE 2.1.21199 git hash: b0e9bbd79fb6) INFO: GL: VAO extension detected, VAO functions loaded successfully INFO: GL: NPOT textures extension detected, full NPOT textures supported INFO: TEXTURE: [ID 1] Texture loaded successfully (1x1 | R8G8B8A8 | 1 mipmaps) INFO: TEXTURE: [ID 1] Default texture loaded successfully INFO: SHADER: [ID 1] Vertex shader compiled successfully INFO: SHADER: [ID 2] Fragment shader compiled successfully INFO: SHADER: [ID 3] Program shader loaded successfully INFO: SHADER: [ID 3] Default shader loaded successfully INFO: RLGL: Render batch vertex buffers loaded successfully in RAM (CPU) INFO: RLGL: Render batch vertex buffers loaded successfully in VRAM (GPU) INFO: RLGL: Default OpenGL state initialized successfully INFO: TEXTURE: [ID 2] Texture loaded successfully (128x128 | GRAY_ALPHA | 1 mipmaps) INFO: FONT: Default font loaded successfully (224 glyphs) INFO: TIMER: Target time per frame: 16.667 milliseconds INFO: SYSTEM: Decompress data: Comp. size: 1059 -> Original size: 131072 INFO: TEXTURE: [ID 3] Texture loaded successfully (256x256 | GRAY_ALPHA | 1 mipmaps)
4.4 Производительность
С УГЛОМ
Да… Это 11 тысяч + FPS, вы правильно видите. У меня даже есть браузер Chrome с Spotify и VS Code Running. Конечно, raylib здесь мало что делает, но все же!
Без УГЛА
Да… сказал Наф. Это почти в 4 раза быстрее. ANGLE определенно стоит того на MacOS и чипах M1/M2.
6. Устранение неполадок
Если вы получаете ошибку, например, при компиляции следующим образом:
error: incompatible pointer types assigning to 'int *' from 'bool *' if (active == NULL) active = &temp;
Просто отредактируйте эту строку в vendor/raygui/src/raygui.h
и измените эти строки:
bool temp = false; if (active == NULL) active = &temp;
to
bool temp = false; if (active == NULL) active = (int *)&temp;
Это приводит temp
, который является bool *
к int *
Вы также можете изменить bool temp
на int temp
Я отправлю запрос на включение этого исправления позже. К тому времени, когда вы это прочтете, это может уже не быть проблемой.
Заключение
Это пока все! ANGLE может не дать такого же улучшения скорости на других платформах, таких как Windows и Linux, но я могу ошибаться. Поддержка ANGLE в Raylib все еще экспериментальная, но это в значительной степени подтверждает, что она работает!
Я надеюсь вернуться с еще несколькими рецензиями на Raylib. На данный момент потрясающая экосистема Go checkout ray демонстрирует любовь к проекту по адресу:
- https://www.raylib.com/
- https://www.raylibtech.com/
- https://github.com/raysan5/raylib
- https://www.patreon.com/raylib
- https://discord.gg/raylib
Если вам нужен код стартового пакета, который мы установили сегодня, вы можете найти его на https://github.com/grplyler/raylib-cmake-starter.
До скорого! Продолжай программировать!
-Райан «Вортигон» Плайлер