Compare commits
271 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
226430f01e | ||
|
|
ae3be69081 | ||
|
|
307270532f | ||
|
|
04f9cb1d95 | ||
|
|
c45a76a5bf | ||
|
|
09561328ed | ||
|
|
baa0ab0a2c | ||
|
|
fd56e83c7b | ||
|
|
ea2ee83a3e | ||
|
|
5be3c86de4 | ||
|
|
ae02055e18 | ||
|
|
74e2d04b7b | ||
|
|
6ad95ca4c4 | ||
|
|
f08b1f6c8a | ||
|
|
4d640ed70c | ||
|
|
85ada83d57 | ||
|
|
c9ca2187b3 | ||
|
|
6a0f4fd8dc | ||
|
|
3dd68f9942 | ||
|
|
ffe5704673 | ||
|
|
20ec13d2b9 | ||
|
|
33d2b98c55 | ||
|
|
1adce43d9f | ||
|
|
466050ee7a | ||
|
|
6bc505de13 | ||
|
|
d70d748877 | ||
|
|
5cda85d16c | ||
|
|
9318456afb | ||
|
|
40fe100ecc | ||
|
|
c1bfc0f27d | ||
|
|
5a09ebb179 | ||
|
|
8370ae8324 | ||
|
|
a4fcbf187b | ||
|
|
b15aa648e2 | ||
|
|
9a88a8502e | ||
|
|
34a46d643a | ||
|
|
359be83f49 | ||
|
|
8c8c96bf30 | ||
|
|
e30a243452 | ||
|
|
f8e1cd4a66 | ||
|
|
d5512b72fa | ||
|
|
86f3d545ee | ||
|
|
9149f42b95 | ||
|
|
7aea6682f2 | ||
|
|
d0ca0e4ab7 | ||
|
|
f6dfed48dd | ||
|
|
5a69dff9d7 | ||
|
|
b7e2164f91 | ||
|
|
273858ec8f | ||
|
|
8f088eb76d | ||
|
|
a7433a6570 | ||
|
|
3ab445e780 | ||
|
|
dd554cce2a | ||
|
|
a182b53d7f | ||
|
|
a5f85a8a4c | ||
|
|
ae6a86800e | ||
|
|
b85e0444cb | ||
|
|
fc33d33508 | ||
|
|
14698594d8 | ||
|
|
024f3fefc3 | ||
|
|
33872806a1 | ||
|
|
3b4a1de9f3 | ||
|
|
5af4c82c1b | ||
|
|
e26af9ae1b | ||
|
|
8c41eefadb | ||
|
|
25d86eccee | ||
|
|
2393261cb0 | ||
|
|
d9d165f17e | ||
|
|
f446c82780 | ||
|
|
cc507ea4cf | ||
|
|
42fc7d9a86 | ||
|
|
60d3df7969 | ||
|
|
be52578d37 | ||
|
|
57c5ae5415 | ||
|
|
c6d6e409f1 | ||
|
|
c0dfcd9244 | ||
|
|
689608b3fe | ||
|
|
04330a10ac | ||
|
|
a456ad15ce | ||
|
|
e621bb53d4 | ||
|
|
420ba21b4d | ||
|
|
f3de55d6e9 | ||
|
|
bc1e0fbba9 | ||
|
|
80c0146ecd | ||
|
|
dbe3bb3cb3 | ||
|
|
83ecc6e498 | ||
|
|
8b2965f6dd | ||
|
|
6c31d3347a | ||
|
|
7f8ec481f1 | ||
|
|
25bb57a973 | ||
|
|
39365f52a2 | ||
|
|
fafc94248d | ||
|
|
edeaff793a | ||
|
|
2d5758419f | ||
|
|
ba063dae3b | ||
|
|
e018cad851 | ||
|
|
9ee8041710 | ||
|
|
1b50e123c5 | ||
|
|
77563b8449 | ||
|
|
d0923320a3 | ||
|
|
d8cab7aa47 | ||
|
|
fcf4d3d030 | ||
|
|
05362905f7 | ||
|
|
6866f2240e | ||
|
|
1903104247 | ||
|
|
04db0a7441 | ||
|
|
91cbb15b66 | ||
|
|
eeded8c8bc | ||
|
|
58e687c952 | ||
|
|
a0b536483a | ||
|
|
de1e8ed563 | ||
|
|
a832c3ca40 | ||
|
|
575ee21c7a | ||
|
|
071bc4596b | ||
|
|
178690cff3 | ||
|
|
1d566f74e3 | ||
|
|
eaa1b9afd0 | ||
|
|
a2d40ce844 | ||
|
|
4dcdcde7d5 | ||
|
|
8805f91bfd | ||
|
|
b5ca757189 | ||
|
|
c2d27c8434 | ||
|
|
5f55dd9b9a | ||
|
|
f044b9ab45 | ||
|
|
8c6ad92f37 | ||
|
|
34bdb740c2 | ||
|
|
c485f039fb | ||
|
|
3c60e76094 | ||
|
|
39650b5c96 | ||
|
|
0f16255240 | ||
|
|
91661fd206 | ||
|
|
6648bd427f | ||
|
|
aa2d0be63f | ||
|
|
2b557d5be7 | ||
|
|
36fae5c7d1 | ||
|
|
68570910e3 | ||
|
|
697a5e7147 | ||
|
|
31073c116c | ||
|
|
c6a024d911 | ||
|
|
66a1b44224 | ||
|
|
f5c581d89c | ||
|
|
765a04d9b5 | ||
|
|
ac054830b9 | ||
|
|
ccbd7561f4 | ||
|
|
2859725257 | ||
|
|
f18cce29b3 | ||
|
|
d9a7f337ba | ||
|
|
f8e619ad94 | ||
|
|
ea6450b308 | ||
|
|
6df9c284b8 | ||
|
|
d6b3f5dcc2 | ||
|
|
826740906f | ||
|
|
2c1f5181bf | ||
|
|
e728926521 | ||
|
|
04af533469 | ||
|
|
53048bd82a | ||
|
|
d0a19c5312 | ||
|
|
6e284fb9bc | ||
|
|
ea87c32051 | ||
|
|
d73ade4a85 | ||
|
|
67bfc73066 | ||
|
|
8b44a3aa6e | ||
|
|
36f9fdd53b | ||
|
|
9c43069e5f | ||
|
|
0b6e1717d9 | ||
|
|
41f7b4ef4c | ||
|
|
418791930c | ||
|
|
0690ecacd8 | ||
|
|
36f7efb679 | ||
|
|
a52e33e697 | ||
|
|
086c5402f5 | ||
|
|
dd1bd43360 | ||
|
|
d515ca5333 | ||
|
|
eeb4695d6c | ||
|
|
e94d3fd70f | ||
|
|
e76f084625 | ||
|
|
6e1fcb381a | ||
|
|
52c309a288 | ||
|
|
9ad28d7cf2 | ||
|
|
5f21f0bcf9 | ||
|
|
066eec2cf3 | ||
|
|
03e21227fa | ||
|
|
6f05728906 | ||
|
|
5edc36393a | ||
|
|
af29fc7b39 | ||
|
|
9795988e14 | ||
|
|
4087fca980 | ||
|
|
f3efb72a21 | ||
|
|
fc97445875 | ||
|
|
5babfde870 | ||
|
|
04ffce60cd | ||
|
|
9aaa26ddf5 | ||
|
|
df12d08ad3 | ||
|
|
064f660852 | ||
|
|
bf6389f9a7 | ||
|
|
cae3db0ebf | ||
|
|
79b01a5007 | ||
|
|
91927126f2 | ||
|
|
6fb8932ba9 | ||
|
|
536cf4c420 | ||
|
|
1b49794be6 | ||
|
|
25f73a6967 | ||
|
|
b7424e7f92 | ||
|
|
0b4b32b5ac | ||
|
|
1922b409dd | ||
|
|
80e938c019 | ||
|
|
68d2c63694 | ||
|
|
1386fe64cb | ||
|
|
7fd0ccff94 | ||
|
|
b28b144edb | ||
|
|
8e33b2fa30 | ||
|
|
cebadef063 | ||
|
|
57b27adf1a | ||
|
|
d08a97f55c | ||
|
|
c7ad6650d9 | ||
|
|
ac91253f51 | ||
|
|
3d939675e4 | ||
|
|
11b1bd147d | ||
|
|
c013237219 | ||
|
|
8039638885 | ||
|
|
d56b224d42 | ||
|
|
6ccf2a10d7 | ||
|
|
cfd1aab9e3 | ||
|
|
c5752f773e | ||
|
|
f398126e08 | ||
|
|
6c0d8829a5 | ||
|
|
cf3f16d832 | ||
|
|
b60ae54e34 | ||
|
|
7786b07eb8 | ||
|
|
90b1dac0f5 | ||
|
|
3c52fd05f3 | ||
|
|
843d7f0fe2 | ||
|
|
ea2014819d | ||
|
|
e458ef6401 | ||
|
|
0494ff14da | ||
|
|
c2c2dece61 | ||
|
|
401e6d13f3 | ||
|
|
2e5346a0ff | ||
|
|
ce5157a299 | ||
|
|
b5ce2347f6 | ||
|
|
9e0a0df5ca | ||
|
|
8f6f50c37f | ||
|
|
c36de40f4a | ||
|
|
52ca0c0d1b | ||
|
|
651a05c4bc | ||
|
|
1cfb8745e2 | ||
|
|
b3f3a01ee6 | ||
|
|
4acd240737 | ||
|
|
b79b8da031 | ||
|
|
bc7ef4484f | ||
|
|
9db5515fb5 | ||
|
|
387a1f5632 | ||
|
|
0babc2235f | ||
|
|
1a9a6ec6f8 | ||
|
|
d59d9f285a | ||
|
|
d16af1c4a8 | ||
|
|
5dcc2045d6 | ||
|
|
19ce912afe | ||
|
|
890e301b78 | ||
|
|
218a97e4ec | ||
|
|
74e5e35f5a | ||
|
|
e6298b1dc3 | ||
|
|
df860a5a64 | ||
|
|
b22064035a | ||
|
|
197c71021b | ||
|
|
d5fa70d7ab | ||
|
|
fd8e98f1ce | ||
|
|
0e10e5f8e1 | ||
|
|
689c9b3ed4 | ||
|
|
ecd43dedc5 | ||
|
|
dea507ec0e |
11
.github/dependabot.yml
vendored
git.filemode.normal_file
@@ -0,0 +1,11 @@
|
||||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions" # See documentation for possible values
|
||||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
29
.github/workflows/fetch_dependencies.yml
vendored
git.filemode.normal_file
@@ -0,0 +1,29 @@
|
||||
name: Fetch Dependencies
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0' # Runs weekly
|
||||
|
||||
jobs:
|
||||
update-dependencies:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run Fetch Dependencies Script
|
||||
run: cd scripts && bash ./fetch_dependencies.sh
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
with:
|
||||
title: update dependencies
|
||||
commit-message: "[BOT] update dependencies"
|
||||
committer: GitHub <noreply@github.com>
|
||||
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
|
||||
signoff: false
|
||||
base: indev
|
||||
branch: auto_deps_updates
|
||||
labels: |
|
||||
automated
|
||||
25
.github/workflows/greetings.yml
vendored
git.filemode.normal_file
@@ -0,0 +1,25 @@
|
||||
name: Greetings
|
||||
|
||||
on: [pull_request_target, issues]
|
||||
|
||||
jobs:
|
||||
greeting:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/first-interaction@v1
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-message: |
|
||||
Hello! Thank you for filing an issue.
|
||||
|
||||
If this is a bug report, please include relevant logs to help us debug the problem (OS, MLX version, drivers installed, GPU type and vendor, ...)
|
||||
pr-message: |
|
||||
Hello! Thank you for your contribution.
|
||||
|
||||
If you are fixing a bug, please reference the issue number in the description.
|
||||
|
||||
If you are implementing a feature request, please explain all your changes in your pull request.
|
||||
|
||||
8
.github/workflows/linux_clang.yml
vendored
@@ -35,8 +35,8 @@ jobs:
|
||||
|
||||
# Build the lib
|
||||
- name: Build MacroLibX
|
||||
run: make -j
|
||||
run: make -j && make fclean && make debug
|
||||
|
||||
# Build the test
|
||||
- name: Build Test
|
||||
run: cd test && clang main.c ../libmlx.so -lSDL2
|
||||
# Build the example
|
||||
- name: Build Example
|
||||
run: cd example && bash ./build.sh
|
||||
|
||||
8
.github/workflows/linux_gcc.yml
vendored
@@ -35,9 +35,9 @@ jobs:
|
||||
|
||||
# Build the lib
|
||||
- name: Build MacroLibX
|
||||
run: make TOOLCHAIN=gcc -j
|
||||
run: make TOOLCHAIN=gcc -j && make fclean && make TOOLCHAIN=gcc debug
|
||||
|
||||
# Build the test
|
||||
- name: Build Test
|
||||
run: cd test && gcc main.c ../libmlx.so -lSDL2
|
||||
# Build the example
|
||||
- name: Build Example
|
||||
run: cd example && bash ./build.sh
|
||||
|
||||
|
||||
14
.github/workflows/macos_x86.yml
vendored
@@ -29,21 +29,15 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Install system dependencies
|
||||
- name: Install Vulkan SDK
|
||||
uses: humbletim/install-vulkan-sdk@v1.1.1
|
||||
with:
|
||||
version: 1.3.204.1
|
||||
cache: true
|
||||
|
||||
- name: Install Dependancies
|
||||
run: |
|
||||
brew install SDL2
|
||||
|
||||
# Build the lib
|
||||
- name: Build MacroLibX
|
||||
run: make -j
|
||||
run: make -j && make fclean && make debug
|
||||
|
||||
# Build the test
|
||||
- name: Build Test
|
||||
run: cd test && clang main.c ../libmlx.so -lSDL2
|
||||
# Build the example
|
||||
- name: Build Example
|
||||
run: cd example && bash ./build.sh
|
||||
|
||||
|
||||
56
.github/workflows/windows.yml
vendored
git.filemode.normal_file
@@ -0,0 +1,56 @@
|
||||
name: Windows (xmake)
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
paths-ignore:
|
||||
- '.gitignore'
|
||||
- 'LICENSE'
|
||||
- 'README.md'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [windows-latest]
|
||||
arch: [x64]
|
||||
mode: [release]
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
if: "!contains(github.event.head_commit.message, 'ci skip')"
|
||||
|
||||
steps:
|
||||
- name: Get current date as package key
|
||||
id: cache_key
|
||||
run: echo "key=$(date +'%W')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Force xmake to a specific folder (for cache)
|
||||
- name: Set xmake env
|
||||
run: echo "XMAKE_GLOBALDIR=${{ runner.workspace }}/xmake-global" >> $GITHUB_ENV
|
||||
|
||||
# Install xmake
|
||||
- name: Setup xmake
|
||||
uses: xmake-io/github-action-setup-xmake@v1
|
||||
with:
|
||||
xmake-version: branch@master
|
||||
actions-cache-folder: .xmake-cache-W${{ steps.cache_key.outputs.key }}
|
||||
|
||||
# Update xmake repository (in order to have the file that will be cached)
|
||||
- name: Update xmake repository
|
||||
run: xmake repo --update
|
||||
|
||||
# Setup compilation mode and install project dependencies
|
||||
- name: Configure xmake and install dependencies
|
||||
run: xmake config --arch=${{ matrix.arch }} --mode=${{ matrix.mode }} --yes
|
||||
|
||||
# Build the mlx
|
||||
- name: Build MacroLibX
|
||||
run: xmake --yes
|
||||
|
||||
# Build the example
|
||||
- name: Build Example
|
||||
run: xmake build --yes Test
|
||||
16
.gitignore
vendored
@@ -4,5 +4,19 @@
|
||||
*.a
|
||||
*.so
|
||||
*.out
|
||||
*.dll
|
||||
*.lib
|
||||
*.exp
|
||||
*.json
|
||||
*.tmp
|
||||
*.ilk
|
||||
*.pdb
|
||||
*.exe
|
||||
*vgcore
|
||||
*.gdb_history
|
||||
.vs/
|
||||
.xmake/
|
||||
.cache/
|
||||
test/.gdb_history
|
||||
objs/
|
||||
build/
|
||||
example/Test
|
||||
|
||||
17
CONTRIBUTING.md
git.filemode.normal_file
@@ -0,0 +1,17 @@
|
||||
# How to contribute to the MacroLibX
|
||||
|
||||
For any questions, suggestions or help [contact me](mailto:contact@kbz8.me)
|
||||
|
||||
## **Found a bug?**
|
||||
|
||||
* Avoid opening any new issues without having checked if your problem has already been reported. If there are no currently open issues that fit your problem's description, feel free to [add it](https://github.com/seekrs/MacroLibX/issues/new).
|
||||
|
||||
* When writing an issue make sure to include a clear title and description as well as having filled out all the necessary information: System info, OS, OS-Version, ...
|
||||
|
||||
* If possible add pictures of the issue.
|
||||
|
||||
## Contributing
|
||||
|
||||
Before thinking of adding a contribution, think. Is it necessary? Will this actually be a useful/required feature? Is your implementation good?
|
||||
Provide clear and documented explanation as to what was changed.
|
||||
|
||||
2
LICENSE
@@ -1,5 +1,5 @@
|
||||
MIT License
|
||||
Copyright (c) 2022-2023 kbz_8
|
||||
Copyright (c) 2022-2024 kbz_8
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
126
Makefile
@@ -3,89 +3,129 @@
|
||||
# ::: :::::::: #
|
||||
# Makefile :+: :+: :+: #
|
||||
# +:+ +:+ +:+ #
|
||||
# By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ #
|
||||
# By: kiroussa <oss@xtrm.me> +#+ +:+ +#+ #
|
||||
# +#+#+#+#+#+ +#+ #
|
||||
# Created: 2022/10/04 16:43:41 by maldavid #+# #+# #
|
||||
# Updated: 2023/11/24 10:03:17 by maldavid ### ########.fr #
|
||||
# Updated: 2024/04/24 14:59:23 by kiroussa ### ########.fr #
|
||||
# #
|
||||
# **************************************************************************** #
|
||||
|
||||
NAME = libmlx.so
|
||||
NAME = libmlx.so
|
||||
MAKE = make --no-print-directory
|
||||
|
||||
SRCS = $(wildcard $(addsuffix /*.cpp, ./src/core))
|
||||
SRCS += $(wildcard $(addsuffix /*.cpp, ./src/platform))
|
||||
SRCS += $(wildcard $(addsuffix /*.cpp, ./src/renderer))
|
||||
SRCS += $(wildcard $(addsuffix /*.cpp, ./src/renderer/**))
|
||||
OS ?= $(shell uname -s)
|
||||
DEBUG ?= false
|
||||
TOOLCHAIN ?= clang
|
||||
IMAGES_OPTIMIZED ?= true
|
||||
FORCE_INTEGRATED_GPU ?= false
|
||||
GRAPHICS_MEMORY_DUMP ?= false
|
||||
PROFILER ?= false
|
||||
_ENABLEDFLAGS =
|
||||
|
||||
OBJ_DIR = objs
|
||||
OBJS = $(addprefix $(OBJ_DIR)/, $(SRCS:.cpp=.o))
|
||||
SRCS = $(wildcard $(addsuffix /*.cpp, src/core))
|
||||
SRCS += $(wildcard $(addsuffix /*.cpp, src/platform))
|
||||
SRCS += $(wildcard $(addsuffix /*.cpp, src/renderer))
|
||||
SRCS += $(wildcard $(addsuffix /*.cpp, src/renderer/**))
|
||||
|
||||
OS = $(shell uname -s)
|
||||
DEBUG ?= false
|
||||
TOOLCHAIN ?= clang
|
||||
IMAGES_OPTIMIZED ?= true
|
||||
FORCE_INTEGRATED_GPU ?= false
|
||||
GRAPHICS_MEMORY_DUMP ?= false
|
||||
OBJ_DIR = objs/make/$(shell echo $(OS) | tr '[:upper:]' '[:lower:]')
|
||||
OBJS := $(addprefix $(OBJ_DIR)/, $(SRCS:.cpp=.o))
|
||||
|
||||
MODE = "release"
|
||||
|
||||
CXX = clang++
|
||||
CXX = clang++
|
||||
CXXFLAGS = -std=c++17 -O3 -fPIC -Wall -Wextra -Werror -DSDL_MAIN_HANDLED
|
||||
INCLUDES = -I./includes -I./src -I./third_party
|
||||
|
||||
ifeq ($(TOOLCHAIN), gcc)
|
||||
CXX = g++
|
||||
CXX = g++
|
||||
CXXFLAGS += -Wno-error=cpp
|
||||
else
|
||||
CXXFLAGS += -Wno-error=#warning
|
||||
endif
|
||||
|
||||
CXXFLAGS = -std=c++17 -O3 -fPIC
|
||||
INCLUDES = -I./includes -I./src -I./third_party
|
||||
|
||||
LDLIBS =
|
||||
|
||||
ifeq ($(OS), Darwin)
|
||||
LDLIBS += -lSDL2
|
||||
LDFLAGS += -L /opt/homebrew/lib -lSDL2
|
||||
CXXFLAGS += -I /opt/homebrew/include
|
||||
NAME = libmlx.dylib
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG), true)
|
||||
CXXFLAGS += -g -D DEBUG
|
||||
MODE = "debug"
|
||||
CXXFLAGS += -g3 -D DEBUG
|
||||
LDFLAGS += -rdynamic
|
||||
endif
|
||||
|
||||
ifeq ($(FORCE_INTEGRATED_GPU), true)
|
||||
CXXFLAGS += -D FORCE_INTEGRATED_GPU
|
||||
_ENABLEDFLAGS += FORCE_INTEGRATED_GPU
|
||||
endif
|
||||
|
||||
ifeq ($(IMAGES_OPTIMIZED), true)
|
||||
CXXFLAGS += -D IMAGE_OPTIMIZED
|
||||
_ENABLEDFLAGS += IMAGE_OPTIMIZED
|
||||
endif
|
||||
|
||||
ifeq ($(GRAPHICS_MEMORY_DUMP), true)
|
||||
CXXFLAGS += -D GRAPHICS_MEMORY_DUMP
|
||||
_ENABLEDFLAGS += GRAPHICS_MEMORY_DUMP
|
||||
endif
|
||||
|
||||
ifeq ($(PROFILER), true)
|
||||
_ENABLEDFLAGS += PROFILER
|
||||
endif
|
||||
|
||||
CXXFLAGS += $(addprefix -D, $(_ENABLEDFLAGS))
|
||||
|
||||
RM = rm -rf
|
||||
|
||||
TPUT = tput -T xterm-256color
|
||||
_RESET := $(shell $(TPUT) sgr0)
|
||||
_BOLD := $(shell $(TPUT) bold)
|
||||
_ITALIC := $(shell $(TPUT) sitm)
|
||||
_UNDER := $(shell $(TPUT) smul)
|
||||
_GREEN := $(shell $(TPUT) setaf 2)
|
||||
_YELLOW := $(shell $(TPUT) setaf 3)
|
||||
_RED := $(shell $(TPUT) setaf 1)
|
||||
_GRAY := $(shell $(TPUT) setaf 8)
|
||||
_PURPLE := $(shell $(TPUT) setaf 5)
|
||||
|
||||
ifeq ($(DEBUG), true)
|
||||
MODE := $(_RESET)$(_PURPLE)$(_BOLD)Debug$(_RESET)$(_PURPLE)
|
||||
COLOR := $(_PURPLE)
|
||||
else
|
||||
MODE := $(_RESET)$(_GREEN)$(_BOLD)Release$(_RESET)$(_GREEN)
|
||||
COLOR := $(_GREEN)
|
||||
endif
|
||||
|
||||
OBJS_TOTAL = $(words $(OBJS))
|
||||
N_OBJS := $(shell find $(OBJ_DIR) -type f -name '*.o' 2>/dev/null | wc -l)
|
||||
OBJS_TOTAL := $(shell echo $$(( $(OBJS_TOTAL) - $(N_OBJS) )))
|
||||
CURR_OBJ = 0
|
||||
|
||||
$(OBJ_DIR)/%.o: %.cpp
|
||||
@printf "\033[1;32m[compiling... "$(MODE)" "$(CXX)"]\033[1;00m "$<"\n"
|
||||
@mkdir -p $(dir $@)
|
||||
@$(eval CURR_OBJ=$(shell echo $$(( $(CURR_OBJ) + 1 ))))
|
||||
@$(eval PERCENT=$(shell echo $$(( $(CURR_OBJ) * 100 / $(OBJS_TOTAL) ))))
|
||||
@printf "$(COLOR)($(_BOLD)%3s%%$(_RESET)$(COLOR)) $(_RESET)Compiling $(_BOLD)$<$(_RESET)\n" "$(PERCENT)"
|
||||
@$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
|
||||
|
||||
all: $(NAME)
|
||||
all: _printbuildinfos
|
||||
@$(MAKE) $(NAME)
|
||||
|
||||
$(NAME): $(OBJ_DIR) $(OBJS)
|
||||
@printf "\033[1;32m[linking ... "$(MODE)"]\033[1;00m "$@"\n"
|
||||
@$(CXX) -shared -o $(NAME) $(OBJS) $(LDLIBS)
|
||||
@printf "\033[1;32m[build finished]\033[1;00m\n"
|
||||
$(NAME): $(OBJS)
|
||||
@printf "Linking $(_BOLD)$(NAME)$(_RESET)\n"
|
||||
@$(CXX) -shared -o $(NAME) $(OBJS) $(LDFLAGS)
|
||||
@printf "$(_BOLD)$(NAME)$(_RESET) compiled $(COLOR)$(_BOLD)successfully$(_RESET)\n"
|
||||
|
||||
$(OBJ_DIR):
|
||||
@mkdir -p $(sort $(addprefix $(OBJ_DIR)/, $(dir $(SRCS))))
|
||||
@printf "\033[1;32m[created objs directory]\033[1;00m\n"
|
||||
_printbuildinfos:
|
||||
@printf "$(_PURPLE)$(_BOLD)MacroLibX $(_RESET)Compiling in $(_BOLD)$(MODE)$(_RESET) mode on $(_BOLD)$(OS)$(_RESET) | Using $(_BOLD)$(CXX)$(_RESET), flags: $(_BOLD)$(_ENABLEDFLAGS)$(_RESET)\n"
|
||||
|
||||
debug:
|
||||
@$(MAKE) all DEBUG=true -j$(shell nproc)
|
||||
|
||||
clean:
|
||||
@$(RM) $(OBJ_DIR)
|
||||
@printf "\033[1;32m[object files removed]\033[1;00m\n"
|
||||
@printf "Cleaned $(_BOLD)$(OBJ_DIR)$(_RESET)\n"
|
||||
|
||||
fclean: clean
|
||||
@$(RM) $(NAME)
|
||||
@printf "\033[1;32m["$(NAME)" removed]\033[1;00m\n"
|
||||
@printf "Cleaned $(_BOLD)$(NAME)$(_RESET)\n"
|
||||
|
||||
re: fclean all
|
||||
re: fclean _printbuildinfos
|
||||
@$(MAKE) $(NAME)
|
||||
|
||||
.PHONY: all clean fclean re
|
||||
.PHONY: all clean debug fclean re
|
||||
|
||||
72
README.md
@@ -1,23 +1,44 @@
|
||||
<div align="center">
|
||||
<img src="./res/logo.png" alt="drawing" width="200"/>
|
||||
<div align="center">
|
||||
<a href="https://github.com/420verfl0w/MacroLibX/actions/workflows/linux_clang.yml"><img src="https://github.com/420verfl0w/MacroLibX/actions/workflows/linux_clang.yml/badge.svg"></a>
|
||||
<a href="https://github.com/420verfl0w/MacroLibX/actions/workflows/linux_gcc.yml"><img src="https://github.com/420verfl0w/MacroLibX/actions/workflows/linux_gcc.yml/badge.svg"></a>
|
||||
<a href="https://github.com/420verfl0w/MacroLibX/actions/workflows/macos_x86.yml"><img src="https://github.com/420verfl0w/MacroLibX/actions/workflows/macos_x86.yml/badge.svg"></a>
|
||||
<a href="https://github.com/seekrs/MacroLibX/actions/workflows/linux_clang.yml"><img src="https://github.com/seekrs/MacroLibX/actions/workflows/linux_clang.yml/badge.svg"></a>
|
||||
<a href="https://github.com/seekrs/MacroLibX/actions/workflows/linux_gcc.yml"><img src="https://github.com/seekrs/MacroLibX/actions/workflows/linux_gcc.yml/badge.svg"></a>
|
||||
<a href="https://github.com/seekrs/MacroLibX/actions/workflows/macos_x86.yml"><img src="https://github.com/seekrs/MacroLibX/actions/workflows/macos_x86.yml/badge.svg"></a>
|
||||
</div>
|
||||
<div align="center">
|
||||
<a href="https://github.com/seekrs/MacroLibX/actions/workflows/windows.yml"><img src="https://github.com/seekrs/MacroLibX/actions/workflows/windows.yml/badge.svg"></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
###### MacroLibX a rewrite of 42 School's MiniLibX using SDL2 and Vulkan.
|
||||
###### MacroLibX, a rewrite of 42 School's MiniLibX using SDL2 and Vulkan.
|
||||
The goal of this version is to provide a light, fast, and modern graphical tool while keeping the same API.
|
||||
|
||||
## 🌟 Features
|
||||
|
||||
### 🚀 Performances
|
||||
Built on top of Vulkan, the MacroLibX takes advantage of its very low-level nature to achieve high performance with great control over available resources.
|
||||
|
||||
### 💻 Cross-Platform
|
||||
Designed to be totally cross-platform, it can run on any SDL2-supported platform that supports Vulkan (even the Nintendo Switch ! theoretically... ).
|
||||
|
||||
### 🗿 Close to the old minilibx
|
||||
One of the guidelines of this lib was to get as close as possible to the old minilibx API, and therefore to the educational choices of the old minilibx.
|
||||
|
||||
### 📖 It's all FOSS
|
||||
Everything in this repo is entirely free and open source, all available under the MIT license (even the third-party libraries used).
|
||||
|
||||
### 🔍 Valgrind suppressions file
|
||||
Experimental for now, a [suppressions file for valgrind](./valgrind.supp) is given to remove potential leaks comming from Xorg, Nvidia drivers, SDL2, or any other tool which the user has no control. It is far from perfect at the moment and may allow some leaks but it will block the majority.
|
||||
|
||||
### ⛔ Error system
|
||||
Strong error handling informing the user of problems with their code and even capable of informing them of graphics memory leaks that tools like Valgrind cannot detect.
|
||||
|
||||
## 🖥️ Installation
|
||||
|
||||
### Dependencies
|
||||
|
||||
You first need to install the proper dependencies for your operating-system.
|
||||
|
||||
#### 🐧 Linux
|
||||
|
||||
Here are a few common cases for different Linux distributions:
|
||||
|
||||
<details>
|
||||
@@ -37,30 +58,28 @@ sudo apt install libsdl2-2.0-0 libsdl2-dev build-essential
|
||||
<pre><code>sudo pacman -S sdl2</code></pre>
|
||||
</details>
|
||||
|
||||
#### 🍎 macOS
|
||||
<br>
|
||||
Note that you need to have up do date video drivers with <code>libvulkan.so</code> installed.
|
||||
|
||||
#### 🍎 macOS
|
||||
[MacroLibX](#) on macOS requires [SDL2](#) and [MoltenVK](https://github.com/KhronosGroup/MoltenVK). You can install both using the [Homebrew](https://brew.sh) package manager:
|
||||
```sh
|
||||
brew install molten-vk
|
||||
brew install SDL2
|
||||
```
|
||||
|
||||
### Clone and Build
|
||||
### 🪟 Windows
|
||||
To build on Windows you may need to use the [xmake](https://xmake.io) build. [Here's](./XMAKE_BUILD.md) how you can use it.
|
||||
|
||||
### Clone and Build
|
||||
Finally, you can clone the Git repository. When inside it, run the GNU `make` command to compile MacroLibX.
|
||||
```bash
|
||||
git clone https://github.com/420verfl0w/MacroLibX.git
|
||||
git clone https://github.com/seekrs/MacroLibX.git
|
||||
cd MacroLibX
|
||||
make
|
||||
```
|
||||
|
||||
If you want to build using GCC you can add `TOOLCHAIN=gcc` to your `make` command
|
||||
```bash
|
||||
make TOOLCHAIN=gcc
|
||||
```
|
||||
|
||||
## 🔨 Compile your project
|
||||
|
||||
To compile your project with MacroLibX, you just provide the shared library path in your compilation/linking command:
|
||||
|
||||
```sh
|
||||
@@ -73,17 +92,22 @@ And you can enjoy your project
|
||||
<img src="./res/screenshot_test.png" alt="drawing" width="400"/>
|
||||
</p>
|
||||
|
||||
### ⚠️ Troubleshooting
|
||||
## ⚙️ Some compilation configurations
|
||||
|
||||
#### If you run into glitches when writing or reading pixels from images
|
||||
### 📦 Compile mode
|
||||
By default the mlx is built in release mode but you can switch to debug by using `make DEBUG=true`.
|
||||
|
||||
You need to add `IMAGES_OPTIMIZED=false` to your `make` command:
|
||||
### 🛠️ Set the toolchain
|
||||
If you want to use `GCC` to build the mlx you can use `make TOOLCHAIN=gcc`
|
||||
|
||||
```sh
|
||||
# In your cloned environment, inside the MacroLibX folder
|
||||
make IMAGES_OPTIMIZED=false
|
||||
```
|
||||
### ⚠️⚠️⚠️ 🖼️ Image optimisations ⚠️⚠️⚠️
|
||||
If you run into glitches when writing or reading pixels from images you can turn off images optimisations by using `make IMAGES_OPTIMIZED=false`.
|
||||
|
||||
### 🖥️ Force the integrated GPU (not recommended)
|
||||
You can force the mlx to use your integrated GPU by using `make FORCE_INTEGRATED_GPU=true`. Note that there are a lot of chances that your application crashes by using that.
|
||||
|
||||
### 💽 Dump the graphics memory
|
||||
The mlx can dump it's graphics memory use to json files every two seconds by enabling this option `make GRAPHICS_MEMORY_DUMP=true`.
|
||||
|
||||
## License
|
||||
|
||||
This project and all its files, except the [`third_party`](./third_party) directory or unless otherwise mentionned, are licenced under the [MIT license](./LICENSE).
|
||||
This project and all its files, even the [`third_party`](./third_party) directory or unless otherwise mentionned, are licenced under the [MIT license](./LICENSE).
|
||||
|
||||
47
XMAKE_BUILD.md
git.filemode.normal_file
@@ -0,0 +1,47 @@
|
||||
# 🏗️ xmake build
|
||||
To build on Windows (if you don't use [WSL](https://learn.microsoft.com/en-us/windows/wsl/install)), the MacroLibX uses [xmake](https://xmake.io), a build system which will download and compile all dependencies it won't find on your computer.
|
||||
|
||||
## 💾 Install xmake
|
||||
You can find how to install it on your system [here](https://xmake.io/#/guide/installation). Note that you can also download a [portable version](https://github.com/xmake-io/xmake/releases) of xmake if you wish not to install it.
|
||||
|
||||
## ⚙️ Configure the MacroLibX build
|
||||
Just as the Makfile build system, you can configure how xmake should build the MacroLibX. The base command to configure it is `xmake config [opts...]` or `xmake f [opts...]`.
|
||||
|
||||
### 📦 Compile mode
|
||||
You can configure xmake to build the mlx in debug mode or in release mode (release mode is enabled by default). To do so you can use `xmake config --mode=debug` or `xmake config --mode=release`.
|
||||
|
||||
### 🛠️ Set the toolchain
|
||||
To change the compilation toolchain you can use `xmake config --toolchain=[gcc|clang|...]`
|
||||
|
||||
### ⚠️⚠️⚠️ 🖼️ Image optimisations ⚠️⚠️⚠️
|
||||
If you run into glitches when writing or reading pixels from images you can turn off images optimisations by using `xmake config --images_optimized=n`.
|
||||
|
||||
### 🖥️ Force the integrated GPU (not recommended)
|
||||
You can force the mlx to use your integrated GPU using `xmake config --force_integrated_gpu=y`. Note that there are a lot of chances that your application crashes by using that.
|
||||
|
||||
### 💽 Dump the graphics memory
|
||||
The mlx can dump it's graphics memory use to json files every two seconds by enabling this option `xmake config --graphics_memory_dump=y`.
|
||||
|
||||
### 🪛 A possible build configuration
|
||||
As a configuration example here's how the command can look like `xmake config --mode=debug --toolchain=clang --graphics_memory_dump=y --images_optimized=n`
|
||||
|
||||
## 🚧 Build the lib
|
||||
|
||||
### Compile using command-line (first method)
|
||||
Once you're ready to compile the lib, run `xmake` (or `xmake -jX` if you wish not to use all your computer threads, with X being the number of threads you wish to use) and watch as the lib compiles.
|
||||
|
||||
### Generate a project (second method)
|
||||
xmake can also generate a project file for another tool:
|
||||
* Visual Studio : `xmake project -k vs`
|
||||
* CMakeLists.txt (which you can open in CLion and more) : `xmake project -k cmake`
|
||||
* Makefile : `xmake project -k make`
|
||||
* Ninja : `xmake project -k ninja`
|
||||
* XCode : `xmake project -k xcode`
|
||||
|
||||
You should now be able to open the project file with the tool of your choice.
|
||||
|
||||
## 😋 Enjoy
|
||||
Enjoy you project built with the mlx
|
||||
<p align="center">
|
||||
<img src="./res/screenshot_test_windows.png" alt="drawing" width="400"/>
|
||||
</p>
|
||||
BIN
example/42_logo.bmp
git.filemode.normal_file
|
After Width: | Height: | Size: 30 KiB |
BIN
example/42_logo.jpg
git.filemode.normal_file
|
After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
12
example/build.sh
git.filemode.executable_file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ -e a.out ]; then
|
||||
rm a.out
|
||||
fi
|
||||
|
||||
if [ $(uname -s) = 'Darwin' ]; then
|
||||
clang main.c ../libmlx.dylib -L /opt/homebrew/lib -lSDL2 -g;
|
||||
else
|
||||
clang main.c ../libmlx.so -lSDL2 -g -Wall -Wextra -Werror;
|
||||
fi
|
||||
|
||||
182
example/main.c
git.filemode.normal_file
@@ -0,0 +1,182 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* main.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/04 17:55:21 by maldavid #+# #+# */
|
||||
/* Updated: 2024/03/25 16:16:07 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../includes/mlx.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void* mlx;
|
||||
void* win;
|
||||
void* logo_png;
|
||||
void* logo_jpg;
|
||||
void* logo_bmp;
|
||||
void* img;
|
||||
} mlx_t;
|
||||
|
||||
//void* img = NULL;
|
||||
|
||||
int update(void* param)
|
||||
{
|
||||
static int i = 0;
|
||||
mlx_t* mlx = (mlx_t*)param;
|
||||
|
||||
if(i == 200)
|
||||
mlx_clear_window(mlx->mlx, mlx->win);
|
||||
/*
|
||||
if(img)
|
||||
mlx_destroy_image(mlx->mlx,img);
|
||||
img = mlx_new_image(mlx->mlx, 800, 800);
|
||||
mlx_set_image_pixel(mlx->mlx, img, 4, 4, 0xFF00FF00);
|
||||
mlx_put_image_to_window(mlx->mlx, mlx->win, img, 0, 0);
|
||||
*/
|
||||
if(i >= 250)
|
||||
mlx_set_font_scale(mlx->mlx, mlx->win, "default", 16.f);
|
||||
else
|
||||
mlx_set_font_scale(mlx->mlx, mlx->win, "default", 6.f);
|
||||
mlx_string_put(mlx->mlx, mlx->win, 160, 120, 0xFFFF2066, "this text should be hidden");
|
||||
|
||||
mlx_put_image_to_window(mlx->mlx, mlx->win, mlx->logo_png, 100, 100);
|
||||
mlx_put_image_to_window(mlx->mlx, mlx->win, mlx->logo_jpg, 210, 150);
|
||||
mlx_put_image_to_window(mlx->mlx, mlx->win, mlx->logo_bmp, 220, 40);
|
||||
mlx_put_image_to_window(mlx->mlx, mlx->win, mlx->img, 150, 60);
|
||||
|
||||
mlx_set_font(mlx->mlx, mlx->win, "default");
|
||||
mlx_string_put(mlx->mlx, mlx->win, 20, 50, 0xFFFFFFFF, "that's a text");
|
||||
|
||||
int color = 0;
|
||||
for(int j = 0; j < 400; j++)
|
||||
{
|
||||
mlx_pixel_put(mlx->mlx, mlx->win, j, j, 0xFFFF0000 + color);
|
||||
mlx_pixel_put(mlx->mlx, mlx->win, 399 - j, j, 0xFF0000FF);
|
||||
color += (color < 255);
|
||||
}
|
||||
|
||||
i++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* create_image(mlx_t* mlx)
|
||||
{
|
||||
unsigned char pixel[4];
|
||||
void* img = mlx_new_image(mlx->mlx, 100, 100);
|
||||
for(int i = 0, j = 0, k = 0; i < (100 * 100) * 4; i += 4, j++)
|
||||
{
|
||||
if(j >= 100)
|
||||
{
|
||||
j = 0;
|
||||
k++;
|
||||
}
|
||||
if(i < 10000 || i > 20000)
|
||||
{
|
||||
pixel[0] = i;
|
||||
pixel[1] = j;
|
||||
pixel[2] = k;
|
||||
pixel[3] = 0x99;
|
||||
mlx_set_image_pixel(mlx->mlx, img, j, k, *((int *)pixel));
|
||||
}
|
||||
}
|
||||
return img;
|
||||
}
|
||||
|
||||
int key_hook(int key, void* param)
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
mlx_t* mlx = (mlx_t*)param;
|
||||
|
||||
mlx_mouse_get_pos(mlx->mlx, &x, &y);
|
||||
switch(key)
|
||||
{
|
||||
case 41 : // ESCAPE
|
||||
mlx_loop_end(mlx->mlx);
|
||||
break;
|
||||
case 22 : // (S)how
|
||||
mlx_mouse_show();
|
||||
break;
|
||||
case 11 : // (H)ide
|
||||
mlx_mouse_hide();
|
||||
break;
|
||||
case 6 : // (C)lear
|
||||
mlx_clear_window(mlx->mlx, mlx->win);
|
||||
break;
|
||||
case 79 : // RIGHT KEY
|
||||
mlx_mouse_move(mlx->mlx, mlx->win, x + 10, y);
|
||||
break;
|
||||
case 80 : // LEFT KEY
|
||||
mlx_mouse_move(mlx->mlx, mlx->win, x - 10, y);
|
||||
break;
|
||||
case 81 : // UP KEY
|
||||
mlx_mouse_move(mlx->mlx, mlx->win, x, y + 10);
|
||||
break;
|
||||
case 82 : // DOWN KEY
|
||||
mlx_mouse_move(mlx->mlx, mlx->win, x, y - 10);
|
||||
break;
|
||||
|
||||
default : break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int window_hook(int event, void* param)
|
||||
{
|
||||
if(event == 0)
|
||||
mlx_loop_end(((mlx_t*)param)->mlx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
mlx_t mlx;
|
||||
int w;
|
||||
int h;
|
||||
int dummy;
|
||||
|
||||
mlx.mlx = mlx_init();
|
||||
mlx.win = mlx_new_window(mlx.mlx, 400, 400, "My window");
|
||||
|
||||
mlx_set_fps_goal(mlx.mlx, 60);
|
||||
|
||||
mlx_on_event(mlx.mlx, mlx.win, MLX_KEYDOWN, key_hook, &mlx);
|
||||
mlx_on_event(mlx.mlx, mlx.win, MLX_WINDOW_EVENT, window_hook, &mlx);
|
||||
|
||||
mlx.logo_png = mlx_png_file_to_image(mlx.mlx, "42_logo.png", &dummy, &dummy);
|
||||
mlx.logo_bmp = mlx_bmp_file_to_image(mlx.mlx, "42_logo.bmp", &dummy, &dummy);
|
||||
mlx.logo_jpg = mlx_jpg_file_to_image(mlx.mlx, "42_logo.jpg", &dummy, &dummy);
|
||||
|
||||
mlx_pixel_put(mlx.mlx, mlx.win, 200, 10, 0xFFFF00FF);
|
||||
mlx_put_image_to_window(mlx.mlx, mlx.win, mlx.logo_png, 10, 190);
|
||||
|
||||
mlx.img = create_image(&mlx);
|
||||
|
||||
|
||||
mlx_string_put(mlx.mlx, mlx.win, 0, 10, 0xFFFFFF00, "fps:");
|
||||
mlx_string_put(mlx.mlx, mlx.win, 0, 20, 0xFFFFFFFF, "fps:");
|
||||
|
||||
mlx_set_font_scale(mlx.mlx, mlx.win, "font.ttf", 16.f);
|
||||
mlx_string_put(mlx.mlx, mlx.win, 20, 20, 0xFF0020FF, "that text will disappear");
|
||||
|
||||
mlx_loop_hook(mlx.mlx, update, &mlx);
|
||||
mlx_loop(mlx.mlx);
|
||||
|
||||
mlx_get_screens_size(mlx.mlx, mlx.win, &w, &h);
|
||||
printf("screen size : %dx%d\n", w, h);
|
||||
|
||||
mlx_destroy_image(mlx.mlx, mlx.logo_png);
|
||||
mlx_destroy_image(mlx.mlx, mlx.logo_jpg);
|
||||
mlx_destroy_image(mlx.mlx, mlx.logo_bmp);
|
||||
mlx_destroy_image(mlx.mlx, mlx.img);
|
||||
mlx_destroy_window(mlx.mlx, mlx.win);
|
||||
mlx_destroy_display(mlx.mlx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
4
example/run.sh
git.filemode.executable_file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
bash ./build.sh
|
||||
./a.out
|
||||
122
includes/mlx.h
@@ -6,15 +6,18 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/04 16:56:35 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/23 14:32:06 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/09/12 01:28:12 by tdelage ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
// MacroLibX official repo https://github.com/420verfl0w/MacroLibX
|
||||
// MacroLibX official repo https://github.com/seekrs/MacroLibX
|
||||
// MacroLibX official website https://macrolibx.kbz8.me/
|
||||
|
||||
#ifndef __MACRO_LIB_X_H__
|
||||
#define __MACRO_LIB_X_H__
|
||||
|
||||
#include "mlx_profile.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -25,15 +28,18 @@ typedef enum
|
||||
MLX_KEYUP = 1,
|
||||
MLX_MOUSEDOWN = 2,
|
||||
MLX_MOUSEUP = 3,
|
||||
MLX_WINDOW_EVENT = 4
|
||||
MLX_MOUSEWHEEL = 4,
|
||||
MLX_WINDOW_EVENT = 5
|
||||
} mlx_event_type;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initializes the MLX internal application
|
||||
*
|
||||
* @return (void*) An opaque pointer to the internal MLX application or NULL (0x0) in case of error
|
||||
*/
|
||||
void* mlx_init();
|
||||
MLX_API void* mlx_init();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Creates a new window
|
||||
@@ -45,7 +51,19 @@ void* mlx_init();
|
||||
*
|
||||
* @return (void*) An opaque pointer to the internal MLX window or NULL (0x0) in case of error
|
||||
*/
|
||||
void* mlx_new_window(void* mlx, int w, int h, const char* title);
|
||||
MLX_API void* mlx_new_window(void* mlx, int w, int h, const char* title);
|
||||
|
||||
/**
|
||||
* @brief Creates a new window
|
||||
*
|
||||
* @param mlx Internal MLX application
|
||||
* @param win Internal window to move
|
||||
* @param x New x position
|
||||
* @param y New y position
|
||||
*
|
||||
*/
|
||||
MLX_API void mlx_set_window_position(void *mlx, void *win, int x, int y);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gives a function to be executed at each loop turn
|
||||
@@ -56,8 +74,8 @@ void* mlx_new_window(void* mlx, int w, int h, const char* title);
|
||||
*
|
||||
* @return (int) Always return 0, made this to copy the behaviour of the original MLX
|
||||
*/
|
||||
MLX_API int mlx_loop_hook(void* mlx, int (*f)(void*), void* param);
|
||||
|
||||
int mlx_loop_hook(void* mlx, int (*f)(), void* param);
|
||||
|
||||
/**
|
||||
* @brief Starts the internal main loop
|
||||
@@ -66,7 +84,8 @@ int mlx_loop_hook(void* mlx, int (*f)(), void* param);
|
||||
*
|
||||
* @return (int) Always return 0, made this to copy the behaviour of the original MLX
|
||||
*/
|
||||
int mlx_loop(void* mlx);
|
||||
MLX_API int mlx_loop(void* mlx);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Ends the internal main loop
|
||||
@@ -75,24 +94,27 @@ int mlx_loop(void* mlx);
|
||||
*
|
||||
* @return (int) Always return 0, made this to copy the behaviour of the original MLX
|
||||
*/
|
||||
int mlx_loop_end(void* mlx);
|
||||
MLX_API int mlx_loop_end(void* mlx);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Shows mouse cursor
|
||||
*
|
||||
* @return (int) Always return 0, made this to copy the behaviour of the original MLX
|
||||
*/
|
||||
int mlx_mouse_show();
|
||||
MLX_API int mlx_mouse_show();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Hides mouse cursor
|
||||
*
|
||||
* @return (int) Always return 0, made this to copy the behaviour of the original MLX
|
||||
*/
|
||||
int mlx_mouse_hide();
|
||||
MLX_API int mlx_mouse_hide();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Moves cursor to givent position
|
||||
* @brief Moves cursor to given position
|
||||
*
|
||||
* @param mlx Internal MLX application
|
||||
* @param win Internal window from which cursor moves
|
||||
@@ -101,7 +123,8 @@ int mlx_mouse_hide();
|
||||
*
|
||||
* @return (int) Always return 0, made this to copy the behaviour of the original MLX
|
||||
*/
|
||||
int mlx_mouse_move(void* mlx, void* win, int x, int y);
|
||||
MLX_API int mlx_mouse_move(void* mlx, void* win, int x, int y);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get cursor's position
|
||||
@@ -112,7 +135,7 @@ int mlx_mouse_move(void* mlx, void* win, int x, int y);
|
||||
*
|
||||
* @return (int) Always return 0, made this to copy the behaviour of the original MLX
|
||||
*/
|
||||
int mlx_mouse_get_pos(void* mlx, int* x, int* y);
|
||||
MLX_API int mlx_mouse_get_pos(void* mlx, int* x, int* y);
|
||||
|
||||
|
||||
/**
|
||||
@@ -126,7 +149,7 @@ int mlx_mouse_get_pos(void* mlx, int* x, int* y);
|
||||
*
|
||||
* @return (int) Always return 0, made this to copy the behaviour of the original MLX
|
||||
*/
|
||||
int mlx_on_event(void* mlx, void* win, mlx_event_type event, int (*f)(), void* param);
|
||||
MLX_API int mlx_on_event(void* mlx, void* win, mlx_event_type event, int (*f)(int, void*), void* param);
|
||||
|
||||
|
||||
/**
|
||||
@@ -136,14 +159,14 @@ int mlx_on_event(void* mlx, void* win, mlx_event_type event, int (*f)(), void* p
|
||||
* @param win Internal window
|
||||
* @param x X coordinate
|
||||
* @param y Y coordinate
|
||||
* @param color Color of the pixel (coded on 3 bytes in an int, 0x00RRGGBB)
|
||||
* @param color Color of the pixel (coded on 4 bytes in an int, 0xAARRGGBB)
|
||||
*
|
||||
* Note : If your're reading pixel colors from an image, don't forget to shift them
|
||||
* one byte to the right as image pixels are encoded as 0xRRGGBBAA and pixel put takes 0x00RRGGBB.
|
||||
* one byte to the right as image pixels are encoded as 0xRRGGBBAA and pixel put takes 0xAARRGGBB.
|
||||
*
|
||||
* @return (int) Always return 0, made this to copy the behaviour of the original MLX
|
||||
*/
|
||||
int mlx_pixel_put(void* mlx, void* win, int x, int y, int color);
|
||||
MLX_API int mlx_pixel_put(void* mlx, void* win, int x, int y, int color);
|
||||
|
||||
|
||||
/**
|
||||
@@ -155,7 +178,8 @@ int mlx_pixel_put(void* mlx, void* win, int x, int y, int color);
|
||||
*
|
||||
* @return (void*) An opaque pointer to the internal image or NULL (0x0) in case of error
|
||||
*/
|
||||
void* mlx_new_image(void* mlx, int width, int height);
|
||||
MLX_API void* mlx_new_image(void* mlx, int width, int height);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get image pixel data
|
||||
@@ -170,12 +194,13 @@ void* mlx_new_image(void* mlx, int width, int height);
|
||||
* /!\ If you run into glitches when writing or reading pixels from images /!\
|
||||
* You need to add IMAGES_OPTIMIZED=false to your make mlx command
|
||||
* ```
|
||||
* ~ git clone https://github.com/420verfl0w/MacroLibX.git
|
||||
* ~ git clone https://github.com/seekrs/MacroLibX.git
|
||||
* ~ cd MacroLibX
|
||||
* ~ make IMAGES_OPTIMIZED=false
|
||||
* ```
|
||||
*/
|
||||
int mlx_get_image_pixel(void* mlx, void* img, int x, int y);
|
||||
MLX_API int mlx_get_image_pixel(void* mlx, void* img, int x, int y);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set image pixel data
|
||||
@@ -191,12 +216,13 @@ int mlx_get_image_pixel(void* mlx, void* img, int x, int y);
|
||||
* /!\ If you run into glitches when writing or reading pixels from images /!\
|
||||
* You need to add IMAGES_OPTIMIZED=false to your make mlx command
|
||||
* ```
|
||||
* ~ git clone https://github.com/420verfl0w/MacroLibX.git
|
||||
* ~ git clone https://github.com/seekrs/MacroLibX.git
|
||||
* ~ cd MacroLibX
|
||||
* ~ make IMAGES_OPTIMIZED=false
|
||||
* ```
|
||||
*/
|
||||
void mlx_set_image_pixel(void* mlx, void* img, int x, int y, int color);
|
||||
MLX_API void mlx_set_image_pixel(void* mlx, void* img, int x, int y, int color);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Put image to the given window
|
||||
@@ -209,7 +235,8 @@ void mlx_set_image_pixel(void* mlx, void* img, int x, int y, int color);
|
||||
*
|
||||
* @return (int) Always return 0, made this to copy the behaviour of the original MLX
|
||||
*/
|
||||
int mlx_put_image_to_window(void* mlx, void* win, void* img, int x, int y);
|
||||
MLX_API int mlx_put_image_to_window(void* mlx, void* win, void* img, int x, int y);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Destroys internal image
|
||||
@@ -219,7 +246,7 @@ int mlx_put_image_to_window(void* mlx, void* win, void* img, int x, int y);
|
||||
*
|
||||
* @return (int) Always return 0, made this to copy the behaviour of the original MLX
|
||||
*/
|
||||
int mlx_destroy_image(void* mlx, void* img);
|
||||
MLX_API int mlx_destroy_image(void* mlx, void* img);
|
||||
|
||||
|
||||
/**
|
||||
@@ -232,7 +259,8 @@ int mlx_destroy_image(void* mlx, void* img);
|
||||
*
|
||||
* @return (void*) An opaque pointer to the internal image or NULL (0x0) in case of error
|
||||
*/
|
||||
void* mlx_png_file_to_image(void* mlx, char* filename, int* width, int* height);
|
||||
MLX_API void* mlx_png_file_to_image(void* mlx, char* filename, int* width, int* height);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a new image from a jpg file
|
||||
@@ -244,7 +272,8 @@ void* mlx_png_file_to_image(void* mlx, char* filename, int* width, int* height);
|
||||
*
|
||||
* @return (void*) An opaque pointer to the internal image or NULL (0x0) in case of error
|
||||
*/
|
||||
void* mlx_jpg_file_to_image(void* mlx, char* filename, int* width, int* height);
|
||||
MLX_API void* mlx_jpg_file_to_image(void* mlx, char* filename, int* width, int* height);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a new image from a bmp file
|
||||
@@ -256,7 +285,7 @@ void* mlx_jpg_file_to_image(void* mlx, char* filename, int* width, int* height);
|
||||
*
|
||||
* @return (void*) An opaque pointer to the internal image or NULL (0x0) in case of error
|
||||
*/
|
||||
void* mlx_bmp_file_to_image(void* mlx, char* filename, int* width, int* height);
|
||||
MLX_API void* mlx_bmp_file_to_image(void* mlx, char* filename, int* width, int* height);
|
||||
|
||||
|
||||
/**
|
||||
@@ -266,12 +295,12 @@ void* mlx_bmp_file_to_image(void* mlx, char* filename, int* width, int* height);
|
||||
* @param win Internal window
|
||||
* @param x X coordinate
|
||||
* @param y Y coordinate
|
||||
* @param color Color of the pixel (coded on 3 bytes in an int, 0x00RRGGBB)
|
||||
* @param color Color of the pixel (coded on 4 bytes in an int, 0xAARRGGBB)
|
||||
* @param str Text to put
|
||||
*
|
||||
* @return (int) Always return 0, made this to copy the behaviour of the original MLX
|
||||
*/
|
||||
int mlx_string_put(void* mlx, void* win, int x, int y, int color, char* str);
|
||||
MLX_API int mlx_string_put(void* mlx, void* win, int x, int y, int color, char* str);
|
||||
|
||||
|
||||
/**
|
||||
@@ -279,23 +308,24 @@ int mlx_string_put(void* mlx, void* win, int x, int y, int color, char* str);
|
||||
*
|
||||
* @param mlx Internal MLX application
|
||||
* @param win Internal window
|
||||
* @param filepath Filepath to the font
|
||||
* @param filepath Filepath to the font or "default" to reset to the embedded font
|
||||
*
|
||||
* @return (void)
|
||||
*/
|
||||
void mlx_set_font(void* mlx, void* win, char* filepath);
|
||||
MLX_API void mlx_set_font(void* mlx, void* win, char* filepath);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Loads a font to be used by `mlx_string_put` and scales it
|
||||
*
|
||||
* @param mlx Internal MLX application
|
||||
* @param win Internal window
|
||||
* @param filepath Filepath to the font
|
||||
* @param filepath Filepath to the font or "default" to reset to the embedded font
|
||||
* @param scale Scale to apply to the font
|
||||
*
|
||||
* @return (void)
|
||||
*/
|
||||
void mlx_set_font_scale(void* mlx, void* win, char* filepath, float scale);
|
||||
MLX_API void mlx_set_font_scale(void* mlx, void* win, char* filepath, float scale);
|
||||
|
||||
|
||||
/**
|
||||
@@ -306,7 +336,7 @@ void mlx_set_font_scale(void* mlx, void* win, char* filepath, float scale);
|
||||
*
|
||||
* @return (int) Always return 0, made this to copy the behaviour of the original MLX
|
||||
*/
|
||||
int mlx_clear_window(void* mlx, void* win);
|
||||
MLX_API int mlx_clear_window(void* mlx, void* win);
|
||||
|
||||
|
||||
/**
|
||||
@@ -317,7 +347,7 @@ int mlx_clear_window(void* mlx, void* win);
|
||||
*
|
||||
* @return (int) Always return 0, made this to copy the behaviour of the original MLX
|
||||
*/
|
||||
int mlx_destroy_window(void* mlx, void* win);
|
||||
MLX_API int mlx_destroy_window(void* mlx, void* win);
|
||||
|
||||
/**
|
||||
* @brief Destroy internal MLX application
|
||||
@@ -326,19 +356,31 @@ int mlx_destroy_window(void* mlx, void* win);
|
||||
*
|
||||
* @return (int) Always return 0, made this to copy the behaviour of the original MLX
|
||||
*/
|
||||
int mlx_destroy_display(void* mlx);
|
||||
MLX_API int mlx_destroy_display(void* mlx);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get screen size
|
||||
* @brief Get the size of the screen the given window is on
|
||||
*
|
||||
* @param mlx Internal MLX application
|
||||
* @param x Get X size
|
||||
* @param y Get Y size
|
||||
* @param win Internal window
|
||||
* @param w Get width size
|
||||
* @param h Get height size
|
||||
*
|
||||
* @return (int) Always return 0, made this to copy the behaviour of the original MLX
|
||||
*/
|
||||
int mlx_get_screens_size(void* mlx, int* w, int* h);
|
||||
MLX_API int mlx_get_screens_size(void* mlx, void* win, int* w, int* h);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Caps the FPS
|
||||
*
|
||||
* @param mlx Internal MLX application
|
||||
* @param fps The FPS cap
|
||||
*
|
||||
* @return (int) Always return 0
|
||||
*/
|
||||
MLX_API int mlx_set_fps_goal(void* mlx, int fps);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
194
includes/mlx_profile.h
git.filemode.normal_file
@@ -0,0 +1,194 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* mlx_profile.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/11/10 08:49:17 by maldavid #+# #+# */
|
||||
/* Updated: 2024/01/03 15:33:35 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __MLX_PROFILE__
|
||||
#define __MLX_PROFILE__
|
||||
|
||||
// Try to identify the compiler
|
||||
#if defined(__BORLANDC__)
|
||||
#define MLX_COMPILER_BORDLAND
|
||||
#elif defined(__clang__)
|
||||
#define MLX_COMPILER_CLANG
|
||||
#ifdef __MINGW32__
|
||||
#define MLX_COMPILER_MINGW
|
||||
#ifdef __MINGW64_VERSION_MAJOR
|
||||
#define MLX_COMPILER_MINGW_W64
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(__GNUC__) || defined(__MINGW32__)
|
||||
#define MLX_COMPILER_GCC
|
||||
#ifdef __MINGW32__
|
||||
#define MLX_COMPILER_MINGW
|
||||
#ifdef __MINGW64_VERSION_MAJOR
|
||||
#define MLX_COMPILER_MINGW_W64
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(__INTEL_COMPILER) || defined(__ICL)
|
||||
#define MLX_COMPILER_INTEL
|
||||
#elif defined(_MSC_VER)
|
||||
#define MLX_COMPILER_MSVC
|
||||
#else
|
||||
#define MLX_COMPILER_UNKNOWN
|
||||
#warning "This compiler is not fully supported"
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#define MLX_PLAT_WINDOWS
|
||||
#elif defined(__linux__)
|
||||
#define MLX_PLAT_LINUX
|
||||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
#define MLX_PLAT_MACOS
|
||||
#elif defined(unix) || defined(__unix__) || defined(__unix)
|
||||
#define MLX_PLAT_UNIX
|
||||
#else
|
||||
#error "Unknown environment (not Windows, not Linux, not MacOS, not Unix)"
|
||||
#endif
|
||||
|
||||
#ifdef MLX_PLAT_WINDOWS
|
||||
#ifdef MLX_COMPILER_MSVC
|
||||
#ifdef MLX_BUILD
|
||||
#define MLX_API __declspec(dllexport)
|
||||
#else
|
||||
#define MLX_API __declspec(dllimport)
|
||||
#endif
|
||||
#elif defined(MLX_COMPILER_GCC)
|
||||
#ifdef MLX_BUILD
|
||||
#define MLX_API __attribute__((dllexport))
|
||||
#else
|
||||
#define MLX_API __attribute__((dllimport))
|
||||
#endif
|
||||
#else
|
||||
#define MLX_API
|
||||
#endif
|
||||
#elif defined(MLX_COMPILER_GCC)
|
||||
#define MLX_API __attribute__((visibility("default")))
|
||||
#else
|
||||
#define MLX_API
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || (defined(__MWERKS__) && (__MWERKS__ >= 0x3000)) || (defined(__ICC) && (__ICC >= 600)) || defined(__ghs__)
|
||||
#define MLX_FUNC_SIG __PRETTY_FUNCTION__
|
||||
#elif defined(__DMC__) && (__DMC__ >= 0x810)
|
||||
#define MLX_FUNC_SIG __PRETTY_FUNCTION__
|
||||
#elif (defined(__FUNCSIG__) || (_MSC_VER))
|
||||
#define MLX_FUNC_SIG __FUNCSIG__
|
||||
#elif (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 600)) || (defined(__IBMCPP__) && (__IBMCPP__ >= 500))
|
||||
#define MLX_FUNC_SIG __FUNCTION__
|
||||
#elif defined(__BORLANDC__) && (__BORLANDC__ >= 0x550)
|
||||
#define MLX_FUNC_SIG __FUNC__
|
||||
#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901)
|
||||
#define MLX_FUNC_SIG __func__
|
||||
#elif defined(__cplusplus) && (__cplusplus >= 201103)
|
||||
#define MLX_FUNC_SIG __func__
|
||||
#else
|
||||
#define MLX_FUNC_SIG "Unknown function"
|
||||
#endif
|
||||
|
||||
#ifndef __cplusplus // if we compile in C
|
||||
#ifdef __STDC__
|
||||
#ifdef __STDC_VERSION__
|
||||
#if __STDC_VERSION__ == 199409L
|
||||
#define MLX_C_VERSION 1994
|
||||
#elif __STDC_VERSION__ == 199901L
|
||||
#define MLX_C_VERSION 1999
|
||||
#elif __STDC_VERSION__ == 201112L
|
||||
#define MLX_C_VERSION 2011
|
||||
#elif __STDC_VERSION__ == 201710L
|
||||
#define MLX_C_VERSION 2017
|
||||
#elif __STDC_VERSION__ == 202311L
|
||||
#define MLX_C_VERSION 2023
|
||||
#else
|
||||
#define MLX_C_VERSION 0
|
||||
#endif
|
||||
#else
|
||||
#define MLX_C_VERSION 0
|
||||
#endif
|
||||
#else
|
||||
#define MLX_C_VERSION 0
|
||||
#endif
|
||||
#else
|
||||
#define MLX_C_VERSION 0
|
||||
#endif
|
||||
|
||||
#if defined(MLX_PLAT_WINDOWS)
|
||||
#define VK_USE_PLATFORM_WIN32_KHR
|
||||
#ifdef __cplusplus
|
||||
constexpr const char* VULKAN_LIB_NAME = "vulkan-1.dll";
|
||||
#endif
|
||||
#elif defined(MLX_PLAT_MACOS)
|
||||
#define VK_USE_PLATFORM_MACOS_MVK
|
||||
#define VK_USE_PLATFORM_METAL_EXT
|
||||
#ifdef __cplusplus
|
||||
constexpr const char* VULKAN_LIB_NAME = "libvulkan.dylib / libvulkan.1.dylib / libMoltenVK.dylib";
|
||||
#endif
|
||||
#else
|
||||
#define VK_USE_PLATFORM_XLIB_KHR
|
||||
#define VK_USE_PLATFORM_WAYLAND_KHR
|
||||
#ifdef __cplusplus
|
||||
constexpr const char* VULKAN_LIB_NAME = "libvulkan.so / libvulkan.so.1";
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Checking common assumptions
|
||||
#ifdef __cplusplus
|
||||
#include <climits>
|
||||
#include <cstdint>
|
||||
|
||||
static_assert(CHAR_BIT == 8, "CHAR_BIT is expected to be 8");
|
||||
|
||||
static_assert(sizeof(int8_t) == 1, "int8_t is not of the correct size" );
|
||||
static_assert(sizeof(int16_t) == 2, "int16_t is not of the correct size");
|
||||
static_assert(sizeof(int32_t) == 4, "int32_t is not of the correct size");
|
||||
static_assert(sizeof(int64_t) == 8, "int64_t is not of the correct size");
|
||||
|
||||
static_assert(sizeof(uint8_t) == 1, "uint8_t is not of the correct size" );
|
||||
static_assert(sizeof(uint16_t) == 2, "uint16_t is not of the correct size");
|
||||
static_assert(sizeof(uint32_t) == 4, "uint32_t is not of the correct size");
|
||||
static_assert(sizeof(uint64_t) == 8, "uint64_t is not of the correct size");
|
||||
#elif MLX_C_VERSION >= 2011
|
||||
#if MLX_C_VERSION < 2023
|
||||
#include <assert.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static_assert(CHAR_BIT == 8, "CHAR_BIT is expected to be 8");
|
||||
|
||||
static_assert(sizeof(int8_t) == 1, "int8_t is not of the correct size" );
|
||||
static_assert(sizeof(int16_t) == 2, "int16_t is not of the correct size");
|
||||
static_assert(sizeof(int32_t) == 4, "int32_t is not of the correct size");
|
||||
static_assert(sizeof(int64_t) == 8, "int64_t is not of the correct size");
|
||||
|
||||
static_assert(sizeof(uint8_t) == 1, "uint8_t is not of the correct size" );
|
||||
static_assert(sizeof(uint16_t) == 2, "uint16_t is not of the correct size");
|
||||
static_assert(sizeof(uint32_t) == 4, "uint32_t is not of the correct size");
|
||||
static_assert(sizeof(uint64_t) == 8, "uint64_t is not of the correct size");
|
||||
#else
|
||||
#define STATIC_ASSERT(COND, MSG) typedef char static_assertion___##MSG[(COND)?1:-1]
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
|
||||
STATIC_ASSERT(CHAR_BIT == 8, CHAR_BIT_is_expected_to_be_8);
|
||||
|
||||
STATIC_ASSERT(sizeof(int8_t) == 1, int8_t_is_not_of_the_correct_size);
|
||||
STATIC_ASSERT(sizeof(int16_t) == 2, int16_t_is_not_of_the_correct_size);
|
||||
STATIC_ASSERT(sizeof(int32_t) == 4, int32_t_is_not_of_the_correct_size);
|
||||
STATIC_ASSERT(sizeof(int64_t) == 8, int64_t_is_not_of_the_correct_size);
|
||||
|
||||
STATIC_ASSERT(sizeof(uint8_t) == 1, uint8_t_is_not_of_the_correct_size);
|
||||
STATIC_ASSERT(sizeof(uint16_t) == 2, uint16_t_is_not_of_the_correct_size);
|
||||
STATIC_ASSERT(sizeof(uint32_t) == 4, uint32_t_is_not_of_the_correct_size);
|
||||
STATIC_ASSERT(sizeof(uint64_t) == 8, uint64_t_is_not_of_the_correct_size);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
BIN
res/logo.png
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.1 KiB |
BIN
res/screenshot_test_windows.png
git.filemode.normal_file
|
After Width: | Height: | Size: 13 KiB |
31
scripts/fetch_dependencies.sh
git.filemode.executable_file
@@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Update volk
|
||||
rm -f ../third_party/volk.c
|
||||
rm -f ../third_party/volk.h
|
||||
tag_name=$(curl -sL https://api.github.com/repos/zeux/Volk/releases/latest | jq -r '.tag_name')
|
||||
wget https://api.github.com/repos/zeux/volk/zipball/$tag_name -O volk.zip
|
||||
unzip -o volk.zip -d ../third_party/
|
||||
mv ../third_party/zeux-volk*/volk.h ../third_party
|
||||
mv ../third_party/zeux-volk*/volk.c ../third_party
|
||||
rm -rf ../third_party/zeux-volk*
|
||||
rm volk.zip
|
||||
|
||||
# Update VMA
|
||||
rm -f ../third_party/vma.h
|
||||
tag_name=$(curl -sL https://api.github.com/repos/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/releases/latest | jq -r '.tag_name')
|
||||
wget https://api.github.com/repos/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/zipball/$tag_name -O vma.zip
|
||||
unzip -o vma.zip -d ../third_party/
|
||||
mv ../third_party/GPUOpen-LibrariesAndSDKs-VulkanMemoryAllocator*/include/vk_mem_alloc.h ../third_party/vma.h
|
||||
rm -rf ../third_party/GPUOpen-LibrariesAndSDKs-VulkanMemoryAllocator*
|
||||
rm vma.zip
|
||||
|
||||
# Update Vulkan headers
|
||||
rm -rf ../third_party/vulkan
|
||||
rm -rf ../third_party/vk_video
|
||||
wget https://github.com/KhronosGroup/Vulkan-Headers/archive/main.zip -O vulkan-headers.zip
|
||||
unzip -o vulkan-headers.zip -d ../third_party/
|
||||
mv ../third_party/Vulkan-Headers-main/include/vulkan ../third_party/
|
||||
mv ../third_party/Vulkan-Headers-main/include/vk_video ../third_party/
|
||||
rm -rf ../third_party/Vulkan-Headers-main
|
||||
rm vulkan-headers.zip
|
||||
25
src/core/UUID.cpp
git.filemode.normal_file
@@ -0,0 +1,25 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* UUID.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/01/06 11:26:37 by maldavid #+# #+# */
|
||||
/* Updated: 2024/01/06 11:28:15 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <core/UUID.h>
|
||||
#include <random>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
static std::random_device random_device;
|
||||
static std::mt19937_64 engine(random_device());
|
||||
static std::uniform_int_distribution<std::uint64_t> uniform_distribution;
|
||||
|
||||
UUID::UUID() : _uuid(uniform_distribution(engine)) {}
|
||||
UUID::UUID(std::uint64_t uuid) : _uuid(uuid) {}
|
||||
}
|
||||
33
src/core/UUID.h
git.filemode.normal_file
@@ -0,0 +1,33 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* UUID.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/01/06 11:13:23 by maldavid #+# #+# */
|
||||
/* Updated: 2024/01/07 01:44:21 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __MLX_UUID__
|
||||
#define __MLX_UUID__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
class UUID
|
||||
{
|
||||
public:
|
||||
UUID();
|
||||
UUID(std::uint64_t uuid);
|
||||
|
||||
inline operator std::uint64_t() const { return _uuid; }
|
||||
|
||||
private:
|
||||
std::uint64_t _uuid;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -6,43 +6,71 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/04 22:10:52 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/20 07:29:12 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/10/19 10:49:21 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "application.h"
|
||||
#include <renderer/texts/text_library.h>
|
||||
#include <renderer/texts/font_library.h>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <renderer/images/texture.h>
|
||||
#include <renderer/core/render_core.h>
|
||||
#include <array>
|
||||
#include <core/errors.h>
|
||||
#include <core/profile.h>
|
||||
#include <mlx_profile.h>
|
||||
#include <core/memory.h>
|
||||
|
||||
namespace mlx::core
|
||||
{
|
||||
Application::Application() : _in(std::make_unique<Input>())
|
||||
static bool __drop_sdl_responsability = false;
|
||||
Application::Application() : _fps(), _in(std::make_unique<Input>())
|
||||
{
|
||||
_fps.init();
|
||||
__drop_sdl_responsability = SDL_WasInit(SDL_INIT_VIDEO);
|
||||
if(__drop_sdl_responsability) // is case the mlx is running in a sandbox like MacroUnitTester where SDL is already init
|
||||
return;
|
||||
SDL_SetMemoryFunctions(MemManager::malloc, MemManager::calloc, MemManager::realloc, MemManager::free);
|
||||
|
||||
/* Remove this comment if you want to prioritise Wayland over X11/XWayland, at your own risks */
|
||||
//SDL_SetHint(SDL_HINT_VIDEODRIVER, "wayland,x11");
|
||||
|
||||
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_TIMER) != 0)
|
||||
error::report(e_kind::fatal_error, "SDL error : unable to init all subsystems : %s", SDL_GetError());
|
||||
}
|
||||
|
||||
void Application::run() noexcept
|
||||
{
|
||||
while(_in->is_running())
|
||||
_in->run();
|
||||
while(_in->isRunning())
|
||||
{
|
||||
if(!_fps.update())
|
||||
continue;
|
||||
_in->update();
|
||||
for(auto& gs : _graphics)
|
||||
gs->beginRender();
|
||||
|
||||
if(_loop_hook)
|
||||
_loop_hook(_param);
|
||||
|
||||
|
||||
for(auto& gs : _graphics)
|
||||
gs->endRender();
|
||||
{
|
||||
if(gs)
|
||||
gs->render();
|
||||
}
|
||||
}
|
||||
|
||||
Render_Core::get().getSingleTimeCmdManager().updateSingleTimesCmdBuffersSubmitState();
|
||||
|
||||
for(auto& gs : _graphics)
|
||||
{
|
||||
if(!gs)
|
||||
continue;
|
||||
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
|
||||
gs->getRenderer().getCmdBuffer(i).waitForExecution();
|
||||
}
|
||||
}
|
||||
|
||||
void* Application::newTexture(int w, int h)
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
#ifdef DEBUG
|
||||
_textures.emplace_front().create(nullptr, w, h, VK_FORMAT_R8G8B8A8_UNORM, "__mlx_unamed_user_texture");
|
||||
#else
|
||||
@@ -53,19 +81,49 @@ namespace mlx::core
|
||||
|
||||
void* Application::newStbTexture(char* file, int* w, int* h)
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
_textures.emplace_front(stbTextureLoad(file, w, h));
|
||||
return &_textures.front();
|
||||
}
|
||||
|
||||
void Application::destroyTexture(void* ptr)
|
||||
{
|
||||
vkDeviceWaitIdle(Render_Core::get().getDevice().get());
|
||||
MLX_PROFILE_FUNCTION();
|
||||
vkDeviceWaitIdle(Render_Core::get().getDevice().get()); // TODO : synchronize with another method than waiting for GPU to be idle
|
||||
if(ptr == nullptr)
|
||||
{
|
||||
core::error::report(e_kind::error, "invalid image ptr (NULL)");
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = std::find_if(_textures.begin(), _textures.end(), [=](const Texture& texture) { return &texture == ptr; });
|
||||
if(it == _textures.end())
|
||||
{
|
||||
core::error::report(e_kind::error, "invalid image ptr");
|
||||
return;
|
||||
}
|
||||
Texture* texture = static_cast<Texture*>(ptr);
|
||||
texture->destroy();
|
||||
if(!texture->isInit())
|
||||
core::error::report(e_kind::error, "trying to destroy a texture that has already been destroyed");
|
||||
else
|
||||
texture->destroy();
|
||||
for(auto& gs : _graphics)
|
||||
{
|
||||
if(gs)
|
||||
gs->tryEraseTextureFromManager(texture);
|
||||
}
|
||||
_textures.erase(it);
|
||||
}
|
||||
|
||||
Application::~Application()
|
||||
{
|
||||
TextLibrary::get().clearLibrary();
|
||||
TextLibrary::get().reset();
|
||||
FontLibrary::get().clearLibrary();
|
||||
FontLibrary::get().reset();
|
||||
if(__drop_sdl_responsability)
|
||||
return;
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS);
|
||||
SDL_Quit();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/04 21:49:46 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/23 14:25:43 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/09/12 01:30:35 by tdelage ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -15,15 +15,16 @@
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
|
||||
#include <core/errors.h>
|
||||
|
||||
#include <core/graphics.h>
|
||||
#include <platform/inputs.h>
|
||||
#include <mlx_profile.h>
|
||||
#include <core/profiler.h>
|
||||
#include <core/fps.h>
|
||||
|
||||
namespace mlx::core
|
||||
{
|
||||
@@ -37,20 +38,23 @@ namespace mlx::core
|
||||
|
||||
inline void onEvent(void* win, int event, int (*funct_ptr)(int, void*), void* param) noexcept;
|
||||
|
||||
inline void getScreenSize(int* w, int* h) noexcept;
|
||||
inline void getScreenSize(void* win, int* w, int* h) noexcept;
|
||||
|
||||
inline void* newGraphicsSuport(std::size_t w, std::size_t h, std::string title);
|
||||
inline void setFPSCap(std::uint32_t fps) noexcept;
|
||||
|
||||
inline void* newGraphicsSuport(std::size_t w, std::size_t h, const char* title);
|
||||
inline void clearGraphicsSupport(void* win);
|
||||
inline void destroyGraphicsSupport(void* win);
|
||||
inline void setWindowPosition(void *win, int x, int y);
|
||||
|
||||
inline void pixelPut(void* win, int x, int y, uint32_t color) const noexcept;
|
||||
inline void stringPut(void* win, int x, int y, int color, char* str);
|
||||
inline void pixelPut(void* win, int x, int y, std::uint32_t color) const noexcept;
|
||||
inline void stringPut(void* win, int x, int y, std::uint32_t color, char* str);
|
||||
|
||||
void* newTexture(int w, int h);
|
||||
void* newStbTexture(char* file, int* w, int* h); // stb textures are format managed by stb image (png, jpg, bpm, ...)
|
||||
inline void texturePut(void* win, void* img, int x, int y);
|
||||
inline int getTexturePixel(void* img, int x, int y);
|
||||
inline void setTexturePixel(void* img, int x, int y, uint32_t color);
|
||||
inline void setTexturePixel(void* img, int x, int y, std::uint32_t color);
|
||||
void destroyTexture(void* ptr);
|
||||
|
||||
inline void loopHook(int (*f)(void*), void* param);
|
||||
@@ -63,12 +67,12 @@ namespace mlx::core
|
||||
~Application();
|
||||
|
||||
private:
|
||||
FpsManager _fps;
|
||||
std::list<Texture> _textures;
|
||||
std::vector<std::unique_ptr<GraphicsSupport>> _graphics;
|
||||
std::function<int(void*)> _loop_hook;
|
||||
std::unique_ptr<Input> _in;
|
||||
void* _param = nullptr;
|
||||
bool _is_loop_running = false;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,37 @@
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <SDL2/SDL_video.h>
|
||||
#include <algorithm>
|
||||
#include <core/application.h>
|
||||
|
||||
#define CHECK_WINDOW_PTR(win) \
|
||||
if(win == nullptr) \
|
||||
{ \
|
||||
core::error::report(e_kind::error, "invalid window ptr (NULL)"); \
|
||||
return; \
|
||||
} \
|
||||
else if(*static_cast<int*>(win) < 0 || *static_cast<int*>(win) > static_cast<int>(_graphics.size()))\
|
||||
{ \
|
||||
core::error::report(e_kind::error, "invalid window ptr"); \
|
||||
return; \
|
||||
} else {}
|
||||
|
||||
#define CHECK_IMAGE_PTR(img, retval) \
|
||||
if(img == nullptr) \
|
||||
{ \
|
||||
core::error::report(e_kind::error, "invalid image ptr (NULL)"); \
|
||||
retval; \
|
||||
} \
|
||||
else if(std::find_if(_textures.begin(), _textures.end(), [=](const Texture& texture) \
|
||||
{ \
|
||||
return &texture == img; \
|
||||
}) == _textures.end()) \
|
||||
{ \
|
||||
core::error::report(e_kind::error, "invalid image ptr"); \
|
||||
retval; \
|
||||
} else {}
|
||||
|
||||
namespace mlx::core
|
||||
{
|
||||
void Application::getMousePos(int* x, int* y) noexcept
|
||||
@@ -22,72 +51,153 @@ namespace mlx::core
|
||||
|
||||
void Application::mouseMove(void* win, int x, int y) noexcept
|
||||
{
|
||||
CHECK_WINDOW_PTR(win);
|
||||
if(!_graphics[*static_cast<int*>(win)]->hasWindow())
|
||||
{
|
||||
error::report(e_kind::warning, "trying to move the mouse relative to a window that is targeting an image and not a real window, this is not allowed (move ignored)");
|
||||
return;
|
||||
}
|
||||
SDL_WarpMouseInWindow(_graphics[*static_cast<int*>(win)]->getWindow()->getNativeWindow(), x, y);
|
||||
SDL_PumpEvents();
|
||||
SDL_FlushEvent(SDL_MOUSEMOTION);
|
||||
}
|
||||
|
||||
void Application::onEvent(void* win, int event, int (*funct_ptr)(int, void*), void* param) noexcept
|
||||
{
|
||||
CHECK_WINDOW_PTR(win);
|
||||
if(!_graphics[*static_cast<int*>(win)]->hasWindow())
|
||||
{
|
||||
error::report(e_kind::warning, "trying to add event hook for a window that is targeting an image and not a real window, this is not allowed (hook ignored)");
|
||||
return;
|
||||
}
|
||||
_in->onEvent(_graphics[*static_cast<int*>(win)]->getWindow()->getID(), event, funct_ptr, param);
|
||||
}
|
||||
|
||||
void Application::getScreenSize(int* w, int* h) noexcept
|
||||
void Application::setWindowPosition(void* win, int x, int y)
|
||||
{
|
||||
CHECK_WINDOW_PTR(win);
|
||||
if(!_graphics[*static_cast<int*>(win)]->hasWindow())
|
||||
{
|
||||
error::report(e_kind::warning, "trying to move a window that is targeting an image and not a real window, this is not allowed");
|
||||
return;
|
||||
}
|
||||
SDL_SetWindowPosition(_graphics[*static_cast<int*>(win)]->getWindow()->getNativeWindow(), x, y);
|
||||
}
|
||||
|
||||
void Application::getScreenSize(void* win, int* w, int* h) noexcept
|
||||
{
|
||||
CHECK_WINDOW_PTR(win);
|
||||
SDL_DisplayMode DM;
|
||||
SDL_GetDesktopDisplayMode(0, &DM);
|
||||
SDL_GetDesktopDisplayMode(SDL_GetWindowDisplayIndex(_graphics[*static_cast<int*>(win)]->getWindow()->getNativeWindow()), &DM);
|
||||
*w = DM.w;
|
||||
*h = DM.h;
|
||||
}
|
||||
|
||||
void* Application::newGraphicsSuport(std::size_t w, std::size_t h, std::string title)
|
||||
void Application::setFPSCap(std::uint32_t fps) noexcept
|
||||
{
|
||||
_graphics.emplace_back(std::make_unique<GraphicsSupport>(w, h, title, _graphics.size()));
|
||||
_in->addWindow(_graphics.back()->getWindow());
|
||||
_fps.setMaxFPS(fps);
|
||||
}
|
||||
|
||||
void* Application::newGraphicsSuport(std::size_t w, std::size_t h, const char* title)
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
auto it = std::find_if(_textures.begin(), _textures.end(), [=](const Texture& texture)
|
||||
{
|
||||
return &texture == reinterpret_cast<Texture*>(const_cast<char*>(title));
|
||||
});
|
||||
if(it != _textures.end())
|
||||
_graphics.emplace_back(std::make_unique<GraphicsSupport>(w, h, reinterpret_cast<Texture*>(const_cast<char*>(title)), _graphics.size()));
|
||||
else
|
||||
{
|
||||
if(title == NULL)
|
||||
{
|
||||
core::error::report(e_kind::fatal_error, "invalid window title (NULL)");
|
||||
return nullptr;
|
||||
}
|
||||
_graphics.emplace_back(std::make_unique<GraphicsSupport>(w, h, title, _graphics.size()));
|
||||
_in->addWindow(_graphics.back()->getWindow());
|
||||
}
|
||||
return static_cast<void*>(&_graphics.back()->getID());
|
||||
}
|
||||
|
||||
void Application::clearGraphicsSupport(void* win)
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
CHECK_WINDOW_PTR(win);
|
||||
_graphics[*static_cast<int*>(win)]->clearRenderData();
|
||||
}
|
||||
|
||||
|
||||
void Application::destroyGraphicsSupport(void* win)
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
CHECK_WINDOW_PTR(win);
|
||||
_graphics[*static_cast<int*>(win)].reset();
|
||||
}
|
||||
|
||||
void Application::pixelPut(void* win, int x, int y, uint32_t color) const noexcept
|
||||
void Application::pixelPut(void* win, int x, int y, std::uint32_t color) const noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
CHECK_WINDOW_PTR(win);
|
||||
_graphics[*static_cast<int*>(win)]->pixelPut(x, y, color);
|
||||
}
|
||||
|
||||
void Application::stringPut(void* win, int x, int y, int color, char* str)
|
||||
void Application::stringPut(void* win, int x, int y, std::uint32_t color, char* str)
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
CHECK_WINDOW_PTR(win);
|
||||
if(str == nullptr)
|
||||
{
|
||||
core::error::report(e_kind::error, "wrong text (NULL)");
|
||||
return;
|
||||
}
|
||||
if(std::strlen(str) == 0)
|
||||
{
|
||||
core::error::report(e_kind::warning, "trying to put an empty text");
|
||||
return;
|
||||
}
|
||||
_graphics[*static_cast<int*>(win)]->stringPut(x, y, color, str);
|
||||
}
|
||||
|
||||
void Application::loadFont(void* win, const std::filesystem::path& filepath, float scale)
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
CHECK_WINDOW_PTR(win);
|
||||
_graphics[*static_cast<int*>(win)]->loadFont(filepath, scale);
|
||||
}
|
||||
|
||||
void Application::texturePut(void* win, void* img, int x, int y)
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
CHECK_WINDOW_PTR(win);
|
||||
CHECK_IMAGE_PTR(img, return);
|
||||
Texture* texture = static_cast<Texture*>(img);
|
||||
_graphics[*static_cast<int*>(win)]->texturePut(texture, x, y);
|
||||
if(!texture->isInit())
|
||||
core::error::report(e_kind::error, "trying to put a texture that has been destroyed");
|
||||
else
|
||||
_graphics[*static_cast<int*>(win)]->texturePut(texture, x, y);
|
||||
}
|
||||
|
||||
int Application::getTexturePixel(void* img, int x, int y)
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
CHECK_IMAGE_PTR(img, return 0);
|
||||
Texture* texture = static_cast<Texture*>(img);
|
||||
if(!texture->isInit())
|
||||
{
|
||||
core::error::report(e_kind::error, "trying to get a pixel from texture that has been destroyed");
|
||||
return 0;
|
||||
}
|
||||
return texture->getPixel(x, y);
|
||||
}
|
||||
|
||||
void Application::setTexturePixel(void* img, int x, int y, uint32_t color)
|
||||
void Application::setTexturePixel(void* img, int x, int y, std::uint32_t color)
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
CHECK_IMAGE_PTR(img, return);
|
||||
Texture* texture = static_cast<Texture*>(img);
|
||||
texture->setPixel(x, y, color);
|
||||
if(!texture->isInit())
|
||||
core::error::report(e_kind::error, "trying to set a pixel on texture that has been destroyed");
|
||||
else
|
||||
texture->setPixel(x, y, color);
|
||||
}
|
||||
|
||||
void Application::loopHook(int (*f)(void*), void* param)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/04 17:35:20 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/25 10:12:36 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/09/12 01:29:33 by tdelage ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -15,207 +15,298 @@
|
||||
#include "application.h"
|
||||
#include <renderer/core/render_core.h>
|
||||
#include <filesystem>
|
||||
#include <mlx.h>
|
||||
#include <core/memory.h>
|
||||
#include <mlx_profile.h>
|
||||
|
||||
static void* __mlx_ptr = nullptr;
|
||||
|
||||
#define MLX_CHECK_APPLICATION_POINTER(ptr) \
|
||||
if(ptr != __mlx_ptr || ptr == NULL) \
|
||||
mlx::core::error::report(e_kind::fatal_error, "invalid mlx pointer passed to '%s'", MLX_FUNC_SIG); \
|
||||
else {} // just to avoid issues with possible if-else statements outside this macro
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void* mlx_init()
|
||||
{
|
||||
static bool init = false;
|
||||
if(init)
|
||||
if(__mlx_ptr != nullptr)
|
||||
{
|
||||
mlx::core::error::report(e_kind::error, "MLX cannot be initialized multiple times");
|
||||
return NULL;
|
||||
return NULL; // not nullptr for the C compatibility
|
||||
}
|
||||
mlx::Render_Core::get().init();
|
||||
mlx::MemManager::get(); // just to initialize the C garbage collector
|
||||
mlx::core::Application* app = new mlx::core::Application;
|
||||
mlx::Render_Core::get().init();
|
||||
if(app == nullptr)
|
||||
mlx::core::error::report(e_kind::fatal_error, "Tout a pété");
|
||||
init = true;
|
||||
return app;
|
||||
__mlx_ptr = static_cast<void*>(app);
|
||||
return __mlx_ptr;
|
||||
}
|
||||
|
||||
void* mlx_new_window(mlx::core::Application* mlx, int w, int h, const char* title)
|
||||
void* mlx_new_window(void* mlx, int w, int h, const char* title)
|
||||
{
|
||||
return mlx->newGraphicsSuport(w, h, title);
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
if(w <= 0 || h <= 0)
|
||||
{
|
||||
mlx::core::error::report(e_kind::fatal_error, "invalid window size (%d x %d)", w, h);
|
||||
return NULL; // not nullptr for the C compatibility
|
||||
}
|
||||
return static_cast<mlx::core::Application*>(mlx)->newGraphicsSuport(w, h, title);
|
||||
}
|
||||
|
||||
int mlx_loop_hook(mlx::core::Application* mlx, int (*f)(void*), void* param)
|
||||
int mlx_loop_hook(void* mlx, int (*f)(void*), void* param)
|
||||
{
|
||||
mlx->loopHook(f, param);
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
static_cast<mlx::core::Application*>(mlx)->loopHook(f, param);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlx_loop(mlx::core::Application* mlx)
|
||||
void mlx_set_window_position(void *mlx, void *win, int x, int y)
|
||||
{
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
static_cast<mlx::core::Application*>(mlx)->setWindowPosition(win, x, y);
|
||||
}
|
||||
|
||||
int mlx_loop(void* mlx)
|
||||
{
|
||||
mlx->run();
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
static_cast<mlx::core::Application*>(mlx)->run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlx_loop_end(mlx::core::Application* mlx)
|
||||
int mlx_loop_end(void* mlx)
|
||||
{
|
||||
mlx->loopEnd();
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
static_cast<mlx::core::Application*>(mlx)->loopEnd();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlx_mouse_show()
|
||||
{
|
||||
return SDL_ShowCursor(SDL_ENABLE);
|
||||
SDL_ShowCursor(SDL_ENABLE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlx_mouse_hide()
|
||||
{
|
||||
return SDL_ShowCursor(SDL_DISABLE);
|
||||
}
|
||||
|
||||
int mlx_mouse_move(mlx::core::Application* mlx, void* win, int x, int y)
|
||||
{
|
||||
mlx->mouseMove(win, x, y);
|
||||
SDL_ShowCursor(SDL_DISABLE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlx_mouse_get_pos(mlx::core::Application* mlx, int* x, int* y)
|
||||
int mlx_mouse_move(void* mlx, void* win, int x, int y)
|
||||
{
|
||||
mlx->getMousePos(x, y);
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
static_cast<mlx::core::Application*>(mlx)->mouseMove(win, x, y);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlx_on_event(mlx::core::Application* mlx, void* win, int event, int (*funct_ptr)(int, void*), void* param)
|
||||
int mlx_mouse_get_pos(void* mlx, int* x, int* y)
|
||||
{
|
||||
mlx->onEvent(win, event, funct_ptr, param);
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
static_cast<mlx::core::Application*>(mlx)->getMousePos(x, y);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* mlx_new_image(mlx::core::Application* mlx, int width, int height)
|
||||
int mlx_on_event(void* mlx, void* win, mlx_event_type event, int (*funct_ptr)(int, void*), void* param)
|
||||
{
|
||||
return mlx->newTexture(width, height);
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
static_cast<mlx::core::Application*>(mlx)->onEvent(win, static_cast<int>(event), funct_ptr, param);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlx_get_image_pixel(mlx::core::Application* mlx, void* img, int x, int y)
|
||||
void* mlx_new_image(void* mlx, int width, int height)
|
||||
{
|
||||
return mlx->getTexturePixel(img, x, y);
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
if (width <= 0 || height <= 0)
|
||||
mlx::core::error::report(e_kind::fatal_error, "invalid image size (%d x %d)", width, height);
|
||||
return static_cast<mlx::core::Application*>(mlx)->newTexture(width, height);
|
||||
}
|
||||
|
||||
void mlx_set_image_pixel(mlx::core::Application* mlx, void* img, int x, int y, int color)
|
||||
int mlx_get_image_pixel(void* mlx, void* img, int x, int y)
|
||||
{
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
int color = static_cast<mlx::core::Application*>(mlx)->getTexturePixel(img, x, y);
|
||||
unsigned char color_bits[4];
|
||||
color_bits[0] = (color & 0x000000FF);
|
||||
color_bits[1] = (color & 0x0000FF00) >> 8;
|
||||
color_bits[2] = (color & 0x00FF0000) >> 16;
|
||||
color_bits[3] = (color & 0xFF000000) >> 24;
|
||||
return *reinterpret_cast<int*>(color_bits);
|
||||
}
|
||||
|
||||
void mlx_set_image_pixel(void* mlx, void* img, int x, int y, int color)
|
||||
{
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
unsigned char color_bits[4];
|
||||
color_bits[0] = (color & 0x00FF0000) >> 16;
|
||||
color_bits[1] = (color & 0x0000FF00) >> 8;
|
||||
color_bits[2] = (color & 0x000000FF);
|
||||
color_bits[3] = (color & 0xFF000000) >> 24;
|
||||
mlx->setTexturePixel(img, x, y, *reinterpret_cast<unsigned int*>(color_bits));
|
||||
static_cast<mlx::core::Application*>(mlx)->setTexturePixel(img, x, y, *reinterpret_cast<unsigned int*>(color_bits));
|
||||
}
|
||||
|
||||
int mlx_put_image_to_window(mlx::core::Application* mlx, void* win, void* img, int x, int y)
|
||||
int mlx_put_image_to_window(void* mlx, void* win, void* img, int x, int y)
|
||||
{
|
||||
mlx->texturePut(win, img, x, y);
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
static_cast<mlx::core::Application*>(mlx)->texturePut(win, img, x, y);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlx_destroy_image(mlx::core::Application* mlx, void* img)
|
||||
int mlx_destroy_image(void* mlx, void* img)
|
||||
{
|
||||
mlx->destroyTexture(img);
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
static_cast<mlx::core::Application*>(mlx)->destroyTexture(img);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* mlx_png_file_to_image(mlx::core::Application* mlx, char* filename, int* width, int* height)
|
||||
void* mlx_png_file_to_image(void* mlx, char* filename, int* width, int* height)
|
||||
{
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
if (filename == nullptr)
|
||||
mlx::core::error::report(e_kind::fatal_error, "PNG loader : filename is NULL");
|
||||
std::filesystem::path file(filename);
|
||||
if(file.extension() != ".png")
|
||||
{
|
||||
mlx::core::error::report(e_kind::error, "PNG loader : not a png file '%s'", filename);
|
||||
return nullptr;
|
||||
}
|
||||
return mlx->newStbTexture(filename, width, height);
|
||||
return static_cast<mlx::core::Application*>(mlx)->newStbTexture(filename, width, height);
|
||||
}
|
||||
|
||||
void* mlx_jpg_file_to_image(mlx::core::Application* mlx, char* filename, int* width, int* height)
|
||||
void* mlx_jpg_file_to_image(void* mlx, char* filename, int* width, int* height)
|
||||
{
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
if (filename == nullptr)
|
||||
mlx::core::error::report(e_kind::fatal_error, "JPG loader : filename is NULL");
|
||||
std::filesystem::path file(filename);
|
||||
if(file.extension() != ".jpg" && file.extension() != ".jpeg")
|
||||
{
|
||||
mlx::core::error::report(e_kind::error, "JPG loader : not a jpg file '%s'", filename);
|
||||
return nullptr;
|
||||
}
|
||||
return mlx->newStbTexture(filename, width, height);
|
||||
return static_cast<mlx::core::Application*>(mlx)->newStbTexture(filename, width, height);
|
||||
}
|
||||
|
||||
void* mlx_bmp_file_to_image(mlx::core::Application* mlx, char* filename, int* width, int* height)
|
||||
void* mlx_bmp_file_to_image(void* mlx, char* filename, int* width, int* height)
|
||||
{
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
if (filename == nullptr)
|
||||
mlx::core::error::report(e_kind::fatal_error, "BMP loader : filename is NULL");
|
||||
std::filesystem::path file(filename);
|
||||
if(file.extension() != ".bmp" && file.extension() != ".dib")
|
||||
{
|
||||
mlx::core::error::report(e_kind::error, "BMP loader : not a bmp file '%s'", filename);
|
||||
return nullptr;
|
||||
}
|
||||
return mlx->newStbTexture(filename, width, height);
|
||||
return static_cast<mlx::core::Application*>(mlx)->newStbTexture(filename, width, height);
|
||||
}
|
||||
|
||||
int mlx_pixel_put(mlx::core::Application* mlx, void* win, int x, int y, int color)
|
||||
int mlx_pixel_put(void* mlx, void* win, int x, int y, int color)
|
||||
{
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
unsigned char color_bits[4];
|
||||
color_bits[0] = (color & 0x00FF0000) >> 16;
|
||||
color_bits[1] = (color & 0x0000FF00) >> 8;
|
||||
color_bits[2] = color & 0x000000FF;
|
||||
color_bits[3] = 0xFF;
|
||||
mlx->pixelPut(win, x, y, *reinterpret_cast<unsigned int*>(color_bits));
|
||||
color_bits[2] = (color & 0x000000FF);
|
||||
color_bits[3] = (color & 0xFF000000) >> 24;
|
||||
static_cast<mlx::core::Application*>(mlx)->pixelPut(win, x, y, *reinterpret_cast<unsigned int*>(color_bits));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlx_string_put(mlx::core::Application* mlx, void* win, int x, int y, int color, char* str)
|
||||
int mlx_string_put(void* mlx, void* win, int x, int y, int color, char* str)
|
||||
{
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
unsigned char color_bits[4];
|
||||
color_bits[0] = (color & 0x00FF0000) >> 16;
|
||||
color_bits[1] = (color & 0x0000FF00) >> 8;
|
||||
color_bits[2] = color & 0x000000FF;
|
||||
color_bits[3] = 0xFF;
|
||||
mlx->stringPut(win, x, y, *reinterpret_cast<unsigned int*>(color_bits), str);
|
||||
color_bits[2] = (color & 0x000000FF);
|
||||
color_bits[3] = (color & 0xFF000000) >> 24;
|
||||
static_cast<mlx::core::Application*>(mlx)->stringPut(win, x, y, *reinterpret_cast<unsigned int*>(color_bits), str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mlx_set_font(mlx::core::Application* mlx, void* win, char* filepath)
|
||||
void mlx_set_font(void* mlx, void* win, char* filepath)
|
||||
{
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
if (filepath == nullptr)
|
||||
{
|
||||
mlx::core::error::report(e_kind::error, "Font loader : filepath is NULL");
|
||||
return;
|
||||
}
|
||||
std::filesystem::path file(filepath);
|
||||
if(file.extension() != ".ttf" && file.extension() != ".tte")
|
||||
if(std::strcmp(filepath, "default") != 0 && file.extension() != ".ttf" && file.extension() != ".tte")
|
||||
{
|
||||
mlx::core::error::report(e_kind::error, "TTF loader : not a truetype font file '%s'", filepath);
|
||||
return;
|
||||
}
|
||||
mlx->loadFont(win, file, 16.f);
|
||||
if(std::strcmp(filepath, "default") == 0)
|
||||
static_cast<mlx::core::Application*>(mlx)->loadFont(win, file, 6.f);
|
||||
else
|
||||
static_cast<mlx::core::Application*>(mlx)->loadFont(win, file, 16.f);
|
||||
}
|
||||
|
||||
void mlx_set_font_scale(mlx::core::Application* mlx, void* win, char* filepath, float scale)
|
||||
void mlx_set_font_scale(void* mlx, void* win, char* filepath, float scale)
|
||||
{
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
if (filepath == nullptr)
|
||||
{
|
||||
mlx::core::error::report(e_kind::error, "Font loader : filepath is NULL");
|
||||
return;
|
||||
}
|
||||
std::filesystem::path file(filepath);
|
||||
if(file.extension() != ".ttf" && file.extension() != ".tte")
|
||||
if(std::strcmp(filepath, "default") != 0 && file.extension() != ".ttf" && file.extension() != ".tte")
|
||||
{
|
||||
mlx::core::error::report(e_kind::error, "TTF loader : not a truetype font file '%s'", filepath);
|
||||
return;
|
||||
}
|
||||
mlx->loadFont(win, file, scale);
|
||||
static_cast<mlx::core::Application*>(mlx)->loadFont(win, file, scale);
|
||||
}
|
||||
|
||||
int mlx_clear_window(mlx::core::Application* mlx, void* win)
|
||||
int mlx_clear_window(void* mlx, void* win)
|
||||
{
|
||||
mlx->clearGraphicsSupport(win);
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
static_cast<mlx::core::Application*>(mlx)->clearGraphicsSupport(win);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlx_destroy_window(mlx::core::Application* mlx, void* win)
|
||||
int mlx_destroy_window(void* mlx, void* win)
|
||||
{
|
||||
mlx->destroyGraphicsSupport(win);
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
static_cast<mlx::core::Application*>(mlx)->destroyGraphicsSupport(win);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlx_destroy_display(mlx::core::Application* mlx)
|
||||
int mlx_destroy_display(void* mlx)
|
||||
{
|
||||
delete mlx;
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
delete static_cast<mlx::core::Application*>(mlx);
|
||||
mlx::Render_Core::get().destroy();
|
||||
__mlx_ptr = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlx_get_screens_size(mlx::core::Application* mlx, int* w, int* h)
|
||||
int mlx_get_screens_size(void* mlx, void* win, int* w, int* h)
|
||||
{
|
||||
mlx->getScreenSize(w, h);
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
static_cast<mlx::core::Application*>(mlx)->getScreenSize(win, w, h);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlx_set_fps_goal(void* mlx, int fps)
|
||||
{
|
||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||
if(fps < 0)
|
||||
{
|
||||
mlx::core::error::report(e_kind::error, "You cannot set a negative FPS cap (nice try)");
|
||||
fps = -fps;
|
||||
}
|
||||
if(fps == 0)
|
||||
{
|
||||
mlx::core::error::report(e_kind::error, "You cannot set a FPS cap to 0 (nice try)");
|
||||
return 0;
|
||||
}
|
||||
static_cast<mlx::core::Application*>(mlx)->setFPSCap(static_cast<std::uint32_t>(fps));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/04 17:48:06 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/14 07:14:57 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/01/05 20:41:17 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/04 17:42:32 by maldavid #+# #+# */
|
||||
/* Updated: 2022/10/08 19:06:41 by maldavid ### ########.fr */
|
||||
/* Updated: 2023/12/27 17:21:07 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#define __MLX_ERRORS__
|
||||
|
||||
#include <string>
|
||||
#include <mlx_profile.h>
|
||||
|
||||
enum class e_kind
|
||||
{
|
||||
|
||||
44
src/core/fps.cpp
git.filemode.normal_file
@@ -0,0 +1,44 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* fps.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/01/18 14:56:17 by maldavid #+# #+# */
|
||||
/* Updated: 2024/03/25 16:44:15 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <core/fps.h>
|
||||
#include <chrono>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <thread>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
void FpsManager::init()
|
||||
{
|
||||
_timer = SDL_GetTicks64();
|
||||
_fps_before = static_cast<std::uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count());
|
||||
_fps_now = static_cast<std::uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count());
|
||||
}
|
||||
|
||||
bool FpsManager::update()
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
_fps_now = static_cast<std::uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count());
|
||||
|
||||
if(SDL_GetTicks64() - _timer > 1000)
|
||||
_timer += 1000;
|
||||
|
||||
_fps_elapsed_time = _fps_now - _fps_before;
|
||||
if(_fps_elapsed_time >= _ns)
|
||||
{
|
||||
_fps_before += _ns;
|
||||
return true;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::duration<double, std::nano>(_ns - 1));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
41
src/core/fps.h
git.filemode.normal_file
@@ -0,0 +1,41 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* fps.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/01/18 14:53:30 by maldavid #+# #+# */
|
||||
/* Updated: 2024/01/18 15:16:06 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __MLX_FPS__
|
||||
#define __MLX_FPS__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
class FpsManager
|
||||
{
|
||||
public:
|
||||
FpsManager() = default;
|
||||
|
||||
void init();
|
||||
bool update();
|
||||
inline void setMaxFPS(std::uint32_t fps) noexcept { _max_fps = fps; _ns = 1000000000.0 / fps; }
|
||||
|
||||
~FpsManager() = default;
|
||||
|
||||
private:
|
||||
double _ns = 1000000000.0 / 1'337'000.0;
|
||||
std::uint64_t _timer = 0;
|
||||
std::uint64_t _fps_before = 0;
|
||||
std::uint64_t _fps_now = 0;
|
||||
std::uint32_t _max_fps = 1'337'000;
|
||||
std::uint32_t _fps_elapsed_time = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/04/02 15:13:55 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/24 20:42:15 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/04/22 17:34:27 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -14,55 +14,62 @@
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
GraphicsSupport::GraphicsSupport(std::size_t w, std::size_t h, const std::string& title, int id) :
|
||||
_window(std::make_shared<MLX_Window>(w, h, title)),
|
||||
_renderer(std::make_unique<Renderer>()), _text_put_pipeline(std::make_unique<TextPutPipeline>()),
|
||||
_id(id)
|
||||
GraphicsSupport::GraphicsSupport(std::size_t w, std::size_t h, Texture* render_target, int id) :
|
||||
_window(nullptr),
|
||||
_renderer(std::make_unique<Renderer>()),
|
||||
_width(w),
|
||||
_height(h),
|
||||
_id(id),
|
||||
_has_window(false)
|
||||
{
|
||||
_renderer->setWindow(_window.get());
|
||||
_renderer->init();
|
||||
MLX_PROFILE_FUNCTION();
|
||||
_renderer->setWindow(nullptr);
|
||||
_renderer->init(render_target);
|
||||
_pixel_put_pipeline.init(w, h, *_renderer);
|
||||
_text_put_pipeline->init(_renderer.get());
|
||||
_text_manager.init(*_renderer);
|
||||
}
|
||||
|
||||
void GraphicsSupport::endRender() noexcept
|
||||
GraphicsSupport::GraphicsSupport(std::size_t w, std::size_t h, std::string title, int id) :
|
||||
_window(std::make_shared<MLX_Window>(w, h, title)),
|
||||
_renderer(std::make_unique<Renderer>()),
|
||||
_width(w),
|
||||
_height(h),
|
||||
_id(id),
|
||||
_has_window(true)
|
||||
{
|
||||
auto cmd_buff = _renderer->getActiveCmdBuffer().get();
|
||||
MLX_PROFILE_FUNCTION();
|
||||
_renderer->setWindow(_window.get());
|
||||
_renderer->init(nullptr);
|
||||
_pixel_put_pipeline.init(w, h, *_renderer);
|
||||
_text_manager.init(*_renderer);
|
||||
}
|
||||
|
||||
static std::array<VkDescriptorSet, 2> sets = {
|
||||
void GraphicsSupport::render() noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
if(!_renderer->beginFrame())
|
||||
return;
|
||||
_proj = glm::ortho<float>(0, _width, 0, _height);
|
||||
_renderer->getUniformBuffer()->setData(sizeof(_proj), &_proj);
|
||||
|
||||
std::array<VkDescriptorSet, 2> sets = {
|
||||
_renderer->getVertDescriptorSet().get(),
|
||||
VK_NULL_HANDLE
|
||||
};
|
||||
|
||||
for(auto& data : _textures_to_render)
|
||||
{
|
||||
if(data.texture->getSet() == VK_NULL_HANDLE)
|
||||
data.texture->setDescriptor(_renderer->getFragDescriptorSet().duplicate());
|
||||
if(!data.texture->hasBeenUpdated())
|
||||
data.texture->updateSet(0);
|
||||
sets[1] = data.texture->getSet();
|
||||
vkCmdBindDescriptorSets(cmd_buff, VK_PIPELINE_BIND_POINT_GRAPHICS, _renderer->getPipeline().getPipelineLayout(), 0, sets.size(), sets.data(), 0, nullptr);
|
||||
data.texture->render(*_renderer, data.x, data.y);
|
||||
}
|
||||
for(auto& data : _drawlist)
|
||||
data->render(sets, *_renderer);
|
||||
|
||||
_pixel_put_pipeline.present();
|
||||
|
||||
sets[1] = _pixel_put_pipeline.getDescriptorSet();
|
||||
vkCmdBindDescriptorSets(cmd_buff, VK_PIPELINE_BIND_POINT_GRAPHICS, _renderer->getPipeline().getPipelineLayout(), 0, sets.size(), sets.data(), 0, nullptr);
|
||||
_pixel_put_pipeline.render(*_renderer);
|
||||
|
||||
sets[1] = _text_put_pipeline->getDescriptorSet();
|
||||
vkCmdBindDescriptorSets(cmd_buff, VK_PIPELINE_BIND_POINT_GRAPHICS, _renderer->getPipeline().getPipelineLayout(), 0, sets.size(), sets.data(), 0, nullptr);
|
||||
_text_put_pipeline->render();
|
||||
_pixel_put_pipeline.render(sets, *_renderer);
|
||||
|
||||
_renderer->endFrame();
|
||||
|
||||
for(auto& data : _textures_to_render)
|
||||
data.texture->resetUpdate();
|
||||
for(auto& data : _drawlist)
|
||||
data->resetUpdate();
|
||||
|
||||
#ifdef GRAPHICS_MEMORY_DUMP
|
||||
// dump memory to file every two seconds
|
||||
static uint64_t timer = SDL_GetTicks64();
|
||||
static std::uint64_t timer = SDL_GetTicks64();
|
||||
if(SDL_GetTicks64() - timer > 2000)
|
||||
{
|
||||
Render_Core::get().getAllocator().dumpMemoryToJson();
|
||||
@@ -73,9 +80,12 @@ namespace mlx
|
||||
|
||||
GraphicsSupport::~GraphicsSupport()
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
vkDeviceWaitIdle(Render_Core::get().getDevice().get());
|
||||
_text_put_pipeline->destroy();
|
||||
_text_manager.destroy();
|
||||
_pixel_put_pipeline.destroy();
|
||||
_renderer->destroy();
|
||||
if(_window)
|
||||
_window->destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/04/02 14:49:49 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/25 09:59:39 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/03/24 14:43:09 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#define __MLX_GRAPHICS__
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_set>
|
||||
#include <filesystem>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
@@ -23,39 +22,59 @@
|
||||
#include <platform/window.h>
|
||||
#include <renderer/renderer.h>
|
||||
#include <renderer/pixel_put.h>
|
||||
#include <renderer/text_pipeline.h>
|
||||
#include <renderer/core/drawable_resource.h>
|
||||
#include <renderer/images/texture_manager.h>
|
||||
#include <renderer/texts/text_manager.h>
|
||||
#include <utils/non_copyable.h>
|
||||
#include <renderer/images/texture.h>
|
||||
#include <mlx_profile.h>
|
||||
#include <core/profiler.h>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
class GraphicsSupport : public non_copyable
|
||||
class GraphicsSupport : public NonCopyable
|
||||
{
|
||||
public:
|
||||
GraphicsSupport(std::size_t w, std::size_t h, const std::string& title, int id);
|
||||
GraphicsSupport(std::size_t w, std::size_t h, Texture* render_target, int id);
|
||||
GraphicsSupport(std::size_t w, std::size_t h, std::string title, int id);
|
||||
|
||||
inline int& getID() noexcept;
|
||||
inline std::shared_ptr<MLX_Window> getWindow();
|
||||
|
||||
inline void beginRender() noexcept;
|
||||
void endRender() noexcept;
|
||||
void render() noexcept;
|
||||
|
||||
inline void clearRenderData() noexcept;
|
||||
inline void pixelPut(int x, int y, uint32_t color) noexcept;
|
||||
inline void stringPut(int x, int y, int color, std::string str);
|
||||
inline void pixelPut(int x, int y, std::uint32_t color) noexcept;
|
||||
inline void stringPut(int x, int y, std::uint32_t color, std::string str);
|
||||
inline void texturePut(Texture* texture, int x, int y);
|
||||
inline void loadFont(const std::filesystem::path& filepath, float scale);
|
||||
inline void tryEraseTextureFromManager(Texture* texture) noexcept;
|
||||
|
||||
inline bool hasWindow() const noexcept { return _has_window; }
|
||||
|
||||
inline Renderer& getRenderer() { return *_renderer; }
|
||||
|
||||
~GraphicsSupport();
|
||||
|
||||
private:
|
||||
std::vector<TextureRenderData> _textures_to_render;
|
||||
PixelPutPipeline _pixel_put_pipeline;
|
||||
|
||||
std::vector<DrawableResource*> _drawlist;
|
||||
|
||||
TextManager _text_manager;
|
||||
TextureManager _texture_manager;
|
||||
|
||||
glm::mat4 _proj = glm::mat4(1.0);
|
||||
|
||||
std::shared_ptr<MLX_Window> _window;
|
||||
std::unique_ptr<TextPutPipeline> _text_put_pipeline; // unique_ptr because of the size of the class
|
||||
std::unique_ptr<Renderer> _renderer;
|
||||
|
||||
std::size_t _width = 0;
|
||||
std::size_t _height = 0;
|
||||
|
||||
int _id;
|
||||
|
||||
bool _has_window;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -10,57 +10,71 @@
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "renderer/images/texture.h"
|
||||
#include <algorithm>
|
||||
#include <core/graphics.h>
|
||||
#include <type_traits>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
int& GraphicsSupport::getID() noexcept { return _id; }
|
||||
std::shared_ptr<MLX_Window> GraphicsSupport::getWindow() { return _window; }
|
||||
|
||||
void GraphicsSupport::beginRender() noexcept
|
||||
{
|
||||
if(!_renderer->beginFrame())
|
||||
return;
|
||||
_proj = glm::ortho<float>(0, _window->getWidth(), 0, _window->getHeight());
|
||||
_renderer->getUniformBuffer()->setData(sizeof(_proj), &_proj);
|
||||
}
|
||||
|
||||
void GraphicsSupport::clearRenderData() noexcept
|
||||
{
|
||||
_textures_to_render.clear();
|
||||
MLX_PROFILE_FUNCTION();
|
||||
_drawlist.clear();
|
||||
_pixel_put_pipeline.clear();
|
||||
_text_put_pipeline->clear();
|
||||
_text_manager.clear();
|
||||
_texture_manager.clear();
|
||||
}
|
||||
|
||||
void GraphicsSupport::pixelPut(int x, int y, uint32_t color) noexcept
|
||||
void GraphicsSupport::pixelPut(int x, int y, std::uint32_t color) noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
_pixel_put_pipeline.setPixel(x, y, color);
|
||||
}
|
||||
|
||||
void GraphicsSupport::stringPut(int x, int y, int color, std::string str)
|
||||
void GraphicsSupport::stringPut(int x, int y, std::uint32_t color, std::string str)
|
||||
{
|
||||
_text_put_pipeline->put(x, y, color, str);
|
||||
MLX_PROFILE_FUNCTION();
|
||||
std::pair<DrawableResource*, bool> res = _text_manager.registerText(x, y, color, str);
|
||||
if(!res.second) // if this is not a completly new text draw
|
||||
{
|
||||
auto it = std::find(_drawlist.begin(), _drawlist.end(), res.first);
|
||||
if(it != _drawlist.end())
|
||||
_drawlist.erase(it);
|
||||
}
|
||||
_drawlist.push_back(res.first);
|
||||
}
|
||||
|
||||
void GraphicsSupport::texturePut(Texture* texture, int x, int y)
|
||||
{
|
||||
_textures_to_render.emplace_back(texture, x, y);
|
||||
std::size_t hash = std::hash<TextureRenderData>{}(_textures_to_render.back());
|
||||
_textures_to_render.back().hash = hash;
|
||||
|
||||
auto it = std::find_if(_textures_to_render.begin(), _textures_to_render.end() - 1, [=](const TextureRenderData& rhs)
|
||||
MLX_PROFILE_FUNCTION();
|
||||
auto res = _texture_manager.registerTexture(texture, x, y);
|
||||
if(!res.second) // if this is not a completly new texture draw
|
||||
{
|
||||
return rhs.hash == hash;
|
||||
});
|
||||
|
||||
if(it != _textures_to_render.end() - 1)
|
||||
_textures_to_render.erase(it);
|
||||
auto it = std::find(_drawlist.begin(), _drawlist.end(), res.first);
|
||||
if(it != _drawlist.end())
|
||||
_drawlist.erase(it);
|
||||
}
|
||||
_drawlist.push_back(res.first);
|
||||
}
|
||||
|
||||
void GraphicsSupport::loadFont(const std::filesystem::path& filepath, float scale)
|
||||
{
|
||||
_text_put_pipeline->loadFont(filepath, scale);
|
||||
MLX_PROFILE_FUNCTION();
|
||||
_text_manager.loadFont(*_renderer, filepath, scale);
|
||||
}
|
||||
|
||||
void GraphicsSupport::tryEraseTextureFromManager(Texture* texture) noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
for(auto it = _drawlist.begin(); it != _drawlist.end();)
|
||||
{
|
||||
if(_texture_manager.isTextureKnown(texture))
|
||||
it = _drawlist.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
_texture_manager.eraseTextures(texture);
|
||||
}
|
||||
}
|
||||
|
||||
65
src/core/memory.cpp
git.filemode.normal_file
@@ -0,0 +1,65 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* memory.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/12/07 16:32:01 by kbz_8 #+# #+# */
|
||||
/* Updated: 2023/12/11 15:25:02 by kbz_8 ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <core/memory.h>
|
||||
#include <core/errors.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
void* MemManager::malloc(std::size_t size)
|
||||
{
|
||||
void* ptr = std::malloc(size);
|
||||
if(ptr != nullptr)
|
||||
_blocks.push_back(ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* MemManager::calloc(std::size_t n, std::size_t size)
|
||||
{
|
||||
void* ptr = std::calloc(n, size);
|
||||
if(ptr != nullptr)
|
||||
_blocks.push_back(ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* MemManager::realloc(void* ptr, std::size_t size)
|
||||
{
|
||||
void* ptr2 = std::realloc(ptr, size);
|
||||
if(ptr2 != nullptr)
|
||||
_blocks.push_back(ptr2);
|
||||
auto it = std::find(_blocks.begin(), _blocks.end(), ptr);
|
||||
if(it != _blocks.end())
|
||||
_blocks.erase(it);
|
||||
return ptr2;
|
||||
}
|
||||
|
||||
void MemManager::free(void* ptr)
|
||||
{
|
||||
auto it = std::find(_blocks.begin(), _blocks.end(), ptr);
|
||||
if(it == _blocks.end())
|
||||
{
|
||||
core::error::report(e_kind::error, "Memory Manager : trying to free a pointer not allocated by the memory manager");
|
||||
return;
|
||||
}
|
||||
std::free(*it);
|
||||
_blocks.erase(it);
|
||||
}
|
||||
|
||||
MemManager::~MemManager()
|
||||
{
|
||||
std::for_each(_blocks.begin(), _blocks.end(), [](void* ptr)
|
||||
{
|
||||
std::free(ptr);
|
||||
});
|
||||
}
|
||||
}
|
||||
41
src/core/memory.h
git.filemode.normal_file
@@ -0,0 +1,41 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* memory.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/12/07 16:31:51 by kbz_8 #+# #+# */
|
||||
/* Updated: 2023/12/11 19:47:13 by kbz_8 ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __MLX_MEMORY__
|
||||
#define __MLX_MEMORY__
|
||||
|
||||
#include <utils/singleton.h>
|
||||
#include <mlx_profile.h>
|
||||
#include <list>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
class MemManager : public Singleton<MemManager>
|
||||
{
|
||||
friend class Singleton<MemManager>;
|
||||
|
||||
public:
|
||||
static void* malloc(std::size_t size);
|
||||
static void* calloc(std::size_t n, std::size_t size);
|
||||
static void* realloc(void* ptr, std::size_t size);
|
||||
static void free(void* ptr);
|
||||
|
||||
private:
|
||||
MemManager() = default;
|
||||
~MemManager();
|
||||
|
||||
private:
|
||||
inline static std::list<void*> _blocks;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,60 +0,0 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* profile.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/11/10 08:49:17 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/10 09:05:56 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __MLX_PROFILE__
|
||||
#define __MLX_PROFILE__
|
||||
|
||||
// Try to identify the compiler
|
||||
#if defined(__BORLANDC__)
|
||||
#define MLX_COMPILER_BORDLAND
|
||||
#elif defined(__clang__)
|
||||
#define MLX_COMPILER_CLANG
|
||||
#ifdef __MINGW32__
|
||||
#define MLX_COMPILER_MINGW
|
||||
#ifdef __MINGW64_VERSION_MAJOR
|
||||
#define MLX_COMPILER_MINGW_W64
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(__GNUC__) || defined(__MINGW32__)
|
||||
#define MLX_COMPILER_GCC
|
||||
#ifdef __MINGW32__
|
||||
#define MLX_COMPILER_MINGW
|
||||
#ifdef __MINGW64_VERSION_MAJOR
|
||||
#define MLX_COMPILER_MINGW_W64
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(__INTEL_COMPILER) || defined(__ICL)
|
||||
#define MLX_COMPILER_INTEL
|
||||
#elif defined(_MSC_VER)
|
||||
#define MLX_COMPILER_MSVC
|
||||
#else
|
||||
#define MLX_COMPILER_UNKNOWN
|
||||
#warning "This compiler is not fully supported"
|
||||
#endif
|
||||
|
||||
// Checking common assumptions
|
||||
#include <climits>
|
||||
#include <cstdint>
|
||||
|
||||
static_assert(CHAR_BIT == 8, "CHAR_BIT is expected to be 8");
|
||||
|
||||
static_assert(sizeof(int8_t) == 1, "int8_t is not of the correct size" );
|
||||
static_assert(sizeof(int16_t) == 2, "int16_t is not of the correct size");
|
||||
static_assert(sizeof(int32_t) == 4, "int32_t is not of the correct size");
|
||||
static_assert(sizeof(int64_t) == 8, "int64_t is not of the correct size");
|
||||
|
||||
static_assert(sizeof(uint8_t) == 1, "uint8_t is not of the correct size" );
|
||||
static_assert(sizeof(uint16_t) == 2, "uint16_t is not of the correct size");
|
||||
static_assert(sizeof(uint32_t) == 4, "uint32_t is not of the correct size");
|
||||
static_assert(sizeof(uint64_t) == 8, "uint64_t is not of the correct size");
|
||||
|
||||
#endif
|
||||
79
src/core/profiler.cpp
git.filemode.normal_file
@@ -0,0 +1,79 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* profiler.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/01/10 13:56:21 by maldavid #+# #+# */
|
||||
/* Updated: 2024/01/10 18:17:35 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <core/profiler.h>
|
||||
#include <core/errors.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
void Profiler::beginRuntimeSession()
|
||||
{
|
||||
std::lock_guard lock(_mutex);
|
||||
if(_runtime_session_began)
|
||||
return;
|
||||
_output_stream.open("./runtime_profile.mlx.json", std::ofstream::out | std::ofstream::trunc);
|
||||
|
||||
if(_output_stream.is_open())
|
||||
writeHeader();
|
||||
else
|
||||
core::error::report(e_kind::error, "Profiler : cannot open runtime profile file");
|
||||
_runtime_session_began = true;
|
||||
}
|
||||
|
||||
void Profiler::appendProfileData(ProfileResult&& result)
|
||||
{
|
||||
std::lock_guard lock(_mutex);
|
||||
auto it = _profile_data.find(result.name);
|
||||
if(it != _profile_data.end())
|
||||
{
|
||||
result.elapsed_time = (result.elapsed_time + it->second.second.elapsed_time) / it->second.first;
|
||||
_profile_data[result.name].first++;
|
||||
_profile_data[result.name].second = result;
|
||||
}
|
||||
else
|
||||
_profile_data[result.name] = std::make_pair(1, result);
|
||||
}
|
||||
|
||||
void Profiler::writeProfile(const ProfileResult& result)
|
||||
{
|
||||
std::stringstream json;
|
||||
json << std::setprecision(9) << std::fixed;
|
||||
json << ",\n{\n";
|
||||
json << "\t\"type\" : \"function\"," << '\n';
|
||||
json << "\t\"name\" : \"" << result.name << "\"," << '\n';
|
||||
json << "\t\"thread id\" : " << result.thread_id << "," << '\n';
|
||||
json << "\t\"average duration\" : \"" << result.elapsed_time.count() << "ms\"\n";
|
||||
json << "}";
|
||||
_output_stream << json.str();
|
||||
}
|
||||
|
||||
void Profiler::endRuntimeSession()
|
||||
{
|
||||
std::lock_guard lock(_mutex);
|
||||
if(!_runtime_session_began)
|
||||
return;
|
||||
for(auto& [_, pair] : _profile_data)
|
||||
writeProfile(pair.second);
|
||||
writeFooter();
|
||||
_output_stream.close();
|
||||
_profile_data.clear();
|
||||
_runtime_session_began = false;
|
||||
}
|
||||
|
||||
Profiler::~Profiler()
|
||||
{
|
||||
if(!_runtime_session_began)
|
||||
return;
|
||||
endRuntimeSession();
|
||||
}
|
||||
}
|
||||
146
src/core/profiler.h
git.filemode.normal_file
@@ -0,0 +1,146 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* profiler.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/01/10 13:35:45 by maldavid #+# #+# */
|
||||
/* Updated: 2024/03/24 14:41:27 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __MLX_PROFILER__
|
||||
#define __MLX_PROFILER__
|
||||
|
||||
#include <utils/singleton.h>
|
||||
#include <mlx_profile.h>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <fstream>
|
||||
#include <unordered_map>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
using FloatingPointMilliseconds = std::chrono::duration<double, std::milli>;
|
||||
|
||||
struct ProfileResult
|
||||
{
|
||||
std::string name;
|
||||
FloatingPointMilliseconds elapsed_time;
|
||||
std::thread::id thread_id;
|
||||
};
|
||||
|
||||
class Profiler : public Singleton<Profiler>
|
||||
{
|
||||
friend class Singleton<Profiler>;
|
||||
|
||||
public:
|
||||
Profiler(const Profiler&) = delete;
|
||||
Profiler(Profiler&&) = delete;
|
||||
|
||||
void appendProfileData(ProfileResult&& result);
|
||||
|
||||
private:
|
||||
Profiler() { beginRuntimeSession(); }
|
||||
~Profiler();
|
||||
|
||||
void beginRuntimeSession();
|
||||
void writeProfile(const ProfileResult& result);
|
||||
void endRuntimeSession();
|
||||
inline void writeHeader()
|
||||
{
|
||||
_output_stream << "{\"profileData\":[{}";
|
||||
_output_stream.flush();
|
||||
}
|
||||
|
||||
inline void writeFooter()
|
||||
{
|
||||
_output_stream << "]}";
|
||||
_output_stream.flush();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, std::pair<std::size_t, ProfileResult>> _profile_data;
|
||||
std::ofstream _output_stream;
|
||||
std::mutex _mutex;
|
||||
bool _runtime_session_began = false;
|
||||
};
|
||||
|
||||
class ProfilerTimer
|
||||
{
|
||||
public:
|
||||
ProfilerTimer(const char* name) : _name(name)
|
||||
{
|
||||
_start_timepoint = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
inline void stop()
|
||||
{
|
||||
auto end_timepoint = std::chrono::steady_clock::now();
|
||||
auto high_res_start = FloatingPointMilliseconds{ _start_timepoint.time_since_epoch() };
|
||||
auto elapsed_time = std::chrono::time_point_cast<std::chrono::milliseconds>(end_timepoint).time_since_epoch() - std::chrono::time_point_cast<std::chrono::milliseconds>(_start_timepoint).time_since_epoch();
|
||||
|
||||
Profiler::get().appendProfileData({ _name, elapsed_time, std::this_thread::get_id() });
|
||||
|
||||
_stopped = true;
|
||||
}
|
||||
|
||||
~ProfilerTimer()
|
||||
{
|
||||
if(!_stopped)
|
||||
stop();
|
||||
}
|
||||
|
||||
private:
|
||||
std::chrono::time_point<std::chrono::steady_clock> _start_timepoint;
|
||||
const char* _name;
|
||||
bool _stopped = false;
|
||||
};
|
||||
|
||||
namespace ProfilerUtils
|
||||
{
|
||||
template <std::size_t N>
|
||||
struct ChangeResult
|
||||
{
|
||||
char data[N];
|
||||
};
|
||||
|
||||
template <std::size_t N, std::size_t K>
|
||||
constexpr auto cleanupOutputString(const char(&expr)[N], const char(&remove)[K])
|
||||
{
|
||||
ChangeResult<N> result = {};
|
||||
|
||||
std::size_t src_index = 0;
|
||||
std::size_t dst_index = 0;
|
||||
while(src_index < N)
|
||||
{
|
||||
std::size_t match_index = 0;
|
||||
while(match_index < K - 1 && src_index + match_index < N - 1 && expr[src_index + match_index] == remove[match_index])
|
||||
match_index++;
|
||||
if(match_index == K - 1)
|
||||
src_index += match_index;
|
||||
result.data[dst_index++] = expr[src_index] == '"' ? '\'' : expr[src_index];
|
||||
src_index++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PROFILER
|
||||
#define MLX_PROFILE_SCOPE_LINE2(name, line) constexpr auto fixedName##line = ::mlx::ProfilerUtils::cleanupOutputString(name, "__cdecl ");\
|
||||
::mlx::ProfilerTimer timer##line(fixedName##line.data)
|
||||
#define MLX_PROFILE_SCOPE_LINE(name, line) MLX_PROFILE_SCOPE_LINE2(name, line)
|
||||
#define MLX_PROFILE_SCOPE(name) MLX_PROFILE_SCOPE_LINE(name, __LINE__)
|
||||
#define MLX_PROFILE_FUNCTION() MLX_PROFILE_SCOPE(MLX_FUNC_SIG)
|
||||
#else
|
||||
#define MLX_PROFILE_SCOPE(name)
|
||||
#define MLX_PROFILE_FUNCTION()
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -6,24 +6,19 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/05 16:30:19 by maldavid #+# #+# */
|
||||
/* Updated: 2023/08/28 10:49:03 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/02/23 22:27:30 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "inputs.h"
|
||||
#include <mlx.h>
|
||||
#include <cstring>
|
||||
#include <core/profiler.h>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
Input::Input()
|
||||
{
|
||||
std::memset(_keys.data(), 0, SDL_NUM_SCANCODES);
|
||||
std::memset(_mouse.data(), 0, 8);
|
||||
}
|
||||
|
||||
void Input::update()
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
_xRel = 0;
|
||||
_yRel = 0;
|
||||
|
||||
@@ -38,8 +33,8 @@ namespace mlx
|
||||
_yRel = _event.motion.yrel;
|
||||
}
|
||||
|
||||
uint32_t id = _event.window.windowID;
|
||||
if(!_events_hooks.count(id))
|
||||
std::uint32_t id = _event.window.windowID;
|
||||
if(_events_hooks.find(id) == _events_hooks.end())
|
||||
continue;
|
||||
auto& hooks = _events_hooks[id];
|
||||
|
||||
@@ -47,7 +42,6 @@ namespace mlx
|
||||
{
|
||||
case SDL_KEYDOWN:
|
||||
{
|
||||
_keys[_event.key.keysym.scancode] = static_cast<uint8_t>(action::down);
|
||||
if(hooks[MLX_KEYDOWN].hook)
|
||||
hooks[MLX_KEYDOWN].hook(_event.key.keysym.scancode, hooks[MLX_KEYDOWN].param);
|
||||
break;
|
||||
@@ -55,7 +49,6 @@ namespace mlx
|
||||
|
||||
case SDL_KEYUP:
|
||||
{
|
||||
_keys[_event.key.keysym.scancode] = static_cast<uint8_t>(action::up);
|
||||
if(hooks[MLX_KEYUP].hook)
|
||||
hooks[MLX_KEYUP].hook(_event.key.keysym.scancode, hooks[MLX_KEYUP].param);
|
||||
break;
|
||||
@@ -63,7 +56,6 @@ namespace mlx
|
||||
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
{
|
||||
_mouse[_event.button.button] = static_cast<uint8_t>(action::down);
|
||||
if(hooks[MLX_MOUSEDOWN].hook)
|
||||
hooks[MLX_MOUSEDOWN].hook(_event.button.button, hooks[MLX_MOUSEDOWN].param);
|
||||
break;
|
||||
@@ -71,12 +63,28 @@ namespace mlx
|
||||
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
{
|
||||
_mouse[_event.button.button] = static_cast<uint8_t>(action::up);
|
||||
if(hooks[MLX_MOUSEUP].hook)
|
||||
hooks[MLX_MOUSEUP].hook(_event.button.button, hooks[MLX_MOUSEUP].param);
|
||||
break;
|
||||
}
|
||||
|
||||
case SDL_MOUSEWHEEL:
|
||||
{
|
||||
if(hooks[MLX_MOUSEWHEEL].hook)
|
||||
{
|
||||
if(_event.wheel.y > 0) // scroll up
|
||||
hooks[MLX_MOUSEWHEEL].hook(1, hooks[MLX_MOUSEWHEEL].param);
|
||||
else if(_event.wheel.y < 0) // scroll down
|
||||
hooks[MLX_MOUSEWHEEL].hook(2, hooks[MLX_MOUSEWHEEL].param);
|
||||
|
||||
if(_event.wheel.x > 0) // scroll right
|
||||
hooks[MLX_MOUSEWHEEL].hook(3, hooks[MLX_MOUSEWHEEL].param);
|
||||
else if(_event.wheel.x < 0) // scroll left
|
||||
hooks[MLX_MOUSEWHEEL].hook(4, hooks[MLX_MOUSEWHEEL].param);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SDL_WINDOWEVENT:
|
||||
{
|
||||
auto& win_hook = hooks[MLX_WINDOW_EVENT];
|
||||
@@ -115,19 +123,19 @@ namespace mlx
|
||||
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
||||
{
|
||||
if(win_hook.hook)
|
||||
win_hook.hook(4, win_hook.param);
|
||||
win_hook.hook(5, win_hook.param);
|
||||
break;
|
||||
}
|
||||
case SDL_WINDOWEVENT_LEAVE:
|
||||
{
|
||||
if(win_hook.hook)
|
||||
win_hook.hook(5, win_hook.param);
|
||||
win_hook.hook(6, win_hook.param);
|
||||
break;
|
||||
}
|
||||
case SDL_WINDOWEVENT_FOCUS_LOST:
|
||||
{
|
||||
if(win_hook.hook)
|
||||
win_hook.hook(4, win_hook.param);
|
||||
win_hook.hook(7, win_hook.param);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,40 +6,36 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/05 16:27:35 by maldavid #+# #+# */
|
||||
/* Updated: 2023/04/19 12:14:43 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/04/22 17:35:23 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <function.h>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <mlx_profile.h>
|
||||
|
||||
#include "window.h"
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
enum class action : uint8_t { up = (1 << 1), down = (1 << 2) };
|
||||
|
||||
struct Hook
|
||||
{
|
||||
std::function<int(int, void*)> hook;
|
||||
func::function<int(int, void*)> hook;
|
||||
void* param = nullptr;
|
||||
};
|
||||
|
||||
class Input
|
||||
{
|
||||
public:
|
||||
Input();
|
||||
Input() = default;
|
||||
|
||||
void update();
|
||||
|
||||
inline bool getInKey(const SDL_Scancode key, action type = action::down) const noexcept { return _keys[key] & static_cast<uint8_t>(type); }
|
||||
|
||||
inline bool getInMouse(const uint8_t button, action type = action::down) const noexcept { return _mouse[button] & static_cast<uint8_t>(type); }
|
||||
inline bool isMouseMoving() const noexcept { return _xRel || _yRel; }
|
||||
|
||||
inline int getX() const noexcept { return _x; }
|
||||
@@ -48,7 +44,8 @@ namespace mlx
|
||||
inline int getXRel() const noexcept { return _xRel; }
|
||||
inline int getYRel() const noexcept { return _yRel; }
|
||||
|
||||
inline bool is_running() const noexcept { return !_end; }
|
||||
inline bool isRunning() const noexcept { return !_end; }
|
||||
inline constexpr void run() noexcept { _end = false; }
|
||||
inline constexpr void finish() noexcept { _end = true; }
|
||||
|
||||
inline void addWindow(std::shared_ptr<MLX_Window> window)
|
||||
@@ -57,7 +54,7 @@ namespace mlx
|
||||
_events_hooks[window->getID()] = {};
|
||||
}
|
||||
|
||||
inline void onEvent(uint32_t id, int event, int (*funct_ptr)(int, void*), void* param) noexcept
|
||||
inline void onEvent(std::uint32_t id, int event, int (*funct_ptr)(int, void*), void* param) noexcept
|
||||
{
|
||||
_events_hooks[id][event].hook = funct_ptr;
|
||||
_events_hooks[id][event].param = param;
|
||||
@@ -66,11 +63,9 @@ namespace mlx
|
||||
~Input() = default;
|
||||
|
||||
private:
|
||||
std::array<uint8_t, SDL_NUM_SCANCODES> _keys;
|
||||
std::unordered_map<uint32_t, std::shared_ptr<MLX_Window>> _windows;
|
||||
std::unordered_map<uint32_t, std::array<Hook, 5>> _events_hooks;
|
||||
std::unordered_map<std::uint32_t, std::shared_ptr<MLX_Window>> _windows;
|
||||
std::unordered_map<std::uint32_t, std::array<Hook, 6>> _events_hooks;
|
||||
SDL_Event _event;
|
||||
std::array<uint8_t, 8> _mouse;
|
||||
|
||||
int _x = 0;
|
||||
int _y = 0;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/04 17:36:44 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/25 11:48:26 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/01/16 07:59:21 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -17,19 +17,21 @@
|
||||
namespace mlx
|
||||
{
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
constexpr const uint32_t rmask = 0xff000000;
|
||||
constexpr const uint32_t gmask = 0x00ff0000;
|
||||
constexpr const uint32_t bmask = 0x0000ff00;
|
||||
constexpr const uint32_t amask = 0x000000ff;
|
||||
constexpr const std::uint32_t rmask = 0xff000000;
|
||||
constexpr const std::uint32_t gmask = 0x00ff0000;
|
||||
constexpr const std::uint32_t bmask = 0x0000ff00;
|
||||
constexpr const std::uint32_t amask = 0x000000ff;
|
||||
#else
|
||||
constexpr const uint32_t rmask = 0x000000ff;
|
||||
constexpr const uint32_t gmask = 0x0000ff00;
|
||||
constexpr const uint32_t bmask = 0x00ff0000;
|
||||
constexpr const uint32_t amask = 0xff000000;
|
||||
constexpr const std::uint32_t rmask = 0x000000ff;
|
||||
constexpr const std::uint32_t gmask = 0x0000ff00;
|
||||
constexpr const std::uint32_t bmask = 0x00ff0000;
|
||||
constexpr const std::uint32_t amask = 0xff000000;
|
||||
#endif
|
||||
|
||||
MLX_Window::MLX_Window(std::size_t w, std::size_t h, const std::string& title) : _width(w), _height(h)
|
||||
{
|
||||
if(title.find("vvaas") != std::string::npos)
|
||||
core::error::report(e_kind::message, "vvaas est mauvais");
|
||||
_win = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h, SDL_WINDOW_VULKAN | SDL_WINDOW_SHOWN);
|
||||
if(!_win)
|
||||
core::error::report(e_kind::fatal_error, std::string("unable to open a new window, ") + SDL_GetError());
|
||||
@@ -40,14 +42,15 @@ namespace mlx
|
||||
|
||||
void MLX_Window::destroy() noexcept
|
||||
{
|
||||
if(_win)
|
||||
if(_win != nullptr)
|
||||
{
|
||||
SDL_DestroyWindow(_win);
|
||||
if(_icon)
|
||||
_win = nullptr;
|
||||
}
|
||||
if(_icon != nullptr)
|
||||
{
|
||||
SDL_FreeSurface(_icon);
|
||||
}
|
||||
|
||||
MLX_Window::~MLX_Window()
|
||||
{
|
||||
destroy();
|
||||
_icon = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/04 21:53:12 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/25 11:33:32 by maldavid ### ########.fr */
|
||||
/* Updated: 2023/12/21 00:24:26 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <string>
|
||||
#include <mlx_profile.h>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
@@ -26,18 +27,18 @@ namespace mlx
|
||||
inline SDL_Window* getNativeWindow() const noexcept { return _win; }
|
||||
inline int getWidth() const noexcept { return _width; }
|
||||
inline int getHeight() const noexcept { return _height; }
|
||||
inline uint32_t getID() const noexcept { return _id; }
|
||||
inline std::uint32_t getID() const noexcept { return _id; }
|
||||
|
||||
void destroy() noexcept;
|
||||
|
||||
~MLX_Window();
|
||||
~MLX_Window() = default;
|
||||
|
||||
private:
|
||||
SDL_Surface* _icon = nullptr;
|
||||
SDL_Window* _win = nullptr;
|
||||
int _width = 0;
|
||||
int _height = 0;
|
||||
uint32_t _id = -1;
|
||||
std::uint32_t _id = -1;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/08 18:55:57 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/16 13:54:25 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/03/14 17:28:35 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -14,18 +14,19 @@
|
||||
#include <renderer/command/vk_cmd_pool.h>
|
||||
#include <renderer/command/vk_cmd_buffer.h>
|
||||
#include <renderer/core/render_core.h>
|
||||
#include <core/profiler.h>
|
||||
#include <vma.h>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
void Buffer::create(Buffer::kind type, VkDeviceSize size, VkBufferUsageFlags usage, const char* name, const void* data)
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
_usage = usage;
|
||||
if(type == Buffer::kind::constant)
|
||||
if(type == Buffer::kind::constant || type == Buffer::kind::dynamic_device_local)
|
||||
{
|
||||
if(data == nullptr)
|
||||
if(data == nullptr && type == Buffer::kind::constant)
|
||||
{
|
||||
core::error::report(e_kind::warning, "Vulkan : trying to create constant buffer without data (constant buffers cannot be modified after creation)");
|
||||
return;
|
||||
@@ -45,13 +46,14 @@ namespace mlx
|
||||
mapMem(&mapped);
|
||||
std::memcpy(mapped, data, size);
|
||||
unmapMem();
|
||||
if(type == Buffer::kind::constant)
|
||||
if(type == Buffer::kind::constant || type == Buffer::kind::dynamic_device_local)
|
||||
pushToGPU();
|
||||
}
|
||||
}
|
||||
|
||||
void Buffer::destroy() noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
if(_is_mapped)
|
||||
unmapMem();
|
||||
if(_buffer != VK_NULL_HANDLE)
|
||||
@@ -59,8 +61,9 @@ namespace mlx
|
||||
_buffer = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
void Buffer::createBuffer(VkBufferUsageFlags usage, VmaAllocationCreateInfo info, VkDeviceSize size, const char* name)
|
||||
void Buffer::createBuffer(VkBufferUsageFlags usage, VmaAllocationCreateInfo info, VkDeviceSize size, [[maybe_unused]] const char* name)
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
VkBufferCreateInfo bufferInfo{};
|
||||
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
bufferInfo.size = size;
|
||||
@@ -74,7 +77,7 @@ namespace mlx
|
||||
alloc_name.append("_index_buffer");
|
||||
else if(usage & VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)
|
||||
alloc_name.append("_vertex_buffer");
|
||||
else if((usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) != 1)
|
||||
else if(!(usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT))
|
||||
alloc_name.append("_buffer");
|
||||
_allocation = Render_Core::get().getAllocator().createBuffer(&bufferInfo, &info, _buffer, alloc_name.c_str());
|
||||
#else
|
||||
@@ -83,8 +86,34 @@ namespace mlx
|
||||
_size = size;
|
||||
}
|
||||
|
||||
bool Buffer::copyFromBuffer(const Buffer& buffer) noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
if(!(_usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT))
|
||||
{
|
||||
core::error::report(e_kind::error, "Vulkan : buffer cannot be the destination of a copy because it does not have the correct usage flag");
|
||||
return false;
|
||||
}
|
||||
if(!(buffer._usage & VK_BUFFER_USAGE_TRANSFER_SRC_BIT))
|
||||
{
|
||||
core::error::report(e_kind::error, "Vulkan : buffer cannot be the source of a copy because it does not have the correct usage flag");
|
||||
return false;
|
||||
}
|
||||
|
||||
CmdBuffer& cmd = Render_Core::get().getSingleTimeCmdBuffer();
|
||||
cmd.beginRecord();
|
||||
|
||||
cmd.copyBuffer(*this, const_cast<Buffer&>(buffer));
|
||||
|
||||
cmd.endRecord();
|
||||
cmd.submitIdle();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Buffer::pushToGPU() noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
VmaAllocationCreateInfo alloc_info{};
|
||||
alloc_info.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
|
||||
|
||||
@@ -97,25 +126,8 @@ namespace mlx
|
||||
newBuffer.createBuffer(newBuffer._usage, alloc_info, _size, nullptr);
|
||||
#endif
|
||||
|
||||
CmdPool cmdpool;
|
||||
cmdpool.init();
|
||||
CmdBuffer cmdBuffer;
|
||||
cmdBuffer.init(&cmdpool);
|
||||
|
||||
cmdBuffer.beginRecord(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
|
||||
|
||||
VkBufferCopy copyRegion{};
|
||||
copyRegion.size = _size;
|
||||
vkCmdCopyBuffer(cmdBuffer.get(), _buffer, newBuffer._buffer, 1, ©Region);
|
||||
|
||||
cmdBuffer.endRecord();
|
||||
cmdBuffer.submitIdle();
|
||||
|
||||
cmdBuffer.destroy();
|
||||
cmdpool.destroy();
|
||||
|
||||
this->swap(newBuffer);
|
||||
|
||||
if(newBuffer.copyFromBuffer(*this)) // if the copy succeded we swap the buffers, otherwise the new one is deleted
|
||||
this->swap(newBuffer);
|
||||
newBuffer.destroy();
|
||||
}
|
||||
|
||||
@@ -140,6 +152,12 @@ namespace mlx
|
||||
VkBufferUsageFlags temp_u = _usage;
|
||||
_usage = buffer._usage;
|
||||
buffer._usage = temp_u;
|
||||
|
||||
#ifdef DEBUG
|
||||
std::string temp_n = _name;
|
||||
_name = buffer._name;
|
||||
buffer._name = temp_n;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Buffer::flush(VkDeviceSize size, VkDeviceSize offset)
|
||||
|
||||
@@ -6,22 +6,24 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/06 23:18:52 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/16 13:56:19 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/01/11 05:16:58 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __MLX_VK_BUFFER__
|
||||
#define __MLX_VK_BUFFER__
|
||||
|
||||
#include <mlx_profile.h>
|
||||
#include <volk.h>
|
||||
#include <renderer/core/render_core.h>
|
||||
#include <renderer/core/cmd_resource.h>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
class Buffer
|
||||
class Buffer : public CmdResource
|
||||
{
|
||||
public:
|
||||
enum class kind { dynamic, uniform, constant };
|
||||
enum class kind { dynamic, dynamic_device_local, uniform, constant };
|
||||
|
||||
void create(kind type, VkDeviceSize size, VkBufferUsageFlags usage, const char* name, const void* data = nullptr);
|
||||
void destroy() noexcept;
|
||||
@@ -31,6 +33,7 @@ namespace mlx
|
||||
inline void unmapMem() noexcept { Render_Core::get().getAllocator().unmapMemory(_allocation); _is_mapped = false; }
|
||||
|
||||
void flush(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
|
||||
bool copyFromBuffer(const Buffer& buffer) noexcept;
|
||||
|
||||
inline VkBuffer& operator()() noexcept { return _buffer; }
|
||||
inline VkBuffer& get() noexcept { return _buffer; }
|
||||
|
||||
@@ -6,13 +6,14 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/01/25 15:05:05 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/14 03:25:59 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/01/10 23:05:15 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __VK_IBO__
|
||||
#define __VK_IBO__
|
||||
|
||||
#include <mlx_profile.h>
|
||||
#include <volk.h>
|
||||
#include "vk_buffer.h"
|
||||
#include <renderer/renderer.h>
|
||||
@@ -22,8 +23,8 @@ namespace mlx
|
||||
class C_IBO : public Buffer
|
||||
{
|
||||
public:
|
||||
inline void create(uint32_t size, const uint16_t* data, const char* name) { Buffer::create(Buffer::kind::constant, size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, name, data); }
|
||||
inline void bind(Renderer& renderer) noexcept { vkCmdBindIndexBuffer(renderer.getActiveCmdBuffer().get(), _buffer, _offset, VK_INDEX_TYPE_UINT16); }
|
||||
inline void create(std::uint32_t size, const std::uint16_t* data, const char* name) { Buffer::create(Buffer::kind::constant, size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, name, data); }
|
||||
inline void bind(Renderer& renderer) noexcept { renderer.getActiveCmdBuffer().bindIndexBuffer(*this); }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -6,18 +6,20 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/06 18:45:52 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/16 13:57:42 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/01/10 18:30:57 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "vk_ubo.h"
|
||||
#include <cstring>
|
||||
#include <renderer/renderer.h>
|
||||
#include <core/profiler.h>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
void UBO::create(Renderer* renderer, uint32_t size, const char* name)
|
||||
void UBO::create(Renderer* renderer, std::uint32_t size, [[maybe_unused]] const char* name)
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
_renderer = renderer;
|
||||
|
||||
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
|
||||
@@ -35,14 +37,16 @@ namespace mlx
|
||||
}
|
||||
}
|
||||
|
||||
void UBO::setData(uint32_t size, const void* data)
|
||||
void UBO::setData(std::uint32_t size, const void* data)
|
||||
{
|
||||
std::memcpy(_maps[_renderer->getActiveImageIndex()], data, static_cast<size_t>(size));
|
||||
MLX_PROFILE_FUNCTION();
|
||||
std::memcpy(_maps[_renderer->getActiveImageIndex()], data, static_cast<std::size_t>(size));
|
||||
}
|
||||
|
||||
void UBO::setDynamicData(uint32_t size, const void* data)
|
||||
void UBO::setDynamicData(std::uint32_t size, const void* data)
|
||||
{
|
||||
std::memcpy(_maps[_renderer->getActiveImageIndex()], data, static_cast<size_t>(size));
|
||||
MLX_PROFILE_FUNCTION();
|
||||
std::memcpy(_maps[_renderer->getActiveImageIndex()], data, static_cast<std::size_t>(size));
|
||||
_buffers[_renderer->getActiveImageIndex()].flush();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/06 18:45:29 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/14 03:26:10 by maldavid ### ########.fr */
|
||||
/* Updated: 2023/12/08 19:06:28 by kbz_8 ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -16,16 +16,17 @@
|
||||
#include "vk_buffer.h"
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <mlx_profile.h>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
class UBO
|
||||
{
|
||||
public:
|
||||
void create(class Renderer* renderer, uint32_t size, const char* name);
|
||||
void create(class Renderer* renderer, std::uint32_t size, const char* name);
|
||||
|
||||
void setData(uint32_t size, const void* data);
|
||||
void setDynamicData(uint32_t size, const void* data);
|
||||
void setData(std::uint32_t size, const void* data);
|
||||
void setDynamicData(std::uint32_t size, const void* data);
|
||||
|
||||
void destroy() noexcept;
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/06 18:28:08 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/10 08:33:52 by maldavid ### ########.fr */
|
||||
/* Updated: 2023/12/12 22:17:14 by kbz_8 ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -15,17 +15,41 @@
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
void VBO::setData(uint32_t size, const void* data)
|
||||
void VBO::setData(std::uint32_t size, const void* data)
|
||||
{
|
||||
if(size > getSize())
|
||||
{
|
||||
core::error::report(e_kind::error, "Vulkan : trying to store to much data in a vertex buffer (%d bytes in %d bytes)", size, getSize());
|
||||
return;
|
||||
}
|
||||
|
||||
if(data == nullptr)
|
||||
core::error::report(e_kind::warning, "Vulkan : mapping null data in a vertex buffer");
|
||||
|
||||
void* temp = nullptr;
|
||||
mapMem(&temp);
|
||||
std::memcpy(temp, data, static_cast<size_t>(size));
|
||||
std::memcpy(temp, data, static_cast<std::size_t>(size));
|
||||
unmapMem();
|
||||
}
|
||||
|
||||
void D_VBO::setData(std::uint32_t size, const void* data)
|
||||
{
|
||||
if(size > getSize())
|
||||
{
|
||||
core::error::report(e_kind::error, "Vulkan : trying to store to much data in a vertex buffer (%d bytes in %d bytes)", size, getSize());
|
||||
return;
|
||||
}
|
||||
|
||||
if(data == nullptr)
|
||||
core::error::report(e_kind::warning, "Vulkan : mapping null data in a vertex buffer");
|
||||
|
||||
Buffer tmp_buf;
|
||||
#ifdef DEBUG
|
||||
tmp_buf.create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, "tmp_buffer", data);
|
||||
#else
|
||||
tmp_buf.create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, nullptr, data);
|
||||
#endif
|
||||
copyFromBuffer(tmp_buf);
|
||||
tmp_buf.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/06 18:27:38 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/14 04:53:36 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/01/10 23:04:40 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -15,22 +15,31 @@
|
||||
|
||||
#include "vk_buffer.h"
|
||||
#include <renderer/renderer.h>
|
||||
#include <mlx_profile.h>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
class VBO : public Buffer
|
||||
{
|
||||
public:
|
||||
inline void create(uint32_t size, const char* name) { Buffer::create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, name); }
|
||||
void setData(uint32_t size, const void* data);
|
||||
inline void bind(Renderer& renderer) noexcept { vkCmdBindVertexBuffers(renderer.getActiveCmdBuffer().get(), 0, 1, &_buffer, &_offset); }
|
||||
inline void create(std::uint32_t size, const void* data, const char* name) { Buffer::create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, name, data); }
|
||||
void setData(std::uint32_t size, const void* data);
|
||||
inline void bind(Renderer& renderer) noexcept { renderer.getActiveCmdBuffer().bindVertexBuffer(*this); }
|
||||
};
|
||||
|
||||
class D_VBO : public Buffer
|
||||
{
|
||||
public:
|
||||
inline void create(std::uint32_t size, const void* data, const char* name) { Buffer::create(Buffer::kind::dynamic_device_local, size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, name, data); }
|
||||
void setData(std::uint32_t size, const void* data);
|
||||
inline void bind(Renderer& renderer) noexcept { renderer.getActiveCmdBuffer().bindVertexBuffer(*this); }
|
||||
};
|
||||
|
||||
class C_VBO : public Buffer
|
||||
{
|
||||
public:
|
||||
inline void create(uint32_t size, const void* data, const char* name) { Buffer::create(Buffer::kind::constant, size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, name, data); }
|
||||
inline void bind(Renderer& renderer) noexcept { vkCmdBindVertexBuffers(renderer.getActiveCmdBuffer().get(), 0, 1, &_buffer, &_offset); }
|
||||
inline void create(std::uint32_t size, const void* data, const char* name) { Buffer::create(Buffer::kind::constant, size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, name, data); }
|
||||
inline void bind(Renderer& renderer) noexcept { renderer.getActiveCmdBuffer().bindVertexBuffer(*this); }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/04/02 17:50:52 by maldavid #+# #+# */
|
||||
/* Updated: 2023/04/02 17:51:46 by maldavid ### ########.fr */
|
||||
/* Updated: 2023/12/17 20:10:45 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace mlx
|
||||
{
|
||||
_cmd_pool.init();
|
||||
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
|
||||
_cmd_buffers[i].init(this);
|
||||
_cmd_buffers[i].init(CmdBuffer::kind::long_time, this);
|
||||
}
|
||||
|
||||
void CmdManager::beginRecord(int active_image_index)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/04/02 17:48:52 by maldavid #+# #+# */
|
||||
/* Updated: 2023/04/02 17:50:48 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/01/03 15:27:35 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <mlx_profile.h>
|
||||
#include <volk.h>
|
||||
#include <renderer/core/render_core.h>
|
||||
#include <renderer/command/vk_cmd_pool.h>
|
||||
|
||||
64
src/renderer/command/single_time_cmd_manager.cpp
git.filemode.normal_file
@@ -0,0 +1,64 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* single_time_cmd_manager.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/12/15 19:57:49 by maldavid #+# #+# */
|
||||
/* Updated: 2024/10/19 10:47:04 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <algorithm>
|
||||
#include <renderer/command/single_time_cmd_manager.h>
|
||||
#include <renderer/core/render_core.h>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
void SingleTimeCmdManager::init() noexcept
|
||||
{
|
||||
_pool.init();
|
||||
for(int i = 0; i < BASE_POOL_SIZE; i++)
|
||||
{
|
||||
_buffers.emplace_back();
|
||||
_buffers.back().init(CmdBuffer::kind::single_time, &_pool);
|
||||
}
|
||||
}
|
||||
|
||||
CmdBuffer& SingleTimeCmdManager::getCmdBuffer() noexcept
|
||||
{
|
||||
for(CmdBuffer& buf : _buffers)
|
||||
{
|
||||
if(buf.isReadyToBeUsed())
|
||||
{
|
||||
buf.reset();
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
_buffers.emplace_back().init(CmdBuffer::kind::single_time, &_pool);
|
||||
return _buffers.back();
|
||||
}
|
||||
|
||||
void SingleTimeCmdManager::updateSingleTimesCmdBuffersSubmitState() noexcept
|
||||
{
|
||||
for(CmdBuffer& cmd : _buffers)
|
||||
cmd.updateSubmitState();
|
||||
}
|
||||
|
||||
void SingleTimeCmdManager::waitForAllExecutions() noexcept
|
||||
{
|
||||
for(CmdBuffer& cmd : _buffers)
|
||||
cmd.waitForExecution();
|
||||
}
|
||||
|
||||
void SingleTimeCmdManager::destroy() noexcept
|
||||
{
|
||||
std::for_each(_buffers.begin(), _buffers.end(), [](CmdBuffer& buf)
|
||||
{
|
||||
buf.destroy();
|
||||
});
|
||||
_pool.destroy();
|
||||
_buffers.clear();
|
||||
}
|
||||
}
|
||||
50
src/renderer/command/single_time_cmd_manager.h
git.filemode.normal_file
@@ -0,0 +1,50 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* single_time_cmd_manager.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/12/15 18:25:57 by maldavid #+# #+# */
|
||||
/* Updated: 2024/01/07 01:30:19 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __MLX_SINGLE_TIME_CMD_MANAGER__
|
||||
#define __MLX_SINGLE_TIME_CMD_MANAGER__
|
||||
|
||||
#include <vector>
|
||||
#include <renderer/command/vk_cmd_buffer.h>
|
||||
#include <renderer/command/vk_cmd_pool.h>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
class CmdBuffer;
|
||||
|
||||
class SingleTimeCmdManager
|
||||
{
|
||||
friend class Render_Core;
|
||||
|
||||
public:
|
||||
SingleTimeCmdManager() = default;
|
||||
|
||||
void init() noexcept;
|
||||
void destroy() noexcept;
|
||||
|
||||
void updateSingleTimesCmdBuffersSubmitState() noexcept;
|
||||
void waitForAllExecutions() noexcept;
|
||||
|
||||
inline CmdPool& getCmdPool() noexcept { return _pool; }
|
||||
CmdBuffer& getCmdBuffer() noexcept;
|
||||
|
||||
~SingleTimeCmdManager() = default;
|
||||
|
||||
inline static constexpr const std::uint8_t BASE_POOL_SIZE = 16;
|
||||
|
||||
private:
|
||||
std::vector<CmdBuffer> _buffers;
|
||||
CmdPool _pool;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -6,24 +6,45 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/06 18:26:06 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/08 20:17:49 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/02/25 08:02:26 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "vk_cmd_buffer.h"
|
||||
#include <renderer/core/cmd_resource.h>
|
||||
#include <renderer/core/render_core.h>
|
||||
#include <renderer/command/cmd_manager.h>
|
||||
#include <renderer/core/vk_semaphore.h>
|
||||
#include <renderer/buffers/vk_buffer.h>
|
||||
#include <renderer/images/vk_image.h>
|
||||
#include <core/profiler.h>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
void CmdBuffer::init(CmdManager* manager)
|
||||
bool vector_push_back_if_not_found(std::vector<CmdResource*>& vector, CmdResource* res)
|
||||
{
|
||||
init(&manager->getCmdPool());
|
||||
auto it = std::find_if(vector.begin(), vector.end(), [=](const CmdResource* vres)
|
||||
{
|
||||
return vres->getUUID() == res->getUUID();
|
||||
});
|
||||
|
||||
if(it == vector.end())
|
||||
{
|
||||
vector.push_back(res);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CmdBuffer::init(CmdPool* pool)
|
||||
void CmdBuffer::init(kind type, CmdManager* manager)
|
||||
{
|
||||
init(type, &manager->getCmdPool());
|
||||
}
|
||||
|
||||
void CmdBuffer::init(kind type, CmdPool* pool)
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
_type = type;
|
||||
_pool = pool;
|
||||
|
||||
VkCommandBufferAllocateInfo allocInfo{};
|
||||
@@ -32,18 +53,23 @@ namespace mlx
|
||||
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
allocInfo.commandBufferCount = 1;
|
||||
|
||||
if(vkAllocateCommandBuffers(Render_Core::get().getDevice().get(), &allocInfo, &_cmd_buffer) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to allocate command buffer");
|
||||
VkResult res = vkAllocateCommandBuffers(Render_Core::get().getDevice().get(), &allocInfo, &_cmd_buffer);
|
||||
if(res != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to allocate command buffer, %s", RCore::verbaliseResultVk(res));
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : created new command buffer");
|
||||
#endif
|
||||
|
||||
_fence.init();
|
||||
_state = state::idle;
|
||||
}
|
||||
|
||||
void CmdBuffer::beginRecord(VkCommandBufferUsageFlags usage)
|
||||
{
|
||||
if(_is_recording)
|
||||
MLX_PROFILE_FUNCTION();
|
||||
if(!isInit())
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : begenning record on un uninit command buffer");
|
||||
if(_state == state::recording)
|
||||
return;
|
||||
|
||||
VkCommandBufferBeginInfo beginInfo{};
|
||||
@@ -52,62 +78,291 @@ namespace mlx
|
||||
if(vkBeginCommandBuffer(_cmd_buffer, &beginInfo) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to begin recording command buffer");
|
||||
|
||||
_is_recording = true;
|
||||
_state = state::recording;
|
||||
}
|
||||
|
||||
void CmdBuffer::bindVertexBuffer(Buffer& buffer) noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
if(!isRecording())
|
||||
{
|
||||
core::error::report(e_kind::warning, "Vulkan : trying to bind a vertex buffer to a non recording command buffer");
|
||||
return;
|
||||
}
|
||||
VkDeviceSize offset[] = { buffer.getOffset() };
|
||||
vkCmdBindVertexBuffers(_cmd_buffer, 0, 1, &buffer.get(), offset);
|
||||
|
||||
buffer.recordedInCmdBuffer();
|
||||
vector_push_back_if_not_found(_cmd_resources, &buffer);
|
||||
}
|
||||
|
||||
void CmdBuffer::bindIndexBuffer(Buffer& buffer) noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
if(!isRecording())
|
||||
{
|
||||
core::error::report(e_kind::warning, "Vulkan : trying to bind a index buffer to a non recording command buffer");
|
||||
return;
|
||||
}
|
||||
vkCmdBindIndexBuffer(_cmd_buffer, buffer.get(), buffer.getOffset(), VK_INDEX_TYPE_UINT16);
|
||||
|
||||
buffer.recordedInCmdBuffer();
|
||||
vector_push_back_if_not_found(_cmd_resources, &buffer);
|
||||
}
|
||||
|
||||
void CmdBuffer::copyBuffer(Buffer& dst, Buffer& src) noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
if(!isRecording())
|
||||
{
|
||||
core::error::report(e_kind::warning, "Vulkan : trying to do a buffer to buffer copy in a non recording command buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
preTransferBarrier();
|
||||
|
||||
VkBufferCopy copyRegion{};
|
||||
copyRegion.size = src.getSize();
|
||||
vkCmdCopyBuffer(_cmd_buffer, src.get(), dst.get(), 1, ©Region);
|
||||
|
||||
postTransferBarrier();
|
||||
|
||||
dst.recordedInCmdBuffer();
|
||||
src.recordedInCmdBuffer();
|
||||
vector_push_back_if_not_found(_cmd_resources, &dst);
|
||||
vector_push_back_if_not_found(_cmd_resources, &src);
|
||||
}
|
||||
|
||||
void CmdBuffer::copyBufferToImage(Buffer& buffer, Image& image) noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
if(!isRecording())
|
||||
{
|
||||
core::error::report(e_kind::warning, "Vulkan : trying to do a buffer to image copy in a non recording command buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
preTransferBarrier();
|
||||
|
||||
VkBufferImageCopy region{};
|
||||
region.bufferOffset = 0;
|
||||
region.bufferRowLength = 0;
|
||||
region.bufferImageHeight = 0;
|
||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.imageSubresource.mipLevel = 0;
|
||||
region.imageSubresource.baseArrayLayer = 0;
|
||||
region.imageSubresource.layerCount = 1;
|
||||
region.imageOffset = { 0, 0, 0 };
|
||||
region.imageExtent = { image.getWidth(), image.getHeight(), 1 };
|
||||
|
||||
vkCmdCopyBufferToImage(_cmd_buffer, buffer.get(), image.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||
|
||||
postTransferBarrier();
|
||||
|
||||
image.recordedInCmdBuffer();
|
||||
buffer.recordedInCmdBuffer();
|
||||
vector_push_back_if_not_found(_cmd_resources, &image);
|
||||
vector_push_back_if_not_found(_cmd_resources, &buffer);
|
||||
}
|
||||
|
||||
void CmdBuffer::copyImagetoBuffer(Image& image, Buffer& buffer) noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
if(!isRecording())
|
||||
{
|
||||
core::error::report(e_kind::warning, "Vulkan : trying to do an image to buffer copy in a non recording command buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
preTransferBarrier();
|
||||
|
||||
VkBufferImageCopy region{};
|
||||
region.bufferOffset = 0;
|
||||
region.bufferRowLength = 0;
|
||||
region.bufferImageHeight = 0;
|
||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.imageSubresource.mipLevel = 0;
|
||||
region.imageSubresource.baseArrayLayer = 0;
|
||||
region.imageSubresource.layerCount = 1;
|
||||
region.imageOffset = { 0, 0, 0 };
|
||||
region.imageExtent = { image.getWidth(), image.getHeight(), 1 };
|
||||
|
||||
vkCmdCopyImageToBuffer(_cmd_buffer, image.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer.get(), 1, ®ion);
|
||||
|
||||
postTransferBarrier();
|
||||
|
||||
image.recordedInCmdBuffer();
|
||||
buffer.recordedInCmdBuffer();
|
||||
vector_push_back_if_not_found(_cmd_resources, &buffer);
|
||||
vector_push_back_if_not_found(_cmd_resources, &image);
|
||||
}
|
||||
|
||||
void CmdBuffer::transitionImageLayout(Image& image, VkImageLayout new_layout) noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
if(!isRecording())
|
||||
{
|
||||
core::error::report(e_kind::warning, "Vulkan : trying to do an image layout transition in a non recording command buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
VkImageMemoryBarrier barrier{};
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier.oldLayout = image.getLayout();
|
||||
barrier.newLayout = new_layout;
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.image = image.get();
|
||||
barrier.subresourceRange.aspectMask = isDepthFormat(image.getFormat()) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
barrier.subresourceRange.baseMipLevel = 0;
|
||||
barrier.subresourceRange.levelCount = 1;
|
||||
barrier.subresourceRange.baseArrayLayer = 0;
|
||||
barrier.subresourceRange.layerCount = 1;
|
||||
barrier.srcAccessMask = layoutToAccessMask(image.getLayout(), false);
|
||||
barrier.dstAccessMask = layoutToAccessMask(new_layout, true);
|
||||
if(isStencilFormat(image.getFormat()))
|
||||
barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
|
||||
VkPipelineStageFlags sourceStage = 0;
|
||||
if(barrier.oldLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
|
||||
sourceStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
else if(barrier.srcAccessMask != 0)
|
||||
sourceStage = RCore::accessFlagsToPipelineStage(barrier.srcAccessMask, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
else
|
||||
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
|
||||
VkPipelineStageFlags destinationStage = 0;
|
||||
if(barrier.newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
|
||||
destinationStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
else if(barrier.dstAccessMask != 0)
|
||||
destinationStage = RCore::accessFlagsToPipelineStage(barrier.dstAccessMask, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
else
|
||||
destinationStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
|
||||
vkCmdPipelineBarrier(_cmd_buffer, sourceStage, destinationStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
|
||||
image.recordedInCmdBuffer();
|
||||
vector_push_back_if_not_found(_cmd_resources, &image);
|
||||
}
|
||||
|
||||
void CmdBuffer::endRecord()
|
||||
{
|
||||
if(!_is_recording)
|
||||
MLX_PROFILE_FUNCTION();
|
||||
if(!isInit())
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : ending record on un uninit command buffer");
|
||||
if(_state != state::recording)
|
||||
return;
|
||||
if(vkEndCommandBuffer(_cmd_buffer) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to end recording command buffer");
|
||||
|
||||
_is_recording = false;
|
||||
_state = state::idle;
|
||||
}
|
||||
|
||||
void CmdBuffer::submitIdle() noexcept
|
||||
void CmdBuffer::submitIdle(bool shouldWaitForExecution) noexcept
|
||||
{
|
||||
auto device = Render_Core::get().getDevice().get();
|
||||
MLX_PROFILE_FUNCTION();
|
||||
if(_type != kind::single_time)
|
||||
{
|
||||
core::error::report(e_kind::error, "Vulkan : try to perform an idle submit on a command buffer that is not single-time, this is not allowed");
|
||||
return;
|
||||
}
|
||||
|
||||
VkSubmitInfo submitInfo = {};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = &_cmd_buffer;
|
||||
|
||||
VkFenceCreateInfo fenceCreateInfo = {};
|
||||
fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
|
||||
VkFence fence;
|
||||
vkCreateFence(device, &fenceCreateInfo, nullptr, &fence);
|
||||
vkResetFences(device, 1, &fence);
|
||||
vkQueueSubmit(Render_Core::get().getQueue().getGraphic(), 1, &submitInfo, fence);
|
||||
vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX);
|
||||
vkDestroyFence(device, fence, nullptr);
|
||||
}
|
||||
|
||||
void CmdBuffer::submit(Semaphore& semaphores) noexcept
|
||||
{
|
||||
VkSemaphore signalSemaphores[] = { semaphores.getRenderImageSemaphore() };
|
||||
VkSemaphore waitSemaphores[] = { semaphores.getImageSemaphore() };
|
||||
VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
|
||||
_fence.reset();
|
||||
|
||||
VkSubmitInfo submitInfo{};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.waitSemaphoreCount = 1;
|
||||
submitInfo.pWaitSemaphores = waitSemaphores;
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = &_cmd_buffer;
|
||||
|
||||
VkResult res = vkQueueSubmit(Render_Core::get().getQueue().getGraphic(), 1, &submitInfo, _fence.get());
|
||||
if(res != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan error : failed to submit a single time command buffer, %s", RCore::verbaliseResultVk(res));
|
||||
_state = state::submitted;
|
||||
|
||||
if(shouldWaitForExecution)
|
||||
waitForExecution();
|
||||
}
|
||||
|
||||
void CmdBuffer::submit(Semaphore* semaphores) noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
std::array<VkSemaphore, 1> signalSemaphores;
|
||||
std::array<VkSemaphore, 1> waitSemaphores;
|
||||
|
||||
if(semaphores != nullptr)
|
||||
{
|
||||
signalSemaphores[0] = semaphores->getRenderImageSemaphore();
|
||||
waitSemaphores[0] = semaphores->getImageSemaphore();
|
||||
}
|
||||
else
|
||||
{
|
||||
signalSemaphores[0] = VK_NULL_HANDLE;
|
||||
waitSemaphores[0] = VK_NULL_HANDLE;
|
||||
}
|
||||
VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
|
||||
|
||||
_fence.reset();
|
||||
|
||||
VkSubmitInfo submitInfo{};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.waitSemaphoreCount = (semaphores == nullptr ? 0 : waitSemaphores.size());
|
||||
submitInfo.pWaitSemaphores = waitSemaphores.data();
|
||||
submitInfo.pWaitDstStageMask = waitStages;
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = &_cmd_buffer;
|
||||
submitInfo.signalSemaphoreCount = 1;
|
||||
submitInfo.pSignalSemaphores = signalSemaphores;
|
||||
submitInfo.signalSemaphoreCount = (semaphores == nullptr ? 0 : signalSemaphores.size());
|
||||
submitInfo.pSignalSemaphores = signalSemaphores.data();
|
||||
|
||||
if(vkQueueSubmit(Render_Core::get().getQueue().getGraphic(), 1, &submitInfo, _fence.get()) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan error : failed to submit draw command buffer");
|
||||
VkResult res = vkQueueSubmit(Render_Core::get().getQueue().getGraphic(), 1, &submitInfo, _fence.get());
|
||||
if(res != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan error : failed to submit draw command buffer, %s", RCore::verbaliseResultVk(res));
|
||||
_state = state::submitted;
|
||||
}
|
||||
|
||||
void CmdBuffer::updateSubmitState() noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
if(!_fence.isReady())
|
||||
return;
|
||||
|
||||
for(CmdResource* res : _cmd_resources)
|
||||
res->removedFromCmdBuffer();
|
||||
_cmd_resources.clear();
|
||||
_state = state::ready;
|
||||
}
|
||||
|
||||
void CmdBuffer::preTransferBarrier() noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
VkMemoryBarrier memoryBarrier{};
|
||||
memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
|
||||
memoryBarrier.pNext = nullptr;
|
||||
memoryBarrier.srcAccessMask = 0U;
|
||||
memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
|
||||
vkCmdPipelineBarrier(_cmd_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, &memoryBarrier, 0, nullptr, 0, nullptr);
|
||||
}
|
||||
|
||||
void CmdBuffer::postTransferBarrier() noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
VkMemoryBarrier memoryBarrier{};
|
||||
memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
|
||||
memoryBarrier.pNext = nullptr;
|
||||
memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_UNIFORM_READ_BIT;
|
||||
|
||||
vkCmdPipelineBarrier(_cmd_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, 0, 1, &memoryBarrier, 0, nullptr, 0, nullptr);
|
||||
}
|
||||
|
||||
void CmdBuffer::destroy() noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
_fence.destroy();
|
||||
_cmd_buffer = VK_NULL_HANDLE;
|
||||
_state = state::uninit;
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : destroyed command buffer");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,47 +3,86 @@
|
||||
/* ::: :::::::: */
|
||||
/* vk_cmd_buffer.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* By: bonsthie <bonsthie@42angouleme.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/06 18:25:42 by maldavid #+# #+# */
|
||||
/* Updated: 2023/04/21 13:20:49 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/08/08 17:46:00 by bonsthie ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __MLX_VK_CMD_BUFFER__
|
||||
#define __MLX_VK_CMD_BUFFER__
|
||||
|
||||
#include <mlx_profile.h>
|
||||
#include <volk.h>
|
||||
#include <renderer/core/vk_fence.h>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
class Buffer;
|
||||
class Image;
|
||||
|
||||
class CmdBuffer
|
||||
{
|
||||
public:
|
||||
void init(class CmdManager* manager);
|
||||
void init(class CmdPool* pool);
|
||||
enum class state
|
||||
{
|
||||
uninit = 0, // buffer not initialized or destroyed
|
||||
ready, // buffer ready to be used after having been submitted
|
||||
idle, // buffer has recorded informations but has not been submitted
|
||||
recording, // buffer is currently recording
|
||||
submitted, // buffer has been submitted
|
||||
};
|
||||
|
||||
enum class kind
|
||||
{
|
||||
single_time = 0,
|
||||
long_time
|
||||
};
|
||||
|
||||
public:
|
||||
void init(kind type, class CmdManager* manager);
|
||||
void init(kind type, class CmdPool* pool);
|
||||
void destroy() noexcept;
|
||||
|
||||
void beginRecord(VkCommandBufferUsageFlags usage = 0);
|
||||
void submit(class Semaphore& semaphores) noexcept;
|
||||
void submitIdle() noexcept;
|
||||
inline void waitForExecution() noexcept { _fence.waitAndReset(); }
|
||||
void submit(class Semaphore* semaphores) noexcept;
|
||||
void submitIdle(bool shouldWaitForExecution = true) noexcept; // TODO : handle `shouldWaitForExecution` as false by default (needs to modify CmdResources lifetimes to do so)
|
||||
void updateSubmitState() noexcept;
|
||||
inline void waitForExecution() noexcept { _fence.wait(); updateSubmitState(); _state = state::ready; }
|
||||
inline void reset() noexcept { vkResetCommandBuffer(_cmd_buffer, 0); }
|
||||
void endRecord();
|
||||
|
||||
inline bool isRecording() const noexcept { return _is_recording; }
|
||||
inline bool isInit() const noexcept { return _cmd_buffer != VK_NULL_HANDLE; }
|
||||
void bindVertexBuffer(Buffer& buffer) noexcept;
|
||||
void bindIndexBuffer(Buffer& buffer) noexcept;
|
||||
void copyBuffer(Buffer& dst, Buffer& src) noexcept;
|
||||
void copyBufferToImage(Buffer& buffer, Image& image) noexcept;
|
||||
void copyImagetoBuffer(Image& image, Buffer& buffer) noexcept;
|
||||
void transitionImageLayout(Image& image, VkImageLayout new_layout) noexcept;
|
||||
|
||||
inline bool isInit() const noexcept { return _state != state::uninit; }
|
||||
inline bool isReadyToBeUsed() const noexcept { return _state == state::ready; }
|
||||
inline bool isRecording() const noexcept { return _state == state::recording; }
|
||||
inline bool hasBeenSubmitted() const noexcept { return _state == state::submitted; }
|
||||
inline state getCurrentState() const noexcept { return _state; }
|
||||
|
||||
inline VkCommandBuffer& operator()() noexcept { return _cmd_buffer; }
|
||||
inline VkCommandBuffer& get() noexcept { return _cmd_buffer; }
|
||||
inline Fence& getFence() noexcept { return _fence; }
|
||||
|
||||
private:
|
||||
void preTransferBarrier() noexcept;
|
||||
void postTransferBarrier() noexcept;
|
||||
|
||||
private:
|
||||
std::vector<class CmdResource*> _cmd_resources;
|
||||
Fence _fence;
|
||||
VkCommandBuffer _cmd_buffer = VK_NULL_HANDLE;
|
||||
class CmdPool* _pool = nullptr;
|
||||
bool _is_recording = false;
|
||||
state _state = state::uninit;
|
||||
kind _type;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/06 18:24:33 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/18 17:23:38 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/03/14 17:23:20 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -20,10 +20,11 @@ namespace mlx
|
||||
VkCommandPoolCreateInfo poolInfo{};
|
||||
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||
poolInfo.queueFamilyIndex = Render_Core::get().getQueue().getFamilies().graphicsFamily.value();
|
||||
poolInfo.queueFamilyIndex = Render_Core::get().getQueue().getFamilies().graphics_family.value();
|
||||
|
||||
if(vkCreateCommandPool(Render_Core::get().getDevice().get(), &poolInfo, nullptr, &_cmd_pool) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create command pool");
|
||||
VkResult res = vkCreateCommandPool(Render_Core::get().getDevice().get(), &poolInfo, nullptr, &_cmd_pool);
|
||||
if(res != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create command pool, %s", RCore::verbaliseResultVk(res));
|
||||
}
|
||||
|
||||
void CmdPool::destroy() noexcept
|
||||
|
||||
@@ -6,13 +6,14 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/06 18:24:12 by maldavid #+# #+# */
|
||||
/* Updated: 2022/12/18 01:08:31 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/01/03 15:27:26 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __MLX_VK_CMD_POOL__
|
||||
#define __MLX_VK_CMD_POOL__
|
||||
|
||||
#include <mlx_profile.h>
|
||||
#include <volk.h>
|
||||
|
||||
namespace mlx
|
||||
|
||||
44
src/renderer/core/cmd_resource.h
git.filemode.normal_file
@@ -0,0 +1,44 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* cmd_resource.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/12/16 20:44:29 by maldavid #+# #+# */
|
||||
/* Updated: 2024/03/14 17:28:08 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __MLX_COMMAND_RESOURCE__
|
||||
#define __MLX_COMMAND_RESOURCE__
|
||||
|
||||
#include <function.h>
|
||||
#include <core/UUID.h>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
class CmdResource
|
||||
{
|
||||
friend class SingleTimeCmdManager;
|
||||
public:
|
||||
enum class state
|
||||
{
|
||||
in_cmd_buffer = 0,
|
||||
out_cmd_buffer,
|
||||
};
|
||||
|
||||
public:
|
||||
CmdResource() : _uuid() {}
|
||||
inline void recordedInCmdBuffer() noexcept { _state = state::in_cmd_buffer; }
|
||||
inline void removedFromCmdBuffer() noexcept { _state = state::out_cmd_buffer; }
|
||||
inline UUID getUUID() const noexcept { return _uuid; }
|
||||
virtual ~CmdResource() = default;
|
||||
|
||||
private:
|
||||
UUID _uuid;
|
||||
state _state = state::out_cmd_buffer;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
32
src/renderer/core/drawable_resource.h
git.filemode.normal_file
@@ -0,0 +1,32 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* drawable_resource.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/01/10 21:00:37 by maldavid #+# #+# */
|
||||
/* Updated: 2024/01/11 01:21:15 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __MLX_DRAWABLE_RESOURCE__
|
||||
#define __MLX_DRAWABLE_RESOURCE__
|
||||
|
||||
#include <mlx_profile.h>
|
||||
#include <volk.h>
|
||||
#include <array>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
class DrawableResource
|
||||
{
|
||||
public:
|
||||
DrawableResource() = default;
|
||||
virtual void render(std::array<VkDescriptorSet, 2>& sets, class Renderer& renderer) = 0;
|
||||
virtual void resetUpdate() {}
|
||||
virtual ~DrawableResource() = default;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -6,25 +6,36 @@
|
||||
/* By: kbz_8 <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/10/20 22:02:37 by kbz_8 #+# #+# */
|
||||
/* Updated: 2023/11/14 12:45:29 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/09/14 00:04:16 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <core/profile.h>
|
||||
#include <mlx_profile.h>
|
||||
#include <core/errors.h>
|
||||
#include <cstdio>
|
||||
#include <core/profiler.h>
|
||||
|
||||
#define VMA_STATIC_VULKAN_FUNCTIONS 0
|
||||
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 0
|
||||
#define VMA_VULKAN_VERSION 1002000
|
||||
#define VMA_ASSERT(expr) (static_cast<bool>(expr) ? void(0) : mlx::core::error::report(e_kind::fatal_error, "Graphics allocator : an assertion has been catched : '%s'", #expr))
|
||||
#define VMA_ASSERT(expr) ((void)0)
|
||||
#define VMA_IMPLEMENTATION
|
||||
|
||||
#ifdef MLX_COMPILER_CLANG
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wnullability-completeness"
|
||||
#pragma clang diagnostic ignored "-Weverything"
|
||||
#include <renderer/core/memory.h>
|
||||
#pragma clang diagnostic pop
|
||||
#elif defined(MLX_COMPILER_GCC)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
||||
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
#pragma GCC diagnostic ignored "-Wparentheses"
|
||||
#pragma GCC diagnostic ignored "-Wparentheses"
|
||||
#include <renderer/core/memory.h>
|
||||
#pragma GCC diagnostic pop
|
||||
#else
|
||||
#include <renderer/core/memory.h>
|
||||
#endif
|
||||
@@ -67,71 +78,91 @@ namespace mlx
|
||||
allocatorCreateInfo.instance = Render_Core::get().getInstance().get();
|
||||
allocatorCreateInfo.pVulkanFunctions = &vma_vulkan_func;
|
||||
|
||||
if(vmaCreateAllocator(&allocatorCreateInfo, &_allocator) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create graphics memory allocator");
|
||||
VkResult res = vmaCreateAllocator(&allocatorCreateInfo, &_allocator);
|
||||
if(res != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Graphics allocator : failed to create graphics memory allocator, %s", RCore::verbaliseResultVk(res));
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : created new allocator");
|
||||
core::error::report(e_kind::message, "Graphics allocator : created new allocator");
|
||||
#endif
|
||||
}
|
||||
|
||||
VmaAllocation GPUallocator::createBuffer(const VkBufferCreateInfo* binfo, const VmaAllocationCreateInfo* vinfo, VkBuffer& buffer, const char* name) noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
VmaAllocation allocation;
|
||||
if(vmaCreateBuffer(_allocator, binfo, vinfo, &buffer, &allocation, nullptr) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to allocate a buffer");
|
||||
VkResult res = vmaCreateBuffer(_allocator, binfo, vinfo, &buffer, &allocation, nullptr);
|
||||
if(res != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Graphics allocator : failed to allocate a buffer, %s", RCore::verbaliseResultVk(res));
|
||||
if(name != nullptr)
|
||||
{
|
||||
Render_Core::get().getLayers().setDebugUtilsObjectNameEXT(VK_OBJECT_TYPE_BUFFER, (std::uint64_t)buffer, name);
|
||||
vmaSetAllocationName(_allocator, allocation, name);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Graphics Allocator : created new buffer");
|
||||
core::error::report(e_kind::message, "Graphics Allocator : created new buffer '%s'", name);
|
||||
#endif
|
||||
_active_buffers_allocations++;
|
||||
return allocation;
|
||||
}
|
||||
|
||||
void GPUallocator::destroyBuffer(VmaAllocation allocation, VkBuffer buffer) noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
vkDeviceWaitIdle(Render_Core::get().getDevice().get());
|
||||
vmaDestroyBuffer(_allocator, buffer, allocation);
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Graphics Allocator : destroyed buffer");
|
||||
#endif
|
||||
_active_buffers_allocations--;
|
||||
}
|
||||
|
||||
VmaAllocation GPUallocator::createImage(const VkImageCreateInfo* iminfo, const VmaAllocationCreateInfo* vinfo, VkImage& image, const char* name) noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
VmaAllocation allocation;
|
||||
if(vmaCreateImage(_allocator, iminfo, vinfo, &image, &allocation, nullptr) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to allocate an image");
|
||||
VkResult res = vmaCreateImage(_allocator, iminfo, vinfo, &image, &allocation, nullptr);
|
||||
if(res != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Graphics allocator : failed to allocate an image, %s", RCore::verbaliseResultVk(res));
|
||||
if(name != nullptr)
|
||||
{
|
||||
Render_Core::get().getLayers().setDebugUtilsObjectNameEXT(VK_OBJECT_TYPE_IMAGE, (std::uint64_t)image, name);
|
||||
vmaSetAllocationName(_allocator, allocation, name);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Graphics Allocator : created new image");
|
||||
core::error::report(e_kind::message, "Graphics Allocator : created new image '%s'", name);
|
||||
#endif
|
||||
_active_images_allocations++;
|
||||
return allocation;
|
||||
}
|
||||
|
||||
void GPUallocator::destroyImage(VmaAllocation allocation, VkImage image) noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
vkDeviceWaitIdle(Render_Core::get().getDevice().get());
|
||||
vmaDestroyImage(_allocator, image, allocation);
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Graphics Allocator : destroyed image");
|
||||
#endif
|
||||
_active_images_allocations--;
|
||||
}
|
||||
|
||||
void GPUallocator::mapMemory(VmaAllocation allocation, void** data) noexcept
|
||||
{
|
||||
if(vmaMapMemory(_allocator, allocation, data) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Graphics allocator : unable to map GPU memory to CPU memory");
|
||||
MLX_PROFILE_FUNCTION();
|
||||
VkResult res = vmaMapMemory(_allocator, allocation, data);
|
||||
if(res != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Graphics allocator : unable to map GPU memory to CPU memory, %s", RCore::verbaliseResultVk(res));
|
||||
}
|
||||
|
||||
void GPUallocator::unmapMemory(VmaAllocation allocation) noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
vmaUnmapMemory(_allocator, allocation);
|
||||
}
|
||||
|
||||
void GPUallocator::dumpMemoryToJson()
|
||||
{
|
||||
static uint32_t id = 0;
|
||||
static std::uint32_t id = 0;
|
||||
std::string name("memory_dump");
|
||||
name.append(std::to_string(id) + ".json");
|
||||
std::ofstream file(name);
|
||||
@@ -147,14 +178,26 @@ namespace mlx
|
||||
file.close();
|
||||
id++;
|
||||
}
|
||||
|
||||
|
||||
void GPUallocator::flush(VmaAllocation allocation, VkDeviceSize size, VkDeviceSize offset) noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
vmaFlushAllocation(_allocator, allocation, offset, size);
|
||||
}
|
||||
|
||||
void GPUallocator::destroy() noexcept
|
||||
{
|
||||
if(_active_images_allocations != 0)
|
||||
core::error::report(e_kind::error, "Graphics allocator : some user-dependant allocations were not freed before destroying the display (%d active allocations). You may have not destroyed all the MLX resources you've created", _active_images_allocations);
|
||||
else if(_active_buffers_allocations != 0)
|
||||
core::error::report(e_kind::error, "Graphics allocator : some MLX-dependant allocations were not freed before destroying the display (%d active allocations). This is an error in the MLX, please report this should not happen", _active_buffers_allocations);
|
||||
if(_active_images_allocations < 0 || _active_buffers_allocations < 0)
|
||||
core::error::report(e_kind::warning, "Graphics allocator : the impossible happened, the MLX has freed more allocations than it has made (wtf)");
|
||||
vmaDestroyAllocator(_allocator);
|
||||
_active_buffers_allocations = 0;
|
||||
_active_images_allocations = 0;
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : destroyed a graphics allocator");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,14 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/10/20 02:13:03 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/14 09:46:32 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/03/25 16:01:06 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __MLX_VK_MEMORY__
|
||||
#define __MLX_VK_MEMORY__
|
||||
|
||||
#include <mlx_profile.h>
|
||||
#include <volk.h>
|
||||
#include <vma.h>
|
||||
|
||||
@@ -43,6 +44,8 @@ namespace mlx
|
||||
|
||||
private:
|
||||
VmaAllocator _allocator;
|
||||
std::int32_t _active_buffers_allocations = 0;
|
||||
std::int32_t _active_images_allocations = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -6,37 +6,34 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/12/17 23:33:34 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/20 12:04:51 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/10/19 10:50:13 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#define VOLK_IMPLEMENTATION
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define VK_USE_PLATFORM_WIN32_KHR
|
||||
#elif defined(__APPLE__) || defined(__MACH__)
|
||||
#define VK_USE_PLATFORM_MACOS_MVK
|
||||
#else
|
||||
#define VK_USE_PLATFORM_XLIB_KHR
|
||||
#endif
|
||||
|
||||
#include "render_core.h"
|
||||
#include <mutex>
|
||||
#include <mlx_profile.h>
|
||||
#include <renderer/core/render_core.h>
|
||||
#include <renderer/command/vk_cmd_buffer.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#warning "MLX is being compiled in debug mode, this activates Vulkan's validation layers and debug messages which may impact rendering performances"
|
||||
#ifdef MLX_COMPILER_MSVC
|
||||
#pragma NOTE("MLX is being compiled in debug mode, this activates Vulkan's validation layers and debug messages which may impact rendering performances")
|
||||
#else
|
||||
#warning "MLX is being compiled in debug mode, this activates Vulkan's validation layers and debug messages which may impact rendering performances"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
namespace RCore
|
||||
{
|
||||
std::optional<uint32_t> findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties, bool error)
|
||||
std::optional<std::uint32_t> findMemoryType(std::uint32_t typeFilter, VkMemoryPropertyFlags properties, bool error)
|
||||
{
|
||||
VkPhysicalDeviceMemoryProperties memProperties;
|
||||
vkGetPhysicalDeviceMemoryProperties(Render_Core::get().getDevice().getPhysicalDevice(), &memProperties);
|
||||
|
||||
for(uint32_t i = 0; i < memProperties.memoryTypeCount; i++)
|
||||
for(std::uint32_t i = 0; i < memProperties.memoryTypeCount; i++)
|
||||
{
|
||||
if((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties)
|
||||
return i;
|
||||
@@ -45,11 +42,84 @@ namespace mlx
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to find suitable memory type");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const char* verbaliseResultVk(VkResult result)
|
||||
{
|
||||
switch(result)
|
||||
{
|
||||
case VK_SUCCESS: return "Success";
|
||||
case VK_NOT_READY: return "A fence or query has not yet completed";
|
||||
case VK_TIMEOUT: return "A wait operation has not completed in the specified time";
|
||||
case VK_EVENT_SET: return "An event is signaled";
|
||||
case VK_EVENT_RESET: return "An event is unsignaled";
|
||||
case VK_INCOMPLETE: return "A return array was too small for the result";
|
||||
case VK_ERROR_OUT_OF_HOST_MEMORY: return "A host memory allocation has failed";
|
||||
case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "A device memory allocation has failed";
|
||||
case VK_ERROR_INITIALIZATION_FAILED: return "Initialization of an object could not be completed for implementation-specific reasons";
|
||||
case VK_ERROR_DEVICE_LOST: return "The logical or physical device has been lost";
|
||||
case VK_ERROR_MEMORY_MAP_FAILED: return "Mapping of a memory object has failed";
|
||||
case VK_ERROR_LAYER_NOT_PRESENT: return "A requested layer is not present or could not be loaded";
|
||||
case VK_ERROR_EXTENSION_NOT_PRESENT: return "A requested extension is not supported";
|
||||
case VK_ERROR_FEATURE_NOT_PRESENT: return "A requested feature is not supported";
|
||||
case VK_ERROR_INCOMPATIBLE_DRIVER: return "The requested version of Vulkan is not supported by the driver or is otherwise incompatible";
|
||||
case VK_ERROR_TOO_MANY_OBJECTS: return "Too many objects of the type have already been created";
|
||||
case VK_ERROR_FORMAT_NOT_SUPPORTED: return "A requested format is not supported on this device";
|
||||
case VK_ERROR_SURFACE_LOST_KHR: return "A surface is no longer available";
|
||||
case VK_SUBOPTIMAL_KHR: return "A swapchain no longer matches the surface properties exactly, but can still be used";
|
||||
case VK_ERROR_OUT_OF_DATE_KHR: return "A surface has changed in such a way that it is no longer compatible with the swapchain";
|
||||
case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "The display used by a swapchain does not use the same presentable image layout";
|
||||
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "The requested window is already connected to a VkSurfaceKHR, or to some other non-Vulkan API";
|
||||
case VK_ERROR_VALIDATION_FAILED_EXT: return "A validation layer found an error";
|
||||
|
||||
default: return "Unknown Vulkan error";
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VkPipelineStageFlags accessFlagsToPipelineStage(VkAccessFlags accessFlags, VkPipelineStageFlags stageFlags)
|
||||
{
|
||||
VkPipelineStageFlags stages = 0;
|
||||
|
||||
while(accessFlags != 0)
|
||||
{
|
||||
VkAccessFlagBits AccessFlag = static_cast<VkAccessFlagBits>(accessFlags & (~(accessFlags - 1)));
|
||||
if(AccessFlag == 0 || (AccessFlag & (AccessFlag - 1)) != 0)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : an error has been caught during access flag to pipeline stage operation");
|
||||
accessFlags &= ~AccessFlag;
|
||||
|
||||
switch(AccessFlag)
|
||||
{
|
||||
case VK_ACCESS_INDIRECT_COMMAND_READ_BIT: stages |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; break;
|
||||
case VK_ACCESS_INDEX_READ_BIT: stages |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; break;
|
||||
case VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT: stages |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; break;
|
||||
case VK_ACCESS_UNIFORM_READ_BIT: stages |= stageFlags | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; break;
|
||||
case VK_ACCESS_INPUT_ATTACHMENT_READ_BIT: stages |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; break;
|
||||
case VK_ACCESS_SHADER_READ_BIT: stages |= stageFlags | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; break;
|
||||
case VK_ACCESS_SHADER_WRITE_BIT: stages |= stageFlags | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; break;
|
||||
case VK_ACCESS_COLOR_ATTACHMENT_READ_BIT: stages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; break;
|
||||
case VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT: stages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; break;
|
||||
case VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT: stages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; break;
|
||||
case VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT: stages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; break;
|
||||
case VK_ACCESS_TRANSFER_READ_BIT: stages |= VK_PIPELINE_STAGE_TRANSFER_BIT; break;
|
||||
case VK_ACCESS_TRANSFER_WRITE_BIT: stages |= VK_PIPELINE_STAGE_TRANSFER_BIT; break;
|
||||
case VK_ACCESS_HOST_READ_BIT: stages |= VK_PIPELINE_STAGE_HOST_BIT; break;
|
||||
case VK_ACCESS_HOST_WRITE_BIT: stages |= VK_PIPELINE_STAGE_HOST_BIT; break;
|
||||
case VK_ACCESS_MEMORY_READ_BIT: break;
|
||||
case VK_ACCESS_MEMORY_WRITE_BIT: break;
|
||||
|
||||
default: core::error::report(e_kind::error, "Vulkan : unknown access flag"); break;
|
||||
}
|
||||
}
|
||||
return stages;
|
||||
}
|
||||
}
|
||||
|
||||
void Render_Core::init()
|
||||
{
|
||||
volkInitialize();
|
||||
if(_is_init)
|
||||
return;
|
||||
if(volkInitialize() != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan loader : cannot load %s, are you sure Vulkan is installed on your system ?", VULKAN_LIB_NAME);
|
||||
|
||||
_instance.init();
|
||||
volkLoadInstance(_instance.get());
|
||||
@@ -58,6 +128,7 @@ namespace mlx
|
||||
volkLoadDevice(_device.get());
|
||||
_queues.init();
|
||||
_allocator.init();
|
||||
_cmd_manager.init();
|
||||
_is_init = true;
|
||||
}
|
||||
|
||||
@@ -68,11 +139,15 @@ namespace mlx
|
||||
|
||||
vkDeviceWaitIdle(_device());
|
||||
|
||||
_pool_manager.destroyAllPools();
|
||||
_cmd_manager.destroy();
|
||||
_allocator.destroy();
|
||||
_device.destroy();
|
||||
_layers.destroy();
|
||||
_instance.destroy();
|
||||
|
||||
volkFinalize();
|
||||
|
||||
_is_init = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,16 +6,20 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/08 19:16:32 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/20 07:20:43 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/01/20 08:17:58 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __MLX_RENDER_CORE__
|
||||
#define __MLX_RENDER_CORE__
|
||||
|
||||
#include <mlx_profile.h>
|
||||
#include <volk.h>
|
||||
#include <optional>
|
||||
|
||||
#include <renderer/command/single_time_cmd_manager.h>
|
||||
#include <renderer/descriptors/descriptor_pool_manager.h>
|
||||
#include <renderer/descriptors/vk_descriptor_pool.h>
|
||||
#include "vk_queues.h"
|
||||
#include "vk_device.h"
|
||||
#include "vk_instance.h"
|
||||
@@ -29,7 +33,9 @@ namespace mlx
|
||||
{
|
||||
namespace RCore
|
||||
{
|
||||
std::optional<uint32_t> findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties, bool error = true);
|
||||
std::optional<std::uint32_t> findMemoryType(std::uint32_t typeFilter, VkMemoryPropertyFlags properties, bool error = true);
|
||||
const char* verbaliseResultVk(VkResult result);
|
||||
VkPipelineStageFlags accessFlagsToPipelineStage(VkAccessFlags accessFlags, VkPipelineStageFlags stageFlags);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
@@ -41,26 +47,36 @@ namespace mlx
|
||||
const std::vector<const char*> validationLayers = { "VK_LAYER_KHRONOS_validation" };
|
||||
|
||||
constexpr const int MAX_FRAMES_IN_FLIGHT = 3;
|
||||
constexpr const int MAX_SETS_PER_POOL = 512;
|
||||
constexpr const int NUMBER_OF_UNIFORM_BUFFERS = 1; // change this if for wathever reason more than one uniform buffer is needed
|
||||
|
||||
class Render_Core : public Singleton<Render_Core>
|
||||
{
|
||||
public:
|
||||
Render_Core() = default;
|
||||
friend class Singleton<Render_Core>;
|
||||
|
||||
public:
|
||||
void init();
|
||||
void destroy();
|
||||
|
||||
inline bool isInit() const noexcept { return _is_init; }
|
||||
inline Instance& getInstance() noexcept { return _instance; }
|
||||
inline Device& getDevice() noexcept { return _device; }
|
||||
inline Queues& getQueue() noexcept { return _queues; }
|
||||
inline GPUallocator& getAllocator() noexcept { return _allocator; }
|
||||
inline ValidationLayers& getLayers() noexcept { return _layers; }
|
||||
inline CmdBuffer& getSingleTimeCmdBuffer() noexcept { return _cmd_manager.getCmdBuffer(); }
|
||||
inline SingleTimeCmdManager& getSingleTimeCmdManager() noexcept { return _cmd_manager; }
|
||||
inline DescriptorPool& getDescriptorPool() { return _pool_manager.getAvailablePool(); }
|
||||
|
||||
private:
|
||||
Render_Core() = default;
|
||||
~Render_Core() = default;
|
||||
|
||||
private:
|
||||
ValidationLayers _layers;
|
||||
SingleTimeCmdManager _cmd_manager;
|
||||
Queues _queues;
|
||||
DescriptorPoolManager _pool_manager;
|
||||
Device _device;
|
||||
Instance _instance;
|
||||
GPUallocator _allocator;
|
||||
|
||||
@@ -6,17 +6,17 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/08 19:14:29 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/18 17:22:02 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/03/14 17:23:45 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "render_core.h"
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_vulkan.h>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
@@ -29,10 +29,10 @@ namespace mlx
|
||||
Queues::QueueFamilyIndices indices = Render_Core::get().getQueue().getFamilies();
|
||||
|
||||
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
|
||||
std::set<uint32_t> uniqueQueueFamilies = { indices.graphicsFamily.value(), indices.presentFamily.value() };
|
||||
std::set<std::uint32_t> uniqueQueueFamilies = { indices.graphics_family.value(), indices.present_family.value() };
|
||||
|
||||
float queuePriority = 1.0f;
|
||||
for(uint32_t queueFamily : uniqueQueueFamilies)
|
||||
for(std::uint32_t queueFamily : uniqueQueueFamilies)
|
||||
{
|
||||
VkDeviceQueueCreateInfo queueCreateInfo{};
|
||||
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
@@ -47,17 +47,18 @@ namespace mlx
|
||||
VkDeviceCreateInfo createInfo{};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
|
||||
createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
|
||||
createInfo.queueCreateInfoCount = static_cast<std::uint32_t>(queueCreateInfos.size());
|
||||
createInfo.pQueueCreateInfos = queueCreateInfos.data();
|
||||
|
||||
createInfo.pEnabledFeatures = &deviceFeatures;
|
||||
|
||||
createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
|
||||
createInfo.enabledExtensionCount = static_cast<std::uint32_t>(deviceExtensions.size());
|
||||
createInfo.ppEnabledExtensionNames = deviceExtensions.data();
|
||||
createInfo.enabledLayerCount = 0;
|
||||
|
||||
if(vkCreateDevice(_physicalDevice, &createInfo, nullptr, &_device) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create logcal device");
|
||||
VkResult res;
|
||||
if((res = vkCreateDevice(_physical_device, &createInfo, nullptr, &_device)) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create logcal device, %s", RCore::verbaliseResultVk(res));
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : created new logical device");
|
||||
#endif
|
||||
@@ -65,7 +66,7 @@ namespace mlx
|
||||
|
||||
void Device::pickPhysicalDevice()
|
||||
{
|
||||
uint32_t deviceCount = 0;
|
||||
std::uint32_t deviceCount = 0;
|
||||
vkEnumeratePhysicalDevices(Render_Core::get().getInstance().get(), &deviceCount, nullptr);
|
||||
|
||||
if(deviceCount == 0)
|
||||
@@ -82,30 +83,27 @@ namespace mlx
|
||||
if(SDL_Vulkan_CreateSurface(window, Render_Core::get().getInstance().get(), &surface) != SDL_TRUE)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create a surface to pick physical device");
|
||||
|
||||
std::vector<std::pair<int, VkPhysicalDevice>> devices_score;
|
||||
std::multimap<int, VkPhysicalDevice> devices_score;
|
||||
|
||||
for(const auto& device : devices)
|
||||
devices_score.emplace_back(deviceScore(device, surface), device);
|
||||
|
||||
vkDestroySurfaceKHR(Render_Core::get().getInstance().get(), surface, nullptr);
|
||||
SDL_DestroyWindow(window);
|
||||
|
||||
using device_pair = std::pair<int, VkPhysicalDevice>;
|
||||
std::sort(devices_score.begin(), devices_score.end(), [](const device_pair& a, const device_pair& b)
|
||||
{
|
||||
return a.first > b.first;
|
||||
});
|
||||
int score = deviceScore(device, surface);
|
||||
devices_score.insert(std::make_pair(score, device));
|
||||
}
|
||||
|
||||
if(devices_score.front().first > 0)
|
||||
_physicalDevice = devices_score.front().second;
|
||||
|
||||
if(_physicalDevice == VK_NULL_HANDLE)
|
||||
if(devices_score.rbegin()->first > 0)
|
||||
_physical_device = devices_score.rbegin()->second;
|
||||
else
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to find a suitable GPU");
|
||||
|
||||
#ifdef DEBUG
|
||||
VkPhysicalDeviceProperties props;
|
||||
vkGetPhysicalDeviceProperties(_physicalDevice, &props);
|
||||
vkGetPhysicalDeviceProperties(_physical_device, &props);
|
||||
core::error::report(e_kind::message, "Vulkan : picked a physical device, %s", props.deviceName);
|
||||
#endif
|
||||
Render_Core::get().getQueue().findQueueFamilies(_physical_device, surface); // update queue indicies to current physical device
|
||||
vkDestroySurfaceKHR(Render_Core::get().getInstance().get(), surface, nullptr);
|
||||
SDL_DestroyWindow(window);
|
||||
}
|
||||
|
||||
int Device::deviceScore(VkPhysicalDevice device, VkSurfaceKHR surface)
|
||||
@@ -113,7 +111,7 @@ namespace mlx
|
||||
Queues::QueueFamilyIndices indices = Render_Core::get().getQueue().findQueueFamilies(device, surface);
|
||||
bool extensionsSupported = checkDeviceExtensionSupport(device);
|
||||
|
||||
uint32_t formatCount = 0;
|
||||
std::uint32_t formatCount = 0;
|
||||
if(extensionsSupported)
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
|
||||
|
||||
@@ -122,6 +120,9 @@ namespace mlx
|
||||
if(!indices.isComplete() || !extensionsSupported || formatCount == 0)
|
||||
return -1;
|
||||
|
||||
VkPhysicalDeviceFeatures features;
|
||||
vkGetPhysicalDeviceFeatures(device, &features);
|
||||
|
||||
int score = 0;
|
||||
#ifndef FORCE_INTEGRATED_GPU
|
||||
if(props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
|
||||
@@ -130,6 +131,10 @@ namespace mlx
|
||||
if(props.deviceType != VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
if(!features.geometryShader)
|
||||
return -1;
|
||||
|
||||
score += props.limits.maxImageDimension2D;
|
||||
score += props.limits.maxBoundDescriptorSets;
|
||||
return score;
|
||||
@@ -137,7 +142,7 @@ namespace mlx
|
||||
|
||||
bool Device::checkDeviceExtensionSupport(VkPhysicalDevice device)
|
||||
{
|
||||
uint32_t extensionCount;
|
||||
std::uint32_t extensionCount;
|
||||
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
|
||||
|
||||
std::vector<VkExtensionProperties> availableExtensions(extensionCount);
|
||||
@@ -155,5 +160,8 @@ namespace mlx
|
||||
{
|
||||
vkDestroyDevice(_device, nullptr);
|
||||
_device = VK_NULL_HANDLE;
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : destroyed a logical device");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,15 +6,15 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/08 19:13:42 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/11 01:51:26 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/03/14 16:59:54 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __MLX_VK_DEVICE__
|
||||
#define __MLX_VK_DEVICE__
|
||||
|
||||
#include <mlx_profile.h>
|
||||
#include <volk.h>
|
||||
#include "vk_queues.h"
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
@@ -27,7 +27,7 @@ namespace mlx
|
||||
inline VkDevice& operator()() noexcept { return _device; }
|
||||
inline VkDevice& get() noexcept { return _device; }
|
||||
|
||||
inline VkPhysicalDevice& getPhysicalDevice() noexcept { return _physicalDevice; }
|
||||
inline VkPhysicalDevice& getPhysicalDevice() noexcept { return _physical_device; }
|
||||
|
||||
private:
|
||||
void pickPhysicalDevice();
|
||||
@@ -35,7 +35,7 @@ namespace mlx
|
||||
int deviceScore(VkPhysicalDevice device, VkSurfaceKHR surface);
|
||||
|
||||
private:
|
||||
VkPhysicalDevice _physicalDevice = VK_NULL_HANDLE;
|
||||
VkPhysicalDevice _physical_device = VK_NULL_HANDLE;
|
||||
VkDevice _device = VK_NULL_HANDLE;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,25 +6,24 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/04/02 17:53:06 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/18 17:07:21 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/02/25 08:02:45 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <renderer/core/vk_fence.h>
|
||||
#include <renderer/core/render_core.h>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
void Fence::init()
|
||||
{
|
||||
VkSemaphoreCreateInfo semaphoreInfo{};
|
||||
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
|
||||
VkFenceCreateInfo fenceInfo{};
|
||||
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||
|
||||
if(vkCreateFence(Render_Core::get().getDevice().get(), &fenceInfo, nullptr, &_fence) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create CPU synchronization object");
|
||||
VkResult res;
|
||||
if((res = vkCreateFence(Render_Core::get().getDevice().get(), &fenceInfo, nullptr, &_fence)) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create a synchronization object (fence), %s", RCore::verbaliseResultVk(res));
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : created new fence");
|
||||
#endif
|
||||
@@ -40,10 +39,18 @@ namespace mlx
|
||||
vkResetFences(Render_Core::get().getDevice().get(), 1, &_fence);
|
||||
}
|
||||
|
||||
bool Fence::isReady() const noexcept
|
||||
{
|
||||
return vkGetFenceStatus(Render_Core::get().getDevice().get(), _fence) == VK_SUCCESS;
|
||||
}
|
||||
|
||||
void Fence::destroy() noexcept
|
||||
{
|
||||
if(_fence != VK_NULL_HANDLE)
|
||||
vkDestroyFence(Render_Core::get().getDevice().get(), _fence, nullptr);
|
||||
_fence = VK_NULL_HANDLE;
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : destroyed fence");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,15 +6,15 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/04/02 17:52:09 by maldavid #+# #+# */
|
||||
/* Updated: 2023/04/02 17:52:59 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/01/03 15:26:21 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __MLX_VK_FENCE__
|
||||
#define __MLX_VK_FENCE__
|
||||
|
||||
#include <mlx_profile.h>
|
||||
#include <volk.h>
|
||||
#include <renderer/core/render_core.h>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
@@ -28,6 +28,7 @@ namespace mlx
|
||||
inline VkFence& get() noexcept { return _fence; }
|
||||
void wait() noexcept;
|
||||
void reset() noexcept;
|
||||
bool isReady() const noexcept;
|
||||
inline void waitAndReset() noexcept { wait(); reset(); }
|
||||
|
||||
void destroy() noexcept;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/08 19:04:21 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/18 17:21:42 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/02/24 21:10:32 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -21,40 +21,35 @@ namespace mlx
|
||||
{
|
||||
VkApplicationInfo appInfo{};
|
||||
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||
appInfo.pApplicationName = "MacroLibX";
|
||||
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||
appInfo.pEngineName = "MacroLibX";
|
||||
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||
appInfo.engineVersion = VK_MAKE_VERSION(1, 3, 1);
|
||||
appInfo.apiVersion = VK_API_VERSION_1_2;
|
||||
|
||||
auto extensions = getRequiredExtensions();
|
||||
|
||||
VkInstanceCreateInfo createInfo{};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
createInfo.pApplicationInfo = &appInfo;
|
||||
|
||||
auto extensions = getRequiredExtensions();
|
||||
createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
|
||||
createInfo.enabledExtensionCount = static_cast<std::uint32_t>(extensions.size());
|
||||
createInfo.ppEnabledExtensionNames = extensions.data();
|
||||
createInfo.enabledLayerCount = 0; // will be replaced if validation layers are enabled
|
||||
createInfo.pNext = nullptr;
|
||||
|
||||
VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo;
|
||||
if constexpr(enableValidationLayers)
|
||||
{
|
||||
if(Render_Core::get().getLayers().checkValidationLayerSupport())
|
||||
{
|
||||
createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
|
||||
createInfo.enabledLayerCount = static_cast<std::uint32_t>(validationLayers.size());
|
||||
createInfo.ppEnabledLayerNames = validationLayers.data();
|
||||
Render_Core::get().getLayers().populateDebugMessengerCreateInfo(debugCreateInfo);
|
||||
createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*) &debugCreateInfo;
|
||||
createInfo.pNext = static_cast<VkDebugUtilsMessengerCreateInfoEXT*>(&debugCreateInfo);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
createInfo.enabledLayerCount = 0;
|
||||
createInfo.pNext = nullptr;
|
||||
}
|
||||
|
||||
VkResult res;
|
||||
if((res = vkCreateInstance(&createInfo, nullptr, &_instance)) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create Vulkan instance");
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create Vulkan instance, %s", RCore::verbaliseResultVk(res));
|
||||
volkLoadInstance(_instance);
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : created new instance");
|
||||
@@ -63,25 +58,34 @@ namespace mlx
|
||||
|
||||
std::vector<const char*> Instance::getRequiredExtensions()
|
||||
{
|
||||
unsigned int count = 0;
|
||||
SDL_Window* window = SDL_CreateWindow("", 0, 0, 1, 1, SDL_WINDOW_VULKAN | SDL_WINDOW_HIDDEN);
|
||||
if(!window)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : cannot get instance extentions from window : %s", SDL_GetError());
|
||||
std::vector<const char*> extensions;
|
||||
extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||
|
||||
#ifdef VK_USE_PLATFORM_XCB_KHR
|
||||
extensions.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
|
||||
#endif
|
||||
|
||||
if(!SDL_Vulkan_GetInstanceExtensions(window, &count, nullptr))
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : cannot get instance extentions from window : %s", SDL_GetError());
|
||||
#ifdef VK_USE_PLATFORM_XLIB_KHR
|
||||
extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||
#endif
|
||||
|
||||
std::vector<const char*> extensions = { VK_EXT_DEBUG_REPORT_EXTENSION_NAME };
|
||||
size_t additional_extension_count = extensions.size();
|
||||
extensions.resize(additional_extension_count + count);
|
||||
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
||||
extensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
|
||||
#endif
|
||||
|
||||
if(!SDL_Vulkan_GetInstanceExtensions(window, &count, extensions.data() + additional_extension_count))
|
||||
core::error::report(e_kind::error, "Vulkan : cannot get instance extentions from window : %s", SDL_GetError());
|
||||
#ifdef VK_USE_PLATFORM_WIN32_KHR
|
||||
extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_METAL_EXT
|
||||
extensions.push_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
|
||||
#endif
|
||||
|
||||
if constexpr(enableValidationLayers)
|
||||
{
|
||||
extensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
|
||||
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
|
||||
SDL_DestroyWindow(window);
|
||||
}
|
||||
return extensions;
|
||||
}
|
||||
|
||||
@@ -89,5 +93,8 @@ namespace mlx
|
||||
{
|
||||
vkDestroyInstance(_instance, nullptr);
|
||||
_instance = VK_NULL_HANDLE;
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : destroyed an instance");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,14 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/08 19:03:04 by maldavid #+# #+# */
|
||||
/* Updated: 2022/12/18 17:42:08 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/01/03 15:26:26 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __MLX_VK_INSTANCE__
|
||||
#define __MLX_VK_INSTANCE__
|
||||
|
||||
#include <mlx_profile.h>
|
||||
#include <volk.h>
|
||||
#include <vector>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/08 19:02:42 by maldavid #+# #+# */
|
||||
/* Updated: 2022/12/18 22:52:04 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/03/14 17:01:10 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace mlx
|
||||
{
|
||||
Queues::QueueFamilyIndices Queues::findQueueFamilies(VkPhysicalDevice device, VkSurfaceKHR surface)
|
||||
{
|
||||
uint32_t queueFamilyCount = 0;
|
||||
std::uint32_t queueFamilyCount = 0;
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
|
||||
|
||||
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
|
||||
@@ -29,16 +29,16 @@ namespace mlx
|
||||
for(const auto& queueFamily : queueFamilies)
|
||||
{
|
||||
if(queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
||||
_families->graphicsFamily = i;
|
||||
_families->graphics_family = i;
|
||||
|
||||
VkBool32 presentSupport = false;
|
||||
vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
|
||||
|
||||
if(presentSupport)
|
||||
_families->presentFamily = i;
|
||||
_families->present_family = i;
|
||||
|
||||
if(_families->isComplete())
|
||||
break;
|
||||
return *_families;
|
||||
i++;
|
||||
}
|
||||
|
||||
@@ -62,7 +62,10 @@ namespace mlx
|
||||
vkDestroySurfaceKHR(Render_Core::get().getInstance().get(), surface, nullptr);
|
||||
SDL_DestroyWindow(window);
|
||||
}
|
||||
vkGetDeviceQueue(Render_Core::get().getDevice().get(), _families->graphicsFamily.value(), 0, &_graphicsQueue);
|
||||
vkGetDeviceQueue(Render_Core::get().getDevice().get(), _families->presentFamily.value(), 0, &_presentQueue);
|
||||
vkGetDeviceQueue(Render_Core::get().getDevice().get(), _families->graphics_family.value(), 0, &_graphics_queue);
|
||||
vkGetDeviceQueue(Render_Core::get().getDevice().get(), _families->present_family.value(), 0, &_present_queue);
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : got graphics and present queues");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,16 +6,18 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/08 19:01:49 by maldavid #+# #+# */
|
||||
/* Updated: 2022/12/18 22:44:37 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/03/14 17:00:48 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __MLX_VK_QUEUES__
|
||||
#define __MLX_VK_QUEUES__
|
||||
|
||||
#include <mlx_profile.h>
|
||||
#include <volk.h>
|
||||
#include <optional>
|
||||
#include <cstdint>
|
||||
#include <core/errors.h>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
@@ -24,23 +26,29 @@ namespace mlx
|
||||
public:
|
||||
struct QueueFamilyIndices
|
||||
{
|
||||
std::optional<uint32_t> graphicsFamily;
|
||||
std::optional<uint32_t> presentFamily;
|
||||
std::optional<std::uint32_t> graphics_family;
|
||||
std::optional<std::uint32_t> present_family;
|
||||
|
||||
inline bool isComplete() { return graphicsFamily.has_value() && presentFamily.has_value(); }
|
||||
inline bool isComplete() { return graphics_family.has_value() && present_family.has_value(); }
|
||||
};
|
||||
|
||||
QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device, VkSurfaceKHR surface);
|
||||
|
||||
void init();
|
||||
|
||||
inline VkQueue& getGraphic() noexcept { return _graphicsQueue; }
|
||||
inline VkQueue& getPresent() noexcept { return _presentQueue; }
|
||||
inline QueueFamilyIndices getFamilies() noexcept { return *_families; }
|
||||
inline VkQueue& getGraphic() noexcept { return _graphics_queue; }
|
||||
inline VkQueue& getPresent() noexcept { return _present_queue; }
|
||||
inline QueueFamilyIndices getFamilies() noexcept
|
||||
{
|
||||
if(_families.has_value())
|
||||
return *_families;
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : cannot get queue families, not init");
|
||||
return {}; // just to avoid warnings
|
||||
}
|
||||
|
||||
private:
|
||||
VkQueue _graphicsQueue;
|
||||
VkQueue _presentQueue;
|
||||
VkQueue _graphics_queue;
|
||||
VkQueue _present_queue;
|
||||
std::optional<QueueFamilyIndices> _families;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/08 19:01:08 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/18 17:22:29 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/03/14 17:02:36 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -21,19 +21,23 @@ namespace mlx
|
||||
VkSemaphoreCreateInfo semaphoreInfo{};
|
||||
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
|
||||
if( vkCreateSemaphore(Render_Core::get().getDevice().get(), &semaphoreInfo, nullptr, &_imageAvailableSemaphores) != VK_SUCCESS ||
|
||||
vkCreateSemaphore(Render_Core::get().getDevice().get(), &semaphoreInfo, nullptr, &_renderFinishedSemaphores) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create GPU synchronization object");
|
||||
VkResult res;
|
||||
if( (res = vkCreateSemaphore(Render_Core::get().getDevice().get(), &semaphoreInfo, nullptr, &_image_available_semaphore)) != VK_SUCCESS ||
|
||||
(res = vkCreateSemaphore(Render_Core::get().getDevice().get(), &semaphoreInfo, nullptr, &_render_finished_semaphore)) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create a synchronization object (semaphore), %s", RCore::verbaliseResultVk(res));
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : created new semaphore");
|
||||
core::error::report(e_kind::message, "Vulkan : created new semaphores");
|
||||
#endif
|
||||
}
|
||||
|
||||
void Semaphore::destroy() noexcept
|
||||
{
|
||||
vkDestroySemaphore(Render_Core::get().getDevice().get(), _renderFinishedSemaphores, nullptr);
|
||||
_renderFinishedSemaphores = VK_NULL_HANDLE;
|
||||
vkDestroySemaphore(Render_Core::get().getDevice().get(), _imageAvailableSemaphores, nullptr);
|
||||
_imageAvailableSemaphores = VK_NULL_HANDLE;
|
||||
vkDestroySemaphore(Render_Core::get().getDevice().get(), _render_finished_semaphore, nullptr);
|
||||
_render_finished_semaphore = VK_NULL_HANDLE;
|
||||
vkDestroySemaphore(Render_Core::get().getDevice().get(), _image_available_semaphore, nullptr);
|
||||
_image_available_semaphore = VK_NULL_HANDLE;
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : destroyed semaphores");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,15 +6,15 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/08 18:59:38 by maldavid #+# #+# */
|
||||
/* Updated: 2023/04/02 17:55:10 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/03/14 17:01:57 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __MLX_VK_SEMAPHORE__
|
||||
#define __MLX_VK_SEMAPHORE__
|
||||
|
||||
#include <mlx_profile.h>
|
||||
#include <volk.h>
|
||||
#include <vector>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
@@ -24,12 +24,12 @@ namespace mlx
|
||||
void init();
|
||||
void destroy() noexcept;
|
||||
|
||||
inline VkSemaphore& getImageSemaphore() noexcept { return _imageAvailableSemaphores; }
|
||||
inline VkSemaphore& getRenderImageSemaphore() noexcept { return _renderFinishedSemaphores; }
|
||||
inline VkSemaphore& getImageSemaphore() noexcept { return _image_available_semaphore; }
|
||||
inline VkSemaphore& getRenderImageSemaphore() noexcept { return _render_finished_semaphore; }
|
||||
|
||||
private:
|
||||
VkSemaphore _imageAvailableSemaphores = VK_NULL_HANDLE;
|
||||
VkSemaphore _renderFinishedSemaphores = VK_NULL_HANDLE;
|
||||
VkSemaphore _image_available_semaphore = VK_NULL_HANDLE;
|
||||
VkSemaphore _render_finished_semaphore = VK_NULL_HANDLE;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/08 18:58:49 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/18 17:22:38 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/01/10 21:55:21 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <renderer/renderer.h>
|
||||
#include <SDL2/SDL_vulkan.h>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
@@ -29,18 +30,20 @@ namespace mlx
|
||||
|
||||
VkSurfaceFormatKHR Surface::chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats)
|
||||
{
|
||||
for(const auto& availableFormat : availableFormats)
|
||||
auto it = std::find_if(availableFormats.begin(), availableFormats.end(), [](VkSurfaceFormatKHR format)
|
||||
{
|
||||
if(availableFormat.format == VK_FORMAT_R8G8B8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
||||
return availableFormat;
|
||||
}
|
||||
return format.format == VK_FORMAT_R8G8B8A8_SRGB && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
|
||||
});
|
||||
|
||||
return availableFormats[0];
|
||||
return (it == availableFormats.end() ? availableFormats[0] : *it);
|
||||
}
|
||||
|
||||
void Surface::destroy() noexcept
|
||||
{
|
||||
vkDestroySurfaceKHR(Render_Core::get().getInstance().get(), _surface, nullptr);
|
||||
_surface = VK_NULL_HANDLE;
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : destroyed a surface");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,14 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/08 18:57:55 by maldavid #+# #+# */
|
||||
/* Updated: 2022/12/18 19:34:04 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/01/03 15:26:43 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __MLX_VK_SURFACE__
|
||||
#define __MLX_VK_SURFACE__
|
||||
|
||||
#include <mlx_profile.h>
|
||||
#include <volk.h>
|
||||
#include <vector>
|
||||
|
||||
|
||||
@@ -3,19 +3,19 @@
|
||||
/* ::: :::::::: */
|
||||
/* vk_validation_layers.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/12/19 14:05:25 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/20 07:21:57 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/03/14 17:03:24 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "vk_validation_layers.h"
|
||||
#include "render_core.h"
|
||||
#include "vulkan/vulkan_core.h"
|
||||
|
||||
#include <core/errors.h>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
@@ -24,54 +24,65 @@ namespace mlx
|
||||
if constexpr(!enableValidationLayers)
|
||||
return;
|
||||
|
||||
VkDebugUtilsMessengerCreateInfoEXT createInfo;
|
||||
std::uint32_t extensionCount;
|
||||
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
|
||||
std::vector<VkExtensionProperties> extensions(extensionCount);
|
||||
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
|
||||
if(!std::any_of(extensions.begin(), extensions.end(), [=](VkExtensionProperties ext) { return std::strcmp(ext.extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0; }))
|
||||
{
|
||||
core::error::report(e_kind::warning , "Vulkan : %s not present, debug utils are disabled", VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
return;
|
||||
}
|
||||
|
||||
VkDebugUtilsMessengerCreateInfoEXT createInfo{};
|
||||
populateDebugMessengerCreateInfo(createInfo);
|
||||
if(createDebugUtilsMessengerEXT(&createInfo, nullptr) != VK_SUCCESS)
|
||||
core::error::report(e_kind::error, "Vulkan : failed to set up debug messenger");
|
||||
VkResult res = createDebugUtilsMessengerEXT(&createInfo, nullptr);
|
||||
if(res != VK_SUCCESS)
|
||||
core::error::report(e_kind::warning, "Vulkan : failed to set up debug messenger, %s", RCore::verbaliseResultVk(res));
|
||||
#ifdef DEBUG
|
||||
else
|
||||
core::error::report(e_kind::message, "Vulkan : enabled validation layers");
|
||||
#endif
|
||||
|
||||
_vkSetDebugUtilsObjectNameEXT = (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(Render_Core::get().getInstance().get(), "vkSetDebugUtilsObjectNameEXT");
|
||||
if(!_vkSetDebugUtilsObjectNameEXT)
|
||||
core::error::report(e_kind::warning, "Vulkan : failed to set up debug object names, %s", RCore::verbaliseResultVk(VK_ERROR_EXTENSION_NOT_PRESENT));
|
||||
#ifdef DEBUG
|
||||
else
|
||||
core::error::report(e_kind::message, "Vulkan : enabled debug object names");
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ValidationLayers::checkValidationLayerSupport()
|
||||
{
|
||||
uint32_t layerCount;
|
||||
std::uint32_t layerCount;
|
||||
vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
|
||||
|
||||
std::vector<VkLayerProperties> availableLayers(layerCount);
|
||||
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
|
||||
|
||||
for(const char* layerName : validationLayers)
|
||||
return std::all_of(validationLayers.begin(), validationLayers.end(), [&](const char* layerName)
|
||||
{
|
||||
bool layerFound = false;
|
||||
|
||||
for(const auto& layerProperties : availableLayers)
|
||||
if(!std::any_of(availableLayers.begin(), availableLayers.end(), [=](VkLayerProperties props) { return std::strcmp(layerName, props.layerName) == 0; }))
|
||||
{
|
||||
if(std::strcmp(layerName, layerProperties.layerName) == 0)
|
||||
{
|
||||
layerFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!layerFound)
|
||||
core::error::report(e_kind::error, "Vulkan : a validation layer was requested but was not found ('%s')", layerName);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void ValidationLayers::destroy()
|
||||
VkResult ValidationLayers::setDebugUtilsObjectNameEXT(VkObjectType object_type, std::uint64_t object_handle, const char* object_name)
|
||||
{
|
||||
if constexpr(!enableValidationLayers)
|
||||
return;
|
||||
destroyDebugUtilsMessengerEXT(nullptr);
|
||||
}
|
||||
if(!_vkSetDebugUtilsObjectNameEXT)
|
||||
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||
|
||||
VkResult ValidationLayers::createDebugUtilsMessengerEXT(const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator)
|
||||
{
|
||||
auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(Render_Core::get().getInstance().get(), "vkCreateDebugUtilsMessengerEXT");
|
||||
return func != nullptr ? func(Render_Core::get().getInstance().get(), pCreateInfo, pAllocator, &_debugMessenger) : VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||
VkDebugUtilsObjectNameInfoEXT name_info{};
|
||||
name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
|
||||
name_info.objectType = object_type;
|
||||
name_info.objectHandle = object_handle;
|
||||
name_info.pObjectName = object_name;
|
||||
return _vkSetDebugUtilsObjectNameEXT(Render_Core::get().getDevice().get(), &name_info);
|
||||
}
|
||||
|
||||
void ValidationLayers::populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo)
|
||||
@@ -83,19 +94,29 @@ namespace mlx
|
||||
createInfo.pfnUserCallback = ValidationLayers::debugCallback;
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkBool32 VKAPI_CALL ValidationLayers::debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData)
|
||||
void ValidationLayers::destroy()
|
||||
{
|
||||
if constexpr(enableValidationLayers)
|
||||
{
|
||||
destroyDebugUtilsMessengerEXT(nullptr);
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : destroyed validation layers");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
VkResult ValidationLayers::createDebugUtilsMessengerEXT(const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator)
|
||||
{
|
||||
auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(Render_Core::get().getInstance().get(), "vkCreateDebugUtilsMessengerEXT");
|
||||
return func != nullptr ? func(Render_Core::get().getInstance().get(), pCreateInfo, pAllocator, &_debug_messenger) : VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkBool32 VKAPI_CALL ValidationLayers::debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, [[maybe_unused]] VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, [[maybe_unused]] void* pUserData)
|
||||
{
|
||||
if(messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
|
||||
{
|
||||
std::cout << '\n';
|
||||
core::error::report(e_kind::error, std::string("Vulkan layer error: ") + pCallbackData->pMessage);
|
||||
}
|
||||
core::error::report(e_kind::error, pCallbackData->pMessage);
|
||||
else if(messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)
|
||||
{
|
||||
std::cout << '\n';
|
||||
core::error::report(e_kind::warning, std::string("Vulkan layer warning: ") + pCallbackData->pMessage);
|
||||
}
|
||||
|
||||
core::error::report(e_kind::warning, pCallbackData->pMessage);
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
@@ -103,7 +124,7 @@ namespace mlx
|
||||
{
|
||||
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(Render_Core::get().getInstance().get(), "vkDestroyDebugUtilsMessengerEXT");
|
||||
if(func != nullptr)
|
||||
func(Render_Core::get().getInstance().get(), _debugMessenger, pAllocator);
|
||||
func(Render_Core::get().getInstance().get(), _debug_messenger, pAllocator);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,13 +6,14 @@
|
||||
/* By: maldavid <marvin@42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/12/19 14:04:25 by maldavid #+# #+# */
|
||||
/* Updated: 2022/12/19 14:05:19 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/03/14 17:02:55 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __VK_VALIDATION_LAYERS__
|
||||
#define __VK_VALIDATION_LAYERS__
|
||||
|
||||
#include <mlx_profile.h>
|
||||
#include <volk.h>
|
||||
|
||||
namespace mlx
|
||||
@@ -20,17 +21,26 @@ namespace mlx
|
||||
class ValidationLayers
|
||||
{
|
||||
public:
|
||||
ValidationLayers() = default;
|
||||
|
||||
void init();
|
||||
void destroy();
|
||||
|
||||
bool checkValidationLayerSupport();
|
||||
void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo);
|
||||
|
||||
VkResult setDebugUtilsObjectNameEXT(VkObjectType object_type, std::uint64_t object_handle, const char* object_name);
|
||||
|
||||
~ValidationLayers() = default;
|
||||
|
||||
private:
|
||||
VkResult createDebugUtilsMessengerEXT(const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator);
|
||||
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData);
|
||||
void destroyDebugUtilsMessengerEXT(const VkAllocationCallbacks* pAllocator);
|
||||
|
||||
VkDebugUtilsMessengerEXT _debugMessenger;
|
||||
private:
|
||||
VkDebugUtilsMessengerEXT _debug_messenger;
|
||||
PFN_vkSetDebugUtilsObjectNameEXT _vkSetDebugUtilsObjectNameEXT = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
39
src/renderer/descriptors/descriptor_pool_manager.cpp
git.filemode.normal_file
@@ -0,0 +1,39 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* descriptor_pool_manager.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/01/20 06:51:47 by maldavid #+# #+# */
|
||||
/* Updated: 2024/01/20 08:18:27 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <renderer/core/render_core.h>
|
||||
#include <renderer/descriptors/descriptor_pool_manager.h>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
DescriptorPool& DescriptorPoolManager::getAvailablePool()
|
||||
{
|
||||
for(auto& pool : _pools)
|
||||
{
|
||||
if(pool.getNumberOfSetsAllocated() < MAX_SETS_PER_POOL)
|
||||
return pool;
|
||||
}
|
||||
VkDescriptorPoolSize pool_sizes[] = {
|
||||
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, (MAX_FRAMES_IN_FLIGHT * NUMBER_OF_UNIFORM_BUFFERS) },
|
||||
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, MAX_SETS_PER_POOL - (MAX_FRAMES_IN_FLIGHT * NUMBER_OF_UNIFORM_BUFFERS) }
|
||||
};
|
||||
_pools.emplace_front().init((sizeof(pool_sizes) / sizeof(VkDescriptorPoolSize)), pool_sizes);
|
||||
return _pools.front();
|
||||
}
|
||||
|
||||
void DescriptorPoolManager::destroyAllPools()
|
||||
{
|
||||
for(auto& pool : _pools)
|
||||
pool.destroy();
|
||||
_pools.clear();
|
||||
}
|
||||
}
|
||||
36
src/renderer/descriptors/descriptor_pool_manager.h
git.filemode.normal_file
@@ -0,0 +1,36 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* descriptor_pool_manager.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/01/20 06:26:26 by maldavid #+# #+# */
|
||||
/* Updated: 2024/01/20 08:23:04 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __MLX_DESCRIPTOR_POOL_MANAGER__
|
||||
#define __MLX_DESCRIPTOR_POOL_MANAGER__
|
||||
|
||||
#include <renderer/descriptors/vk_descriptor_pool.h>
|
||||
#include <list>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
class DescriptorPoolManager
|
||||
{
|
||||
public:
|
||||
DescriptorPoolManager() = default;
|
||||
|
||||
DescriptorPool& getAvailablePool(); // assumes the pool is for only one set allocation, may cause some issues if this is for more than one
|
||||
void destroyAllPools();
|
||||
|
||||
~DescriptorPoolManager() = default;
|
||||
|
||||
private:
|
||||
std::list<DescriptorPool> _pools;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -6,11 +6,12 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/01/23 18:34:23 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/18 17:23:05 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/01/20 07:40:40 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "vk_descriptor_pool.h"
|
||||
#include <renderer/descriptors/vk_descriptor_set.h>
|
||||
#include <renderer/core/render_core.h>
|
||||
|
||||
namespace mlx
|
||||
@@ -21,15 +22,34 @@ namespace mlx
|
||||
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
poolInfo.poolSizeCount = n;
|
||||
poolInfo.pPoolSizes = size;
|
||||
poolInfo.maxSets = 8192;
|
||||
poolInfo.maxSets = MAX_SETS_PER_POOL;
|
||||
poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
|
||||
|
||||
if(vkCreateDescriptorPool(Render_Core::get().getDevice().get(), &poolInfo, nullptr, &_pool) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create descriptor pool");
|
||||
VkResult res = vkCreateDescriptorPool(Render_Core::get().getDevice().get(), &poolInfo, nullptr, &_pool);
|
||||
if(res != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create descriptor pool, %s", RCore::verbaliseResultVk(res));
|
||||
_allocated_sets++;
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : created new descriptor pool");
|
||||
#endif
|
||||
}
|
||||
|
||||
void DescriptorPool::destroy() noexcept
|
||||
void DescriptorPool::freeDescriptor(const DescriptorSet& set)
|
||||
{
|
||||
vkDestroyDescriptorPool(Render_Core::get().getDevice().get(), _pool, nullptr);
|
||||
if(!isInit())
|
||||
return;
|
||||
const auto& sets = set.getAllFramesDescriptorSets();
|
||||
vkFreeDescriptorSets(Render_Core::get().getDevice().get(), _pool, sets.size(), sets.data());
|
||||
_allocated_sets--; // if this goes in underflow I quit
|
||||
}
|
||||
|
||||
void DescriptorPool::destroy() noexcept
|
||||
{
|
||||
if(_pool != VK_NULL_HANDLE)
|
||||
vkDestroyDescriptorPool(Render_Core::get().getDevice().get(), _pool, nullptr);
|
||||
_pool = VK_NULL_HANDLE;
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : destroyed a descriptor pool");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,14 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/01/23 18:32:43 by maldavid #+# #+# */
|
||||
/* Updated: 2023/01/23 18:44:40 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/01/20 07:38:32 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __VK_DESCRIPTOR_POOL__
|
||||
#define __VK_DESCRIPTOR_POOL__
|
||||
|
||||
#include <mlx_profile.h>
|
||||
#include <volk.h>
|
||||
#include <cstddef>
|
||||
|
||||
@@ -21,14 +22,23 @@ namespace mlx
|
||||
class DescriptorPool
|
||||
{
|
||||
public:
|
||||
DescriptorPool() = default;
|
||||
|
||||
void init(std::size_t n, VkDescriptorPoolSize* size);
|
||||
void freeDescriptor(const class DescriptorSet& set);
|
||||
void destroy() noexcept;
|
||||
|
||||
inline VkDescriptorPool& operator()() noexcept { return _pool; }
|
||||
inline VkDescriptorPool& get() noexcept { return _pool; }
|
||||
inline std::size_t getNumberOfSetsAllocated() const noexcept { return _allocated_sets; }
|
||||
|
||||
inline bool isInit() const noexcept { return _pool != VK_NULL_HANDLE; }
|
||||
|
||||
~DescriptorPool() = default;
|
||||
|
||||
private:
|
||||
VkDescriptorPool _pool = VK_NULL_HANDLE;
|
||||
std::size_t _allocated_sets = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -6,20 +6,24 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/01/23 18:40:44 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/12 01:14:52 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/01/20 08:18:07 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "vk_descriptor_set.h"
|
||||
#include "renderer/core/render_core.h"
|
||||
#include "vk_descriptor_pool.h"
|
||||
#include "vk_descriptor_set_layout.h"
|
||||
#include <renderer/buffers/vk_ubo.h>
|
||||
#include <renderer/renderer.h>
|
||||
#include <renderer/images/vk_image.h>
|
||||
#include <core/profiler.h>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
void DescriptorSet::init(Renderer* renderer, DescriptorPool* pool, DescriptorSetLayout* layout)
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
_renderer = renderer;
|
||||
_layout = layout;
|
||||
_pool = pool;
|
||||
@@ -32,18 +36,20 @@ namespace mlx
|
||||
VkDescriptorSetAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
allocInfo.descriptorPool = _pool->get();
|
||||
allocInfo.descriptorSetCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
|
||||
allocInfo.descriptorSetCount = static_cast<std::uint32_t>(MAX_FRAMES_IN_FLIGHT);
|
||||
allocInfo.pSetLayouts = layouts.data();
|
||||
|
||||
if(vkAllocateDescriptorSets(device, &allocInfo, _desc_set.data()) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to allocate descriptor set");
|
||||
VkResult res = vkAllocateDescriptorSets(device, &allocInfo, _desc_set.data());
|
||||
if(res != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to allocate descriptor set, %s", RCore::verbaliseResultVk(res));
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : created new descriptor set");
|
||||
#endif
|
||||
}
|
||||
|
||||
void DescriptorSet::writeDescriptor(int binding, UBO* ubo) noexcept
|
||||
void DescriptorSet::writeDescriptor(int binding, UBO* ubo) const noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
auto device = Render_Core::get().getDevice().get();
|
||||
|
||||
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
|
||||
@@ -66,14 +72,15 @@ namespace mlx
|
||||
}
|
||||
}
|
||||
|
||||
void DescriptorSet::writeDescriptor(int binding, VkImageView view, VkSampler sampler) noexcept
|
||||
void DescriptorSet::writeDescriptor(int binding, const Image& image) const noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
auto device = Render_Core::get().getDevice().get();
|
||||
|
||||
VkDescriptorImageInfo imageInfo{};
|
||||
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
imageInfo.imageView = view;
|
||||
imageInfo.sampler = sampler;
|
||||
imageInfo.imageLayout = image.getLayout();
|
||||
imageInfo.imageView = image.getImageView();
|
||||
imageInfo.sampler = image.getSampler();
|
||||
|
||||
VkWriteDescriptorSet descriptorWrite{};
|
||||
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
@@ -89,8 +96,9 @@ namespace mlx
|
||||
|
||||
DescriptorSet DescriptorSet::duplicate()
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
DescriptorSet set;
|
||||
set.init(_renderer, _pool, _layout);
|
||||
set.init(_renderer, &Render_Core::get().getDescriptorPool(), _layout);
|
||||
return set;
|
||||
}
|
||||
|
||||
@@ -98,8 +106,24 @@ namespace mlx
|
||||
{
|
||||
return _desc_set[_renderer->getActiveImageIndex()];
|
||||
}
|
||||
|
||||
VkDescriptorSet& DescriptorSet::get() noexcept
|
||||
{
|
||||
return _desc_set[_renderer->getActiveImageIndex()];
|
||||
}
|
||||
|
||||
void DescriptorSet::destroy() noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
if(_pool != nullptr && Render_Core::get().isInit()) // checks if the render core is still init (it should always be init but just in case)
|
||||
_pool->freeDescriptor(*this);
|
||||
for(auto& set : _desc_set)
|
||||
{
|
||||
if(set != VK_NULL_HANDLE)
|
||||
set = VK_NULL_HANDLE;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : destroyed descriptor set");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,14 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/01/23 18:39:36 by maldavid #+# #+# */
|
||||
/* Updated: 2023/03/31 17:28:36 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/01/20 07:17:39 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __VK_DESCRIPTOR_SET__
|
||||
#define __VK_DESCRIPTOR_SET__
|
||||
|
||||
#include <mlx_profile.h>
|
||||
#include <volk.h>
|
||||
#include <array>
|
||||
#include <renderer/core/render_core.h>
|
||||
@@ -22,18 +23,26 @@ namespace mlx
|
||||
class DescriptorSet
|
||||
{
|
||||
public:
|
||||
DescriptorSet() = default;
|
||||
|
||||
void init(class Renderer* renderer, class DescriptorPool* pool, class DescriptorSetLayout* layout);
|
||||
|
||||
void writeDescriptor(int binding, class UBO* ubo) noexcept;
|
||||
void writeDescriptor(int binding, VkImageView view, VkSampler sampler) noexcept;
|
||||
void writeDescriptor(int binding, class UBO* ubo) const noexcept;
|
||||
void writeDescriptor(int binding, const class Image& image) const noexcept;
|
||||
|
||||
inline bool isInit() noexcept { return _pool != nullptr && _renderer != nullptr; }
|
||||
inline bool isInit() const noexcept { return _pool != nullptr && _renderer != nullptr; }
|
||||
|
||||
DescriptorSet duplicate();
|
||||
|
||||
VkDescriptorSet& operator()() noexcept;
|
||||
VkDescriptorSet& get() noexcept;
|
||||
|
||||
inline const std::array<VkDescriptorSet, MAX_FRAMES_IN_FLIGHT>& getAllFramesDescriptorSets() const { return _desc_set; }
|
||||
|
||||
void destroy() noexcept;
|
||||
|
||||
~DescriptorSet() = default;
|
||||
|
||||
private:
|
||||
std::array<VkDescriptorSet, MAX_FRAMES_IN_FLIGHT> _desc_set;
|
||||
class DescriptorPool* _pool = nullptr;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/01/23 18:37:28 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/18 17:23:16 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/01/03 13:14:58 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace mlx
|
||||
void DescriptorSetLayout::init(std::vector<std::pair<int, VkDescriptorType>> binds, VkShaderStageFlagBits stage)
|
||||
{
|
||||
std::vector<VkDescriptorSetLayoutBinding> bindings(binds.size());
|
||||
for(int i = 0; i < binds.size(); i++)
|
||||
for(std::size_t i = 0; i < binds.size(); i++)
|
||||
{
|
||||
bindings[i].binding = binds[i].first;
|
||||
bindings[i].descriptorCount = 1;
|
||||
@@ -34,8 +34,9 @@ namespace mlx
|
||||
layoutInfo.bindingCount = _bindings.size();
|
||||
layoutInfo.pBindings = bindings.data();
|
||||
|
||||
if(vkCreateDescriptorSetLayout(Render_Core::get().getDevice().get(), &layoutInfo, nullptr, &_layout) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create descriptor set layout");
|
||||
VkResult res = vkCreateDescriptorSetLayout(Render_Core::get().getDevice().get(), &layoutInfo, nullptr, &_layout);
|
||||
if(res != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create descriptor set layout, %s", RCore::verbaliseResultVk(res));
|
||||
}
|
||||
|
||||
void DescriptorSetLayout::destroy() noexcept
|
||||
|
||||
@@ -6,23 +6,24 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/01/23 18:36:22 by maldavid #+# #+# */
|
||||
/* Updated: 2023/03/31 17:54:03 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/01/20 06:25:54 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __VK_DESCRIPTOR_SET_LAYOUT__
|
||||
#define __VK_DESCRIPTOR_SET_LAYOUT__
|
||||
|
||||
#include <mlx_profile.h>
|
||||
#include <volk.h>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
class DescriptorSetLayout
|
||||
{
|
||||
public:
|
||||
DescriptorSetLayout() = default;
|
||||
|
||||
void init(std::vector<std::pair<int, VkDescriptorType>> binds, VkShaderStageFlagBits stage);
|
||||
void destroy() noexcept;
|
||||
|
||||
@@ -30,6 +31,8 @@ namespace mlx
|
||||
inline VkDescriptorSetLayout& get() noexcept { return _layout; }
|
||||
inline const std::vector<std::pair<int, VkDescriptorType>>& getBindings() const noexcept { return _bindings; }
|
||||
|
||||
~DescriptorSetLayout() = default;
|
||||
|
||||
private:
|
||||
VkDescriptorSetLayout _layout = VK_NULL_HANDLE;
|
||||
std::vector<std::pair<int, VkDescriptorType>> _bindings;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/03/31 18:03:35 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/16 14:01:47 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/09/14 00:04:29 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -14,12 +14,18 @@
|
||||
#include <renderer/images/texture.h>
|
||||
#include <renderer/buffers/vk_buffer.h>
|
||||
#include <renderer/renderer.h>
|
||||
#include <core/profiler.h>
|
||||
#include <cstring>
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
|
||||
#include <iostream>
|
||||
#ifdef MLX_COMPILER_GCC
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wstringop-overflow"
|
||||
#include <stb_image.h>
|
||||
#pragma GCC diagnostic pop
|
||||
#else
|
||||
#include <stb_image.h>
|
||||
#endif
|
||||
|
||||
#ifdef IMAGE_OPTIMIZED
|
||||
#define TILING VK_IMAGE_TILING_OPTIMAL
|
||||
@@ -29,11 +35,13 @@
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
void Texture::create(uint8_t* pixels, uint32_t width, uint32_t height, VkFormat format, const char* name, bool dedicated_memory)
|
||||
void Texture::create(std::uint8_t* pixels, std::uint32_t width, std::uint32_t height, VkFormat format, const char* name, bool dedicated_memory)
|
||||
{
|
||||
Image::create(width, height, format, TILING, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, name, dedicated_memory);
|
||||
MLX_PROFILE_FUNCTION();
|
||||
Image::create(width, height, format, TILING, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, name, dedicated_memory);
|
||||
Image::createImageView(VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
Image::createSampler();
|
||||
transitionLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
||||
std::vector<Vertex> vertexData = {
|
||||
{{0, 0}, {1.f, 1.f, 1.f, 1.f}, {0.0f, 0.0f}},
|
||||
@@ -42,34 +50,44 @@ namespace mlx
|
||||
{{0, height}, {1.f, 1.f, 1.f, 1.f}, {0.0f, 1.0f}}
|
||||
};
|
||||
|
||||
std::vector<uint16_t> indexData = { 0, 1, 2, 2, 3, 0 };
|
||||
std::vector<std::uint16_t> indexData = { 0, 1, 2, 2, 3, 0 };
|
||||
|
||||
#ifdef DEBUG
|
||||
_vbo.create(sizeof(Vertex) * vertexData.size(), vertexData.data(), name);
|
||||
_ibo.create(sizeof(uint16_t) * indexData.size(), indexData.data(), name);
|
||||
_ibo.create(sizeof(std::uint16_t) * indexData.size(), indexData.data(), name);
|
||||
_name = name;
|
||||
#else
|
||||
_vbo.create(sizeof(Vertex) * vertexData.size(), vertexData.data(), nullptr);
|
||||
_ibo.create(sizeof(uint16_t) * indexData.size(), indexData.data(), nullptr);
|
||||
_ibo.create(sizeof(std::uint16_t) * indexData.size(), indexData.data(), nullptr);
|
||||
#endif
|
||||
|
||||
Buffer staging_buffer;
|
||||
std::size_t size = width * height * formatSize(format);
|
||||
if(pixels != nullptr)
|
||||
{
|
||||
Buffer staging_buffer;
|
||||
std::size_t size = width * height * formatSize(format);
|
||||
#ifdef DEBUG
|
||||
staging_buffer.create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, name, pixels);
|
||||
#else
|
||||
staging_buffer.create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, nullptr, pixels);
|
||||
#endif
|
||||
Image::copyFromBuffer(staging_buffer);
|
||||
staging_buffer.destroy();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<std::uint32_t> default_pixels(width * height, 0x00000000);
|
||||
#ifdef DEBUG
|
||||
staging_buffer.create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, name, default_pixels.data());
|
||||
#else
|
||||
staging_buffer.create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, nullptr, default_pixels.data());
|
||||
#endif
|
||||
}
|
||||
Image::copyFromBuffer(staging_buffer);
|
||||
staging_buffer.destroy();
|
||||
}
|
||||
|
||||
void Texture::setPixel(int x, int y, uint32_t color) noexcept
|
||||
void Texture::setPixel(int x, int y, std::uint32_t color) noexcept
|
||||
{
|
||||
if(x < 0 || y < 0 || x > getWidth() || y > getHeight())
|
||||
MLX_PROFILE_FUNCTION();
|
||||
if(x < 0 || y < 0 || static_cast<std::uint32_t>(x) > getWidth() || static_cast<std::uint32_t>(y) > getHeight())
|
||||
return;
|
||||
if(_map == nullptr)
|
||||
openCPUmap();
|
||||
@@ -79,16 +97,22 @@ namespace mlx
|
||||
|
||||
int Texture::getPixel(int x, int y) noexcept
|
||||
{
|
||||
if(x < 0 || y < 0 || x > getWidth() || y > getHeight())
|
||||
MLX_PROFILE_FUNCTION();
|
||||
if(x < 0 || y < 0 || static_cast<std::uint32_t>(x) > getWidth() || static_cast<std::uint32_t>(y) > getHeight())
|
||||
return 0;
|
||||
if(_map == nullptr)
|
||||
openCPUmap();
|
||||
uint32_t color = _cpu_map[(y * getWidth()) + x];
|
||||
return (color);
|
||||
std::uint32_t color = _cpu_map[(y * getWidth()) + x];
|
||||
std::uint8_t* bytes = reinterpret_cast<std::uint8_t*>(&color);
|
||||
std::uint8_t tmp = bytes[0];
|
||||
bytes[0] = bytes[2];
|
||||
bytes[2] = tmp;
|
||||
return *reinterpret_cast<int*>(bytes);
|
||||
}
|
||||
|
||||
void Texture::openCPUmap()
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
if(_map != nullptr)
|
||||
return;
|
||||
|
||||
@@ -104,32 +128,43 @@ namespace mlx
|
||||
#endif
|
||||
Image::copyToBuffer(*_buf_map);
|
||||
_buf_map->mapMem(&_map);
|
||||
_cpu_map = std::vector<uint32_t>(getWidth() * getHeight(), 0);
|
||||
_cpu_map = std::vector<std::uint32_t>(getWidth() * getHeight(), 0);
|
||||
std::memcpy(_cpu_map.data(), _map, size);
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Texture : mapped CPU memory using staging buffer");
|
||||
#endif
|
||||
}
|
||||
|
||||
void Texture::render(Renderer& renderer, int x, int y)
|
||||
void Texture::render(std::array<VkDescriptorSet, 2>& sets, Renderer& renderer, int x, int y)
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
if(_has_been_modified)
|
||||
{
|
||||
std::memcpy(_map, _cpu_map.data(), _cpu_map.size() * formatSize(getFormat()));
|
||||
Image::copyFromBuffer(*_buf_map);
|
||||
_has_been_modified = false;
|
||||
}
|
||||
auto cmd = renderer.getActiveCmdBuffer().get();
|
||||
if(!_set.isInit())
|
||||
_set = renderer.getFragDescriptorSet().duplicate();
|
||||
if(getLayout() != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
transitionLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
if(!_has_set_been_updated)
|
||||
updateSet(0);
|
||||
auto cmd = renderer.getActiveCmdBuffer();
|
||||
_vbo.bind(renderer);
|
||||
_ibo.bind(renderer);
|
||||
glm::vec2 translate(x, y);
|
||||
vkCmdPushConstants(cmd, renderer.getPipeline().getPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(translate), &translate);
|
||||
vkCmdDrawIndexed(cmd, static_cast<uint32_t>(_ibo.getSize() / sizeof(uint16_t)), 1, 0, 0, 0);
|
||||
vkCmdPushConstants(cmd.get(), renderer.getPipeline().getPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(translate), &translate);
|
||||
sets[1] = _set.get();
|
||||
vkCmdBindDescriptorSets(renderer.getActiveCmdBuffer().get(), VK_PIPELINE_BIND_POINT_GRAPHICS, renderer.getPipeline().getPipelineLayout(), 0, sets.size(), sets.data(), 0, nullptr);
|
||||
vkCmdDrawIndexed(cmd.get(), static_cast<std::uint32_t>(_ibo.getSize() / sizeof(std::uint16_t)), 1, 0, 0, 0);
|
||||
}
|
||||
|
||||
void Texture::destroy() noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
Image::destroy();
|
||||
_set.destroy();
|
||||
if(_buf_map.has_value())
|
||||
_buf_map->destroy();
|
||||
_vbo.destroy();
|
||||
@@ -138,20 +173,23 @@ namespace mlx
|
||||
|
||||
Texture stbTextureLoad(std::filesystem::path file, int* w, int* h)
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
Texture texture;
|
||||
int channels;
|
||||
uint8_t* data = nullptr;
|
||||
std::uint8_t* data = nullptr;
|
||||
std::string filename = file.string();
|
||||
|
||||
if(!std::filesystem::exists(std::move(file)))
|
||||
core::error::report(e_kind::fatal_error, "Image : file not found '%s'", filename.c_str());
|
||||
if(stbi_is_hdr(filename.c_str()))
|
||||
core::error::report(e_kind::fatal_error, "Texture : unsupported image format '%s'", filename.c_str());
|
||||
data = stbi_load(filename.c_str(), w, h, &channels, 4);
|
||||
int dummy_w;
|
||||
int dummy_h;
|
||||
data = stbi_load(filename.c_str(), (w == nullptr ? &dummy_w : w), (h == nullptr ? &dummy_h : h), &channels, 4);
|
||||
#ifdef DEBUG
|
||||
texture.create(data, *w, *h, VK_FORMAT_R8G8B8A8_UNORM, filename.c_str());
|
||||
texture.create(data, (w == nullptr ? dummy_w : *w), (h == nullptr ? dummy_h : *h), VK_FORMAT_R8G8B8A8_UNORM, filename.c_str());
|
||||
#else
|
||||
texture.create(data, *w, *h, VK_FORMAT_R8G8B8A8_UNORM, nullptr);
|
||||
texture.create(data, (w == nullptr ? dummy_w : *w), (h == nullptr ? dummy_h : *h), VK_FORMAT_R8G8B8A8_UNORM, nullptr);
|
||||
#endif
|
||||
stbi_image_free(data);
|
||||
return texture;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/03/08 02:24:58 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/25 10:01:35 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/03/14 19:06:07 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -14,33 +14,35 @@
|
||||
#define __MLX_TEXTURE__
|
||||
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <renderer/images/vk_image.h>
|
||||
#include <renderer/descriptors/vk_descriptor_set.h>
|
||||
#include <renderer/buffers/vk_ibo.h>
|
||||
#include <renderer/buffers/vk_vbo.h>
|
||||
#include <mlx_profile.h>
|
||||
#ifdef DEBUG
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
class Texture : public Image
|
||||
class Texture : public Image
|
||||
{
|
||||
public:
|
||||
Texture() = default;
|
||||
|
||||
void create(uint8_t* pixels, uint32_t width, uint32_t height, VkFormat format, const char* name, bool dedicated_memory = false);
|
||||
void render(class Renderer& renderer, int x, int y);
|
||||
|
||||
void create(std::uint8_t* pixels, std::uint32_t width, std::uint32_t height, VkFormat format, const char* name, bool dedicated_memory = false);
|
||||
void render(std::array<VkDescriptorSet, 2>& sets, class Renderer& renderer, int x, int y);
|
||||
void destroy() noexcept override;
|
||||
|
||||
void setPixel(int x, int y, uint32_t color) noexcept;
|
||||
void setPixel(int x, int y, std::uint32_t color) noexcept;
|
||||
int getPixel(int x, int y) noexcept;
|
||||
|
||||
inline void setDescriptor(DescriptorSet set) noexcept { _set = std::move(set); }
|
||||
inline void setDescriptor(DescriptorSet&& set) noexcept { _set = set; }
|
||||
inline VkDescriptorSet getSet() noexcept { return _set.isInit() ? _set.get() : VK_NULL_HANDLE; }
|
||||
inline void updateSet(int binding) noexcept { _set.writeDescriptor(binding, getImageView(), getSampler()); _has_been_updated = true; }
|
||||
inline bool hasBeenUpdated() const noexcept { return _has_been_updated; }
|
||||
inline constexpr void resetUpdate() noexcept { _has_been_updated = false; }
|
||||
inline void updateSet(int binding) noexcept { _set.writeDescriptor(binding, *this); _has_set_been_updated = true; }
|
||||
inline bool hasBeenUpdated() const noexcept { return _has_set_been_updated; }
|
||||
inline constexpr void resetUpdate() noexcept { _has_set_been_updated = false; }
|
||||
|
||||
~Texture() = default;
|
||||
|
||||
@@ -54,37 +56,14 @@ namespace mlx
|
||||
std::string _name;
|
||||
#endif
|
||||
DescriptorSet _set;
|
||||
std::vector<uint32_t> _cpu_map;
|
||||
std::vector<std::uint32_t> _cpu_map;
|
||||
std::optional<Buffer> _buf_map = std::nullopt;
|
||||
void* _map = nullptr;
|
||||
bool _has_been_modified = false;
|
||||
bool _has_been_updated = false;
|
||||
bool _has_set_been_updated = false;
|
||||
};
|
||||
|
||||
Texture stbTextureLoad(std::filesystem::path file, int* w, int* h);
|
||||
|
||||
struct TextureRenderData
|
||||
{
|
||||
Texture* texture;
|
||||
std::size_t hash = 0;
|
||||
int x;
|
||||
int y;
|
||||
|
||||
TextureRenderData(Texture* _texture, int _x, int _y) : texture(_texture), x(_x), y(_y) {}
|
||||
bool operator==(const TextureRenderData& rhs) const { return texture == rhs.texture && x == rhs.x && y == rhs.y; }
|
||||
};
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct hash<mlx::TextureRenderData>
|
||||
{
|
||||
size_t operator()(const mlx::TextureRenderData& td) const noexcept
|
||||
{
|
||||
return std::hash<mlx::Texture*>()(td.texture) + std::hash<int>()(td.x) + std::hash<int>()(td.y);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/04/07 16:40:09 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/14 05:36:46 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/01/18 10:18:08 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -20,33 +20,37 @@
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
void TextureAtlas::create(uint8_t* pixels, uint32_t width, uint32_t height, VkFormat format, const char* name, bool dedicated_memory)
|
||||
void TextureAtlas::create(std::uint8_t* pixels, std::uint32_t width, std::uint32_t height, VkFormat format, const char* name, bool dedicated_memory)
|
||||
{
|
||||
Image::create(width, height, format, TILING, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, name, dedicated_memory);
|
||||
Image::createImageView(VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
Image::createSampler();
|
||||
transitionLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
||||
if(pixels != nullptr)
|
||||
if(pixels == nullptr)
|
||||
{
|
||||
Buffer staging_buffer;
|
||||
std::size_t size = width * height * formatSize(format);
|
||||
staging_buffer.create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, name, pixels);
|
||||
Image::copyFromBuffer(staging_buffer);
|
||||
staging_buffer.destroy();
|
||||
core::error::report(e_kind::warning, "Renderer : creating an empty texture atlas. They cannot be updated after creation, this might be a mistake or a bug, please report");
|
||||
return;
|
||||
}
|
||||
Buffer staging_buffer;
|
||||
std::size_t size = width * height * formatSize(format);
|
||||
staging_buffer.create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, name, pixels);
|
||||
Image::copyFromBuffer(staging_buffer);
|
||||
staging_buffer.destroy();
|
||||
}
|
||||
|
||||
void TextureAtlas::render(Renderer& renderer, int x, int y, uint32_t ibo_size)
|
||||
void TextureAtlas::render(Renderer& renderer, int x, int y, std::uint32_t ibo_size) const
|
||||
{
|
||||
auto cmd = renderer.getActiveCmdBuffer().get();
|
||||
|
||||
glm::vec2 translate(x, y);
|
||||
vkCmdPushConstants(cmd, renderer.getPipeline().getPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(translate), &translate);
|
||||
vkCmdDrawIndexed(cmd, ibo_size / sizeof(uint16_t), 1, 0, 0, 0);
|
||||
vkCmdDrawIndexed(cmd, ibo_size / sizeof(std::uint16_t), 1, 0, 0, 0);
|
||||
}
|
||||
|
||||
void TextureAtlas::destroy() noexcept
|
||||
{
|
||||
Image::destroy();
|
||||
_set.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/04/07 16:36:33 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/14 05:36:30 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/03/14 19:57:55 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
#define __MLX_TEXTURE_ATLAS__
|
||||
|
||||
#include <renderer/images/texture.h>
|
||||
#include <array>
|
||||
#include <glm/glm.hpp>
|
||||
#include <mlx_profile.h>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
@@ -24,18 +24,22 @@ namespace mlx
|
||||
public:
|
||||
TextureAtlas() = default;
|
||||
|
||||
void create(uint8_t* pixels, uint32_t width, uint32_t height, VkFormat format, const char* name, bool dedicated_memory = false);
|
||||
void render(class Renderer& renderer, int x, int y, uint32_t ibo_size);
|
||||
void create(std::uint8_t* pixels, std::uint32_t width, std::uint32_t height, VkFormat format, const char* name, bool dedicated_memory = false);
|
||||
void render(class Renderer& renderer, int x, int y, std::uint32_t ibo_size) const;
|
||||
void destroy() noexcept override;
|
||||
|
||||
inline void setDescriptor(DescriptorSet set) noexcept { _set = std::move(set); }
|
||||
inline VkDescriptorSet getSet() noexcept { return _set.isInit() ? _set.get() : VK_NULL_HANDLE; }
|
||||
inline void updateSet(int binding) noexcept { _set.writeDescriptor(binding, getImageView(), getSampler()); }
|
||||
inline void setDescriptor(DescriptorSet&& set) noexcept { _set = set; }
|
||||
inline VkDescriptorSet getVkSet() noexcept { return _set.isInit() ? _set.get() : VK_NULL_HANDLE; }
|
||||
inline DescriptorSet getSet() noexcept { return _set; }
|
||||
inline void updateSet(int binding) noexcept { _set.writeDescriptor(binding, *this); _has_been_updated = true; }
|
||||
inline bool hasBeenUpdated() const noexcept { return _has_been_updated; }
|
||||
inline constexpr void resetUpdate() noexcept { _has_been_updated = false; }
|
||||
|
||||
~TextureAtlas() = default;
|
||||
|
||||
private:
|
||||
DescriptorSet _set;
|
||||
bool _has_been_updated = false;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
59
src/renderer/images/texture_descriptor.h
git.filemode.normal_file
@@ -0,0 +1,59 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* texture_descriptor.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/01/11 01:00:13 by maldavid #+# #+# */
|
||||
/* Updated: 2024/01/11 01:21:52 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __MLX_TEXTURE_DESCRIPTOR__
|
||||
#define __MLX_TEXTURE_DESCRIPTOR__
|
||||
|
||||
#include <renderer/images/texture.h>
|
||||
#include <renderer/core/drawable_resource.h>
|
||||
#include <utils/combine_hash.h>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
struct TextureRenderDescriptor : public DrawableResource
|
||||
{
|
||||
Texture* texture;
|
||||
int x;
|
||||
int y;
|
||||
|
||||
TextureRenderDescriptor(Texture* _texture, int _x, int _y) : texture(_texture), x(_x), y(_y) {}
|
||||
inline bool operator==(const TextureRenderDescriptor& rhs) const { return texture == rhs.texture && x == rhs.x && y == rhs.y; }
|
||||
inline void render(std::array<VkDescriptorSet, 2>& sets, class Renderer& renderer) override
|
||||
{
|
||||
if(!texture->isInit())
|
||||
return;
|
||||
texture->render(sets, renderer, x, y);
|
||||
}
|
||||
inline void resetUpdate() override
|
||||
{
|
||||
if(!texture->isInit())
|
||||
return;
|
||||
texture->resetUpdate();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct hash<mlx::TextureRenderDescriptor>
|
||||
{
|
||||
std::size_t operator()(const mlx::TextureRenderDescriptor& d) const noexcept
|
||||
{
|
||||
std::size_t hash = 0;
|
||||
mlx::hashCombine(hash, d.texture, d.x, d.y);
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
67
src/renderer/images/texture_manager.h
git.filemode.normal_file
@@ -0,0 +1,67 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* texture_manager.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2024/01/11 00:56:15 by maldavid #+# #+# */
|
||||
/* Updated: 2024/03/25 13:53:59 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __MLX_TEXTURE_MANAGER__
|
||||
#define __MLX_TEXTURE_MANAGER__
|
||||
|
||||
#include <unordered_set>
|
||||
#include <renderer/images/texture_descriptor.h>
|
||||
#include <core/profiler.h>
|
||||
#include <utility>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
class TextureManager
|
||||
{
|
||||
public:
|
||||
TextureManager() = default;
|
||||
|
||||
inline void clear() { _texture_descriptors.clear(); }
|
||||
|
||||
inline std::pair<DrawableResource*, bool> registerTexture(Texture* texture, int x, int y)
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
auto res = _texture_descriptors.emplace(texture, x, y);
|
||||
return std::make_pair(static_cast<DrawableResource*>(&const_cast<TextureRenderDescriptor&>(*res.first)), res.second);
|
||||
}
|
||||
|
||||
inline bool isTextureKnown(Texture* texture) noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
for(const auto& desc : _texture_descriptors)
|
||||
{
|
||||
if(desc.texture == texture)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void eraseTextures(Texture* texture)
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
for(auto it = _texture_descriptors.begin(); it != _texture_descriptors.end();)
|
||||
{
|
||||
if(it->texture == texture)
|
||||
it = _texture_descriptors.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
~TextureManager() = default;
|
||||
|
||||
private:
|
||||
std::unordered_set<TextureRenderDescriptor> _texture_descriptors;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/01/25 11:59:07 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/18 17:21:14 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/03/14 17:28:25 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace mlx
|
||||
}
|
||||
}
|
||||
|
||||
VkFormat bitsToFormat(uint32_t bits)
|
||||
VkFormat bitsToFormat(std::uint32_t bits)
|
||||
{
|
||||
switch(bits)
|
||||
{
|
||||
@@ -99,44 +99,7 @@ namespace mlx
|
||||
return accessMask;
|
||||
}
|
||||
|
||||
VkPipelineStageFlags accessFlagsToPipelineStage(VkAccessFlags accessFlags, VkPipelineStageFlags stageFlags)
|
||||
{
|
||||
VkPipelineStageFlags stages = 0;
|
||||
|
||||
while(accessFlags != 0)
|
||||
{
|
||||
VkAccessFlagBits AccessFlag = static_cast<VkAccessFlagBits>(accessFlags & (~(accessFlags - 1)));
|
||||
if(AccessFlag == 0 || (AccessFlag & (AccessFlag - 1)) != 0)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : an error has been caught during access flag to pipeline stage operation");
|
||||
accessFlags &= ~AccessFlag;
|
||||
|
||||
switch(AccessFlag)
|
||||
{
|
||||
case VK_ACCESS_INDIRECT_COMMAND_READ_BIT: stages |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; break;
|
||||
case VK_ACCESS_INDEX_READ_BIT: stages |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; break;
|
||||
case VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT: stages |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; break;
|
||||
case VK_ACCESS_UNIFORM_READ_BIT: stages |= stageFlags | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; break;
|
||||
case VK_ACCESS_INPUT_ATTACHMENT_READ_BIT: stages |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; break;
|
||||
case VK_ACCESS_SHADER_READ_BIT: stages |= stageFlags | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; break;
|
||||
case VK_ACCESS_SHADER_WRITE_BIT: stages |= stageFlags | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; break;
|
||||
case VK_ACCESS_COLOR_ATTACHMENT_READ_BIT: stages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; break;
|
||||
case VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT: stages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; break;
|
||||
case VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT: stages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; break;
|
||||
case VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT: stages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; break;
|
||||
case VK_ACCESS_TRANSFER_READ_BIT: stages |= VK_PIPELINE_STAGE_TRANSFER_BIT; break;
|
||||
case VK_ACCESS_TRANSFER_WRITE_BIT: stages |= VK_PIPELINE_STAGE_TRANSFER_BIT; break;
|
||||
case VK_ACCESS_HOST_READ_BIT: stages |= VK_PIPELINE_STAGE_HOST_BIT; break;
|
||||
case VK_ACCESS_HOST_WRITE_BIT: stages |= VK_PIPELINE_STAGE_HOST_BIT; break;
|
||||
case VK_ACCESS_MEMORY_READ_BIT: break;
|
||||
case VK_ACCESS_MEMORY_WRITE_BIT: break;
|
||||
|
||||
default: core::error::report(e_kind::error, "Vulkan : unknown access flag"); break;
|
||||
}
|
||||
}
|
||||
return stages;
|
||||
}
|
||||
|
||||
void Image::create(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, const char* name, bool dedicated_memory)
|
||||
void Image::create(std::uint32_t width, std::uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, const char* name, bool dedicated_memory)
|
||||
{
|
||||
_width = width;
|
||||
_height = height;
|
||||
@@ -167,8 +130,9 @@ namespace mlx
|
||||
}
|
||||
|
||||
_allocation = Render_Core::get().getAllocator().createImage(&imageInfo, &alloc_info, _image, name);
|
||||
|
||||
_pool.init();
|
||||
#ifdef DEBUG
|
||||
_name = name;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Image::createImageView(VkImageViewType type, VkImageAspectFlags aspectFlags) noexcept
|
||||
@@ -184,8 +148,13 @@ namespace mlx
|
||||
viewInfo.subresourceRange.baseArrayLayer = 0;
|
||||
viewInfo.subresourceRange.layerCount = 1;
|
||||
|
||||
if(vkCreateImageView(Render_Core::get().getDevice().get(), &viewInfo, nullptr, &_image_view) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create an image view");
|
||||
VkResult res = vkCreateImageView(Render_Core::get().getDevice().get(), &viewInfo, nullptr, &_image_view);
|
||||
if(res != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create an image view, %s", RCore::verbaliseResultVk(res));
|
||||
#ifdef DEBUG
|
||||
else
|
||||
Render_Core::get().getLayers().setDebugUtilsObjectNameEXT(VK_OBJECT_TYPE_IMAGE_VIEW, (std::uint64_t)_image_view, _name.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
void Image::createSampler() noexcept
|
||||
@@ -203,161 +172,66 @@ namespace mlx
|
||||
info.anisotropyEnable = VK_FALSE;
|
||||
info.maxAnisotropy = 1.0f;
|
||||
|
||||
if(vkCreateSampler(Render_Core::get().getDevice().get(), &info, nullptr, &_sampler) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create an image");
|
||||
VkResult res = vkCreateSampler(Render_Core::get().getDevice().get(), &info, nullptr, &_sampler);
|
||||
if(res != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create an image sampler, %s", RCore::verbaliseResultVk(res));
|
||||
#ifdef DEBUG
|
||||
else
|
||||
Render_Core::get().getLayers().setDebugUtilsObjectNameEXT(VK_OBJECT_TYPE_SAMPLER, (std::uint64_t)_sampler, _name.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
void Image::copyFromBuffer(Buffer& buffer)
|
||||
{
|
||||
if(!_transfer_cmd.isInit())
|
||||
_transfer_cmd.init(&_pool);
|
||||
CmdBuffer& cmd = Render_Core::get().getSingleTimeCmdBuffer();
|
||||
cmd.beginRecord();
|
||||
|
||||
_transfer_cmd.reset();
|
||||
_transfer_cmd.beginRecord();
|
||||
VkImageLayout layout_save = _layout;
|
||||
transitionLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &cmd);
|
||||
|
||||
VkImageMemoryBarrier copy_barrier{};
|
||||
copy_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
copy_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
copy_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
copy_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
copy_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
copy_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
copy_barrier.image = _image;
|
||||
copy_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
copy_barrier.subresourceRange.levelCount = 1;
|
||||
copy_barrier.subresourceRange.layerCount = 1;
|
||||
vkCmdPipelineBarrier(_transfer_cmd.get(), VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, ©_barrier);
|
||||
cmd.copyBufferToImage(buffer, *this);
|
||||
|
||||
VkBufferImageCopy region{};
|
||||
region.bufferOffset = 0;
|
||||
region.bufferRowLength = 0;
|
||||
region.bufferImageHeight = 0;
|
||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.imageSubresource.mipLevel = 0;
|
||||
region.imageSubresource.baseArrayLayer = 0;
|
||||
region.imageSubresource.layerCount = 1;
|
||||
region.imageOffset = { 0, 0, 0 };
|
||||
region.imageExtent = { _width, _height, 1 };
|
||||
transitionLayout(layout_save, &cmd);
|
||||
|
||||
vkCmdCopyBufferToImage(_transfer_cmd.get(), buffer.get(), _image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||
|
||||
VkImageMemoryBarrier use_barrier{};
|
||||
use_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
use_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
use_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
use_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
use_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
use_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
use_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
use_barrier.image = _image;
|
||||
use_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
use_barrier.subresourceRange.levelCount = 1;
|
||||
use_barrier.subresourceRange.layerCount = 1;
|
||||
vkCmdPipelineBarrier(_transfer_cmd.get(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &use_barrier);
|
||||
|
||||
_transfer_cmd.endRecord();
|
||||
_transfer_cmd.submitIdle();
|
||||
cmd.endRecord();
|
||||
cmd.submitIdle();
|
||||
}
|
||||
|
||||
void Image::copyToBuffer(Buffer& buffer)
|
||||
{
|
||||
if(!_transfer_cmd.isInit())
|
||||
_transfer_cmd.init(&_pool);
|
||||
CmdBuffer& cmd = Render_Core::get().getSingleTimeCmdBuffer();
|
||||
cmd.beginRecord();
|
||||
|
||||
_transfer_cmd.reset();
|
||||
_transfer_cmd.beginRecord();
|
||||
VkImageLayout layout_save = _layout;
|
||||
transitionLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &cmd);
|
||||
|
||||
VkImageMemoryBarrier copy_barrier{};
|
||||
copy_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
copy_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
copy_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
copy_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
copy_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
copy_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
copy_barrier.image = _image;
|
||||
copy_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
copy_barrier.subresourceRange.levelCount = 1;
|
||||
copy_barrier.subresourceRange.layerCount = 1;
|
||||
vkCmdPipelineBarrier(_transfer_cmd.get(), VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, ©_barrier);
|
||||
cmd.copyImagetoBuffer(*this, buffer);
|
||||
|
||||
VkBufferImageCopy region{};
|
||||
region.bufferOffset = 0;
|
||||
region.bufferRowLength = 0;
|
||||
region.bufferImageHeight = 0;
|
||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.imageSubresource.mipLevel = 0;
|
||||
region.imageSubresource.baseArrayLayer = 0;
|
||||
region.imageSubresource.layerCount = 1;
|
||||
region.imageOffset = { 0, 0, 0 };
|
||||
region.imageExtent = { _width, _height, 1 };
|
||||
transitionLayout(layout_save, &cmd);
|
||||
|
||||
vkCmdCopyImageToBuffer(_transfer_cmd.get(), _image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer.get(), 1, ®ion);
|
||||
|
||||
VkImageMemoryBarrier use_barrier{};
|
||||
use_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
use_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
use_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
use_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
use_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
use_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
use_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
use_barrier.image = _image;
|
||||
use_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
use_barrier.subresourceRange.levelCount = 1;
|
||||
use_barrier.subresourceRange.layerCount = 1;
|
||||
vkCmdPipelineBarrier(_transfer_cmd.get(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &use_barrier);
|
||||
|
||||
_transfer_cmd.endRecord();
|
||||
_transfer_cmd.submitIdle();
|
||||
cmd.endRecord();
|
||||
cmd.submitIdle();
|
||||
}
|
||||
|
||||
void Image::transitionLayout(VkImageLayout new_layout)
|
||||
void Image::transitionLayout(VkImageLayout new_layout, CmdBuffer* cmd)
|
||||
{
|
||||
if(new_layout == _layout)
|
||||
return;
|
||||
|
||||
if(!_transfer_cmd.isInit())
|
||||
_transfer_cmd.init(&_pool);
|
||||
_transfer_cmd.reset();
|
||||
_transfer_cmd.beginRecord();
|
||||
bool singleTime = (cmd == nullptr);
|
||||
if(singleTime)
|
||||
{
|
||||
cmd = &Render_Core::get().getSingleTimeCmdBuffer();
|
||||
cmd->beginRecord();
|
||||
}
|
||||
|
||||
VkImageMemoryBarrier barrier{};
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier.oldLayout = _layout;
|
||||
barrier.newLayout = new_layout;
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.image = _image;
|
||||
barrier.subresourceRange.aspectMask = isDepthFormat(_format) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
barrier.subresourceRange.baseMipLevel = 0;
|
||||
barrier.subresourceRange.levelCount = 1;
|
||||
barrier.subresourceRange.baseArrayLayer = 0;
|
||||
barrier.subresourceRange.layerCount = 1;
|
||||
barrier.srcAccessMask = layoutToAccessMask(_layout, false);
|
||||
barrier.dstAccessMask = layoutToAccessMask(new_layout, true);
|
||||
if(isStencilFormat(_format))
|
||||
barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
cmd->transitionImageLayout(*this, new_layout);
|
||||
|
||||
VkPipelineStageFlags sourceStage = 0;
|
||||
if(barrier.oldLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
|
||||
sourceStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
else if(barrier.srcAccessMask != 0)
|
||||
sourceStage = accessFlagsToPipelineStage(barrier.srcAccessMask, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
else
|
||||
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
|
||||
VkPipelineStageFlags destinationStage = 0;
|
||||
if(barrier.newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
|
||||
destinationStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
else if(barrier.dstAccessMask != 0)
|
||||
destinationStage = accessFlagsToPipelineStage(barrier.dstAccessMask, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
else
|
||||
destinationStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
|
||||
vkCmdPipelineBarrier(_transfer_cmd.get(), sourceStage, destinationStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
|
||||
_transfer_cmd.endRecord();
|
||||
_transfer_cmd.submitIdle();
|
||||
if(singleTime)
|
||||
{
|
||||
cmd->endRecord();
|
||||
cmd->submitIdle();
|
||||
}
|
||||
_layout = new_layout;
|
||||
}
|
||||
|
||||
@@ -379,14 +253,13 @@ namespace mlx
|
||||
{
|
||||
destroySampler();
|
||||
destroyImageView();
|
||||
destroyCmdPool();
|
||||
|
||||
if(_image != VK_NULL_HANDLE)
|
||||
Render_Core::get().getAllocator().destroyImage(_allocation, _image);
|
||||
_image = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
uint32_t formatSize(VkFormat format)
|
||||
std::uint32_t formatSize(VkFormat format)
|
||||
{
|
||||
switch(format)
|
||||
{
|
||||
|
||||
@@ -6,75 +6,85 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/01/25 11:54:21 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/18 17:10:05 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/01/19 06:10:15 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef __MLX_VK_IMAGE__
|
||||
#define __MLX_VK_IMAGE__
|
||||
|
||||
#include <mlx_profile.h>
|
||||
#include <volk.h>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
#include <vma.h>
|
||||
#include <renderer/core/cmd_resource.h>
|
||||
#include <renderer/command/vk_cmd_buffer.h>
|
||||
#include <renderer/command/vk_cmd_pool.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
uint32_t formatSize(VkFormat format);
|
||||
std::uint32_t formatSize(VkFormat format);
|
||||
bool isStencilFormat(VkFormat format);
|
||||
bool isDepthFormat(VkFormat format);
|
||||
VkFormat bitsToFormat(std::uint32_t bits);
|
||||
VkPipelineStageFlags layoutToAccessMask(VkImageLayout layout, bool isDestination);
|
||||
|
||||
class Image
|
||||
class Image : public CmdResource
|
||||
{
|
||||
friend class SwapChain;
|
||||
|
||||
public:
|
||||
Image() = default;
|
||||
|
||||
inline void create(VkImage image, VkFormat format, uint32_t width, uint32_t height, VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED) noexcept
|
||||
inline void create(VkImage image, VkFormat format, std::uint32_t width, std::uint32_t height, VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED) noexcept
|
||||
{
|
||||
_image = image;
|
||||
_format = format;
|
||||
_width = width;
|
||||
_height = height;
|
||||
_layout = layout;
|
||||
_pool.init();
|
||||
}
|
||||
void create(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, const char* name, bool decated_memory = false);
|
||||
void create(std::uint32_t width, std::uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, const char* name, bool decated_memory = false);
|
||||
void createImageView(VkImageViewType type, VkImageAspectFlags aspectFlags) noexcept;
|
||||
void createSampler() noexcept;
|
||||
void copyFromBuffer(class Buffer& buffer);
|
||||
void copyToBuffer(class Buffer& buffer);
|
||||
void transitionLayout(VkImageLayout new_layout);
|
||||
void transitionLayout(VkImageLayout new_layout, CmdBuffer* cmd = nullptr);
|
||||
virtual void destroy() noexcept;
|
||||
|
||||
inline VkImage get() noexcept { return _image; }
|
||||
inline VkImage operator()() noexcept { return _image; }
|
||||
inline VkImageView getImageView() noexcept { return _image_view; }
|
||||
inline VkFormat getFormat() noexcept { return _format; }
|
||||
inline VkImageTiling getTiling() noexcept { return _tiling; }
|
||||
inline VkSampler getSampler() noexcept { return _sampler; }
|
||||
inline uint32_t getWidth() const noexcept { return _width; }
|
||||
inline uint32_t getHeight() const noexcept { return _height; }
|
||||
inline VkImageView getImageView() const noexcept { return _image_view; }
|
||||
inline VkFormat getFormat() const noexcept { return _format; }
|
||||
inline VkImageTiling getTiling() const noexcept { return _tiling; }
|
||||
inline VkImageLayout getLayout() const noexcept { return _layout; }
|
||||
inline VkSampler getSampler() const noexcept { return _sampler; }
|
||||
inline std::uint32_t getWidth() const noexcept { return _width; }
|
||||
inline std::uint32_t getHeight() const noexcept { return _height; }
|
||||
inline bool isInit() const noexcept { return _image != VK_NULL_HANDLE; }
|
||||
|
||||
virtual ~Image() = default;
|
||||
|
||||
private:
|
||||
void destroySampler() noexcept;
|
||||
void destroyImageView() noexcept;
|
||||
inline void destroyCmdPool() noexcept { _transfer_cmd.destroy(); _pool.destroy(); }
|
||||
|
||||
private:
|
||||
CmdBuffer _transfer_cmd;
|
||||
CmdPool _pool;
|
||||
VmaAllocation _allocation;
|
||||
VkImage _image = VK_NULL_HANDLE;
|
||||
VkImageView _image_view = VK_NULL_HANDLE;
|
||||
VkSampler _sampler = VK_NULL_HANDLE;
|
||||
#ifdef DEBUG
|
||||
std::string _name;
|
||||
#endif
|
||||
VkFormat _format;
|
||||
VkImageTiling _tiling;
|
||||
VkImageLayout _layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
uint32_t _width = 0;
|
||||
uint32_t _height = 0;
|
||||
std::uint32_t _width = 0;
|
||||
std::uint32_t _height = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/12/18 21:27:38 by maldavid #+# #+# */
|
||||
/* Updated: 2023/11/25 10:23:20 by maldavid ### ########.fr */
|
||||
/* Updated: 2024/03/14 17:05:21 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace mlx
|
||||
gl_Position = uProj.mat * vec4(pos.x, pos.y, 0.0, 1.0);
|
||||
}
|
||||
*/
|
||||
const std::vector<uint32_t> vertex_shader = {
|
||||
const std::vector<std::uint32_t> vertex_shader = { // precompiled vertex shader
|
||||
0x07230203,0x00010000,0x0008000b,0x0000003b,0x00000000,0x00020011,0x00000001,0x0006000b,
|
||||
0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
|
||||
0x000a000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000b,0x0000000f,0x00000015,
|
||||
@@ -124,7 +124,7 @@ namespace mlx
|
||||
fColor = process_color;
|
||||
}
|
||||
*/
|
||||
const std::vector<uint32_t> fragment_shader = {
|
||||
const std::vector<std::uint32_t> fragment_shader = { // pre compiled fragment shader
|
||||
0x07230203,0x00010000,0x0008000b,0x0000002c,0x00000000,0x00020011,0x00000001,0x0006000b,
|
||||
0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
|
||||
0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x0000000d,0x0000002a,0x00030010,
|
||||
@@ -164,7 +164,7 @@ namespace mlx
|
||||
{
|
||||
VkShaderModuleCreateInfo createInfo{};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
createInfo.codeSize = vertex_shader.size() * sizeof(uint32_t);
|
||||
createInfo.codeSize = vertex_shader.size() * sizeof(std::uint32_t);
|
||||
createInfo.pCode = vertex_shader.data();
|
||||
VkShaderModule vshader;
|
||||
if(vkCreateShaderModule(Render_Core::get().getDevice().get(), &createInfo, nullptr, &vshader) != VK_SUCCESS)
|
||||
@@ -176,7 +176,7 @@ namespace mlx
|
||||
push_constant.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
createInfo.codeSize = fragment_shader.size() * sizeof(uint32_t);
|
||||
createInfo.codeSize = fragment_shader.size() * sizeof(std::uint32_t);
|
||||
createInfo.pCode = fragment_shader.data();
|
||||
VkShaderModule fshader;
|
||||
if(vkCreateShaderModule(Render_Core::get().getDevice().get(), &createInfo, nullptr, &fshader) != VK_SUCCESS)
|
||||
@@ -203,7 +203,7 @@ namespace mlx
|
||||
vertexInputStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||
vertexInputStateCreateInfo.vertexBindingDescriptionCount = 1;
|
||||
vertexInputStateCreateInfo.pVertexBindingDescriptions = &bindingDescription;
|
||||
vertexInputStateCreateInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(attributeDescriptions.size());
|
||||
vertexInputStateCreateInfo.vertexAttributeDescriptionCount = static_cast<std::uint32_t>(attributeDescriptions.size());
|
||||
vertexInputStateCreateInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
|
||||
@@ -213,7 +213,7 @@ namespace mlx
|
||||
|
||||
VkDynamicState states[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
|
||||
|
||||
constexpr size_t statesCount = sizeof(states) / sizeof(VkDynamicState);
|
||||
constexpr std::size_t statesCount = sizeof(states) / sizeof(VkDynamicState);
|
||||
VkPipelineDynamicStateCreateInfo dynamicStates{};
|
||||
dynamicStates.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||
dynamicStates.dynamicStateCount = statesCount;
|
||||
@@ -222,14 +222,14 @@ namespace mlx
|
||||
VkViewport viewport{};
|
||||
viewport.x = 0.0f;
|
||||
viewport.y = 0.0f;
|
||||
viewport.width = (float)renderer.getSwapChain().getExtent().width;
|
||||
viewport.height = (float)renderer.getSwapChain().getExtent().height;
|
||||
viewport.width = (float)renderer.getFrameBuffer(0).getWidth();
|
||||
viewport.height = (float)renderer.getFrameBuffer(0).getHeight();
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 1.0f;
|
||||
|
||||
VkRect2D scissor{};
|
||||
scissor.offset = { 0, 0 };
|
||||
scissor.extent = renderer.getSwapChain().getExtent();
|
||||
scissor.extent = { renderer.getFrameBuffer(0).getWidth(), renderer.getFrameBuffer(0).getHeight()};
|
||||
|
||||
VkPipelineViewportStateCreateInfo viewportState{};
|
||||
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||
@@ -286,7 +286,7 @@ namespace mlx
|
||||
pipelineLayoutInfo.pushConstantRangeCount = 1;
|
||||
pipelineLayoutInfo.pPushConstantRanges = &push_constant;
|
||||
|
||||
if(vkCreatePipelineLayout(Render_Core::get().getDevice().get(), &pipelineLayoutInfo, nullptr, &_pipelineLayout) != VK_SUCCESS)
|
||||
if(vkCreatePipelineLayout(Render_Core::get().getDevice().get(), &pipelineLayoutInfo, nullptr, &_pipeline_layout) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create a graphics pipeline layout");
|
||||
|
||||
VkGraphicsPipelineCreateInfo pipelineInfo{};
|
||||
@@ -300,13 +300,14 @@ namespace mlx
|
||||
pipelineInfo.pMultisampleState = &multisampling;
|
||||
pipelineInfo.pColorBlendState = &colorBlending;
|
||||
pipelineInfo.pDynamicState = &dynamicStates;
|
||||
pipelineInfo.layout = _pipelineLayout;
|
||||
pipelineInfo.layout = _pipeline_layout;
|
||||
pipelineInfo.renderPass = renderer.getRenderPass().get();
|
||||
pipelineInfo.subpass = 0;
|
||||
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
|
||||
|
||||
if(vkCreateGraphicsPipelines(Render_Core::get().getDevice().get(), VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &_graphicsPipeline) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create a graphics pipeline");
|
||||
VkResult res = vkCreateGraphicsPipelines(Render_Core::get().getDevice().get(), VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &_graphics_pipeline);
|
||||
if(res != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create a graphics pipeline, %s", RCore::verbaliseResultVk(res));
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : created new graphic pipeline");
|
||||
#endif
|
||||
@@ -317,7 +318,11 @@ namespace mlx
|
||||
|
||||
void GraphicPipeline::destroy() noexcept
|
||||
{
|
||||
vkDestroyPipeline(Render_Core::get().getDevice().get(), _graphicsPipeline, nullptr);
|
||||
vkDestroyPipelineLayout(Render_Core::get().getDevice().get(), _pipelineLayout, nullptr);
|
||||
vkDestroyPipeline(Render_Core::get().getDevice().get(), _graphics_pipeline, nullptr);
|
||||
vkDestroyPipelineLayout(Render_Core::get().getDevice().get(), _pipeline_layout, nullptr);
|
||||
_graphics_pipeline = VK_NULL_HANDLE;
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : destroyed a graphics pipeline");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||