170 Commits

Author SHA1 Message Date
kbz_8
fcf4d3d030 improving descriptor sets and pools management (#41) 2024-01-20 08:53:13 +01:00
Kbz-8
05362905f7 improving descriptor sets and pools management 2024-01-20 08:46:50 +01:00
kbz_8
6866f2240e adding fps capper (#40) 2024-01-18 15:31:37 +01:00
kbz_8
1903104247 Merge branch 'master' into indev 2024-01-18 15:28:20 +01:00
Kbz-8
04db0a7441 adding fps capper 2024-01-18 15:25:13 +01:00
kbz_8
91cbb15b66 fixing texts allocation issues (#39) 2024-01-18 14:23:05 +01:00
kbz_8
eeded8c8bc Merge branch 'master' into indev 2024-01-18 13:59:37 +01:00
Kbz-8
58e687c952 fixing allocation issues with texts 2024-01-18 13:57:41 +01:00
Kbz-8
a0b536483a fixing shit 2024-01-17 07:41:15 +01:00
Kbz-8
de1e8ed563 i dont know chat i did i was high as f*ck 2024-01-17 05:30:38 +01:00
Kbz-8
a832c3ca40 fixing issue with swapchain recreation 2024-01-16 07:19:27 +01:00
kbz_8
575ee21c7a oh the misery (#38)
Fixed a bug and modified the example/main.c to test all mlx functions 

![image](https://github.com/seekrs/MacroLibX/assets/105780726/d9946f1f-4e97-453f-87a6-953ffd0ad52d)
2024-01-12 14:56:14 +01:00
Namonay
071bc4596b upgraded example to test all mlx functions 2024-01-12 04:25:12 +01:00
Namonay
178690cff3 Fixed mlx_mouse_move() not updating mouse position
Removed SDL_FlushEvent(SDL_MOUSEMOTION) preventing Input::update() from catching new mouse position after a mlx_mouse_move() call
2024-01-12 04:24:24 +01:00
kbz_8
1d566f74e3 Preventing some segfaults (#37)
![nerd](https://github.com/seekrs/MacroLibX/assets/105780726/74152e81-029a-4f35-afda-11e6411646bf)
2024-01-12 01:51:51 +01:00
Namonay
eaa1b9afd0 Merge branch 'seekrs:indev' into indev 2024-01-12 01:28:25 +01:00
Namonay
a2d40ce844 Added protections to THE bridge 2024-01-12 01:27:02 +01:00
Kbz-8
4dcdcde7d5 improving vsupp 2024-01-12 00:49:42 +01:00
kbz_8
8805f91bfd Indev (#36) 2024-01-11 15:53:39 +01:00
kbz_8
b5ca757189 Merge branch 'master' into indev 2024-01-11 15:48:15 +01:00
Kbz-8
c2d27c8434 fixing compilation error 2024-01-11 15:47:45 +01:00
Kbz-8
5f55dd9b9a fixing vsupp missing character 2024-01-11 15:46:11 +01:00
kbz_8
f044b9ab45 merge indev to master (#35) 2024-01-11 05:32:13 +01:00
kbz_8
8c6ad92f37 Merge branch 'master' into indev 2024-01-11 05:27:21 +01:00
Kbz-8
34bdb740c2 new text management, texts and textures are on the same level, new texture rendering management, fixing issues 2024-01-11 05:23:16 +01:00
Kbz-8
c485f039fb fixing color management issue with texts 2024-01-10 20:22:53 +01:00
Kbz-8
3c60e76094 adding xmake profiler option 2024-01-10 18:49:54 +01:00
kbz_8
39650b5c96 adding profiler (#34) 2024-01-10 18:48:52 +01:00
Kbz-8
0f16255240 fixing windows compilation issue 2024-01-10 18:37:14 +01:00
Kbz-8
91661fd206 adding profiler 2024-01-10 18:32:40 +01:00
kbz_8
6648bd427f Indev (#33)
Indev
2024-01-09 01:42:36 +01:00
Namonay
aa2d0be63f added back not so much 'unnecesary' include 2024-01-09 01:37:01 +01:00
Namonay
2b557d5be7 removed useless includes 🤓 2024-01-09 01:28:50 +01:00
Namonay
36fae5c7d1 update buid.sh 2024-01-09 01:01:31 +01:00
Namonay
68570910e3 Fixed brief typo 2024-01-09 00:31:39 +01:00
Kbz-8
697a5e7147 fixing norme issue in the example 2024-01-09 00:25:23 +01:00
Kbz-8
31073c116c fixing issue with vulkan queues on multiple GPU computers 2024-01-08 23:50:00 +01:00
Kbz-8
c6a024d911 fixing issue with fonts vulkan descriptor destroyed 2024-01-08 22:18:45 +01:00
kbz_8
66a1b44224 Better vk commands management (#31) 2024-01-07 01:49:40 +01:00
Kbz-8
f5c581d89c figin another MacOS compilation error 2024-01-07 01:45:12 +01:00
Kbz-8
765a04d9b5 fixing compilation issues 2024-01-07 01:40:19 +01:00
Kbz-8
ac054830b9 removing gdb garbage file 2024-01-07 01:35:18 +01:00
Kbz-8
ccbd7561f4 fixing better vk command buffers management 2024-01-07 01:34:02 +01:00
kbz_8
2859725257 update dependencies (#30)
Automated changes by
[create-pull-request](https://github.com/peter-evans/create-pull-request)
GitHub action
2024-01-06 14:09:23 +01:00
Kbz-8
f18cce29b3 [BOT] update dependencies 2024-01-06 01:06:21 +00:00
Kbz-8
d9a7f337ba working on cmd resources management 2024-01-05 23:13:35 +01:00
Kbz-8
f8e619ad94 fixing 32bit vulkan issue 2024-01-04 12:27:31 +01:00
kbz_8
ea6450b308 yes (#29) 2024-01-03 15:49:18 +01:00
kbz_8
6df9c284b8 Merge branch 'better_vk_commands' into indev 2024-01-03 15:47:31 +01:00
Kbz-8
d6b3f5dcc2 fixing gitignore file 2024-01-03 15:45:24 +01:00
kbz_8
826740906f merge Indev to master (#28) 2024-01-03 15:38:38 +01:00
Kbz-8
2c1f5181bf fixing compilation issue 2024-01-03 15:33:46 +01:00
Kbz-8
e728926521 fixing windows compilation issue 2024-01-03 15:30:35 +01:00
kbz_8
04af533469 Merge branch 'master' into indev 2024-01-03 15:17:17 +01:00
Kbz-8
53048bd82a improving vulkan error messages 2024-01-03 15:15:38 +01:00
Kbz-8
d0a19c5312 adding greetings 2024-01-03 00:30:45 +01:00
Kbz-8
6e284fb9bc fixing the workflows 2024-01-03 00:07:38 +01:00
Kbz-8
ea87c32051 updating license year, fixing fetch dependencies script, adding VMA auto update, removing useless dependency in xmake build 2024-01-03 00:01:30 +01:00
kbz_8
d73ade4a85 Update fetch_dependencies.yml (#27) 2024-01-02 12:04:00 +01:00
kbz_8
67bfc73066 Merge branch 'master' into indev 2024-01-02 11:56:57 +01:00
kbz_8
8b44a3aa6e Update fetch_dependencies.yml 2024-01-02 11:56:10 +01:00
kbz_8
36f9fdd53b merge Indev to master (#26) 2024-01-02 11:46:45 +01:00
kbz_8
9c43069e5f debug fetch_dependencies.yml 2024-01-02 11:28:11 +01:00
Kbz-8
0b6e1717d9 adding note to README 2023-12-31 14:34:52 +01:00
Kbz-8
41f7b4ef4c working automated dependencies updates, polishing the CI 2023-12-31 14:17:24 +01:00
kbz_8
418791930c update dependencies (#25)
Automated changes by
[create-pull-request](https://github.com/peter-evans/create-pull-request)
GitHub action
2023-12-31 13:48:27 +01:00
Kbz-8
0690ecacd8 debugging CI 2023-12-31 13:47:56 +01:00
Kbz-8
36f7efb679 update dependencies 2023-12-31 12:47:00 +00:00
Kbz-8
a52e33e697 debugging CI 2023-12-31 13:46:45 +01:00
Kbz-8
086c5402f5 debugging CI 2023-12-31 13:45:25 +01:00
Kbz-8
dd1bd43360 debugging CI 2023-12-31 13:44:37 +01:00
Kbz-8
d515ca5333 debugging CI 2023-12-31 13:41:09 +01:00
Kbz-8
eeb4695d6c debugging CI 2023-12-31 13:34:11 +01:00
Kbz-8
e94d3fd70f debugging CI 2023-12-31 13:31:22 +01:00
Kbz-8
e76f084625 debugging CI 2023-12-31 13:30:32 +01:00
Kbz-8
6e1fcb381a fixing compilation errors with local vulkan headers 2023-12-31 13:21:40 +01:00
Kbz-8
52c309a288 test automated dependencies updates 2023-12-31 13:12:37 +01:00
kbz_8
9ad28d7cf2 Kbz 8 patch 1 (#23) 2023-12-31 11:57:44 +01:00
kbz_8
5f21f0bcf9 Create dependabot.yml 2023-12-31 11:57:19 +01:00
kbz_8
066eec2cf3 merge Indev to master (#22)
yes
2023-12-31 01:41:39 +01:00
kbz_8
03e21227fa Merge branch 'master' into indev 2023-12-31 01:38:11 +01:00
Kbz-8
6f05728906 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH x2 2023-12-31 01:30:17 +01:00
Kbz-8
5edc36393a AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH 2023-12-31 01:27:37 +01:00
Kbz-8
af29fc7b39 I hate SDL_main on windows 2023-12-31 01:24:10 +01:00
Kbz-8
9795988e14 fuck SDL_main on windows 2023-12-31 01:14:17 +01:00
Kbz-8
4087fca980 fixing SDL issue on windows 2023-12-31 01:08:41 +01:00
Kbz-8
f3efb72a21 adding transparency support to pixel put 2023-12-28 16:59:36 +01:00
kbz_8
fc97445875 Update xmake.lua 2023-12-28 01:13:40 +01:00
Kbz-8
5babfde870 fixing issue when creating multiple mlx application with leaks in the first one 2023-12-28 01:06:03 +01:00
kbz_8
04ffce60cd adding frame capture feature (#21) 2023-12-25 16:18:42 +01:00
Kbz-8
9aaa26ddf5 fixing frame capture 2023-12-24 16:07:09 +01:00
Kbz-8
df12d08ad3 working on frame capture 2023-12-23 01:53:54 +01:00
Kbz-8
064f660852 adding possible new feature 2023-12-22 23:21:24 +01:00
Kbz-8
bf6389f9a7 adding CONTRIBUTIN.md 2023-12-22 01:24:55 +01:00
Kbz-8
cae3db0ebf fixing issue with static casts 2023-12-22 00:45:06 +01:00
Kbz-8
79b01a5007 adding error messages when using a corrupted window pointer, dropping SDL init responsability when running in sandbox 2023-12-21 00:28:53 +01:00
kbz_8
91927126f2 merge indev to master (#20) 2023-12-20 17:50:38 +01:00
kbz_8
6fb8932ba9 Merge branch 'master' into indev 2023-12-20 17:38:06 +01:00
Kbz-8
536cf4c420 working on better command buffers management 2023-12-20 16:35:52 +01:00
kbz_8
1b49794be6 Change github links to reflect organisation change (#19) 2023-12-20 01:03:42 +01:00
xtrm
25f73a6967 🐛 fix: change github links to reflect organisation change
Signed-off-by: xtrm <oss@xtrm.me>
2023-12-20 00:58:24 +01:00
kbz_8
b7424e7f92 Merge pull request #18 from 420verfl0w/errors-everywhere
Errors everywhere
2023-12-16 20:32:04 +01:00
Kbz-8
0b4b32b5ac removing GCC error 2023-12-16 20:20:51 +01:00
Kbz-8
1922b409dd adding error checks 2023-12-16 20:17:49 +01:00
Kbz-8
80e938c019 new branch for error management 2023-12-16 18:51:51 +01:00
Kbz-8
68d2c63694 fixing compilation error 2023-12-16 02:14:23 +01:00
Kbz-8
1386fe64cb updating readme 2023-12-16 02:11:54 +01:00
kbz_8
7fd0ccff94 Merge pull request #17 from 420verfl0w/indev
merge dev to master
2023-12-15 21:13:53 +01:00
Kbz-8
b28b144edb fixing issue when destroying an image in the loop hook, begenning single time command buffers manager 2023-12-15 21:08:46 +01:00
Kbz-8
8e33b2fa30 updating README 2023-12-15 18:08:22 +01:00
kbz_8
cebadef063 Merge pull request #16 from 420verfl0w/multiple-fonts
merge Multiple fonts in dev
2023-12-14 20:12:44 +01:00
kbz_8
57b27adf1a Merge branch 'indev' into multiple-fonts 2023-12-14 19:21:12 +01:00
Kbz-8
d08a97f55c adding multiple font support 2023-12-14 19:13:41 +01:00
kbz_8
c7ad6650d9 Merge pull request #15 from 420verfl0w/indev
removing buggy texture hash system
2023-12-14 14:44:10 +01:00
Kbz-8
ac91253f51 removing buggy texture hash system 2023-12-14 14:39:00 +01:00
kbz_8
3d939675e4 Merge pull request #14 from 420verfl0w/indev
merge dev to master
2023-12-14 13:56:28 +01:00
Kbz-8
11b1bd147d fixing issues with texture rendering 2023-12-14 13:51:17 +01:00
Kbz-8
c013237219 yes 2023-12-14 00:08:38 +01:00
kbz_8
8039638885 removed garbage file 2023-12-13 16:06:43 +01:00
Kbz-8
d56b224d42 working on font system 2023-12-13 00:33:34 +01:00
kbz_8
6ccf2a10d7 Merge pull request #13 from 420verfl0w/indev
Indev
2023-12-12 18:49:48 +01:00
kbz_8
cfd1aab9e3 Merge pull request #12 from 420verfl0w/macos-debug
Macos debug
2023-12-12 18:21:36 +01:00
Kbz-8
c5752f773e fixing CI 2023-12-12 18:12:41 +01:00
Kbz-8
f398126e08 fixing CI 2023-12-12 18:07:58 +01:00
Kbz-8
6c0d8829a5 macos debug 2023-12-12 18:04:27 +01:00
Kbz-8
cf3f16d832 macos debug 2023-12-12 17:58:49 +01:00
Kbz-8
b60ae54e34 macos debug 2023-12-12 17:47:10 +01:00
Kbz-8
7786b07eb8 adding message when vk res init fails 2023-12-12 15:53:57 +01:00
Kbz-8
90b1dac0f5 adding message when instance init fails 2023-12-12 15:46:47 +01:00
Kbz-8
3c52fd05f3 fixing run file and lib name on macos 2023-12-12 13:27:19 +01:00
Kbz-8
843d7f0fe2 removing unused files 2023-12-12 13:08:34 +01:00
Kbz-8
ea2014819d fxing macos libraries location issue 2023-12-12 13:08:00 +01:00
kbz_8
e458ef6401 Merge pull request #11 from 420verfl0w/indev
merge dev to master
2023-12-11 23:53:56 +01:00
kbz_8
0494ff14da Merge pull request #10 from 420verfl0w/indev
Indev
2023-12-11 20:41:15 +01:00
Kbz-8
c2c2dece61 fixing DLL API import error 2023-12-11 20:36:21 +01:00
Kbz-8
401e6d13f3 moving profile to API scope 2023-12-11 20:28:58 +01:00
kbz_8
2e5346a0ff Merge pull request #8 from 420verfl0w/vsupp-debug
Vsupp debug
2023-12-11 19:36:32 +01:00
kbz_8
ce5157a299 Merge pull request #7 from 420verfl0w/malloc-custom
improving custom malloc, removing unused code in input system
2023-12-11 19:35:38 +01:00
Kbz-8
b5ce2347f6 improving custom malloc, removing unused code in input system 2023-12-11 19:30:37 +01:00
Kbz-8
9e0a0df5ca removing error 2023-12-11 13:53:40 +01:00
Kbz-8
8f6f50c37f fixing vsupp issue, cleaning it 2023-12-11 13:40:05 +01:00
Kbz-8
c36de40f4a fixing warning issue with clang 2023-12-10 23:15:59 +01:00
Kbz-8
52ca0c0d1b suppress warnings 2023-12-10 23:12:22 +01:00
kbz_8
651a05c4bc Merge pull request #6 from 420verfl0w/indev
merge Indev to master
2023-12-09 23:41:55 +01:00
Kbz-8
1cfb8745e2 updating readmes 2023-12-09 23:33:02 +01:00
Kbz-8
b3f3a01ee6 updating readmes 2023-12-09 23:18:28 +01:00
kbz_8
4acd240737 Merge pull request #5 from 420verfl0w/indev
merge Indev to master
2023-12-09 18:13:55 +01:00
Kbz-8
b79b8da031 improving vsupp file 2023-12-09 18:02:30 +01:00
Kbz-8
bc7ef4484f improving vsupp file 2023-12-09 16:23:38 +01:00
Kbz-8
9db5515fb5 adding vsupp file 2023-12-09 15:46:32 +01:00
kbz_8
387a1f5632 Merge pull request #4 from 420verfl0w/windows-support
Merge windows support into dev
2023-12-09 13:40:45 +01:00
Kbz-8
0babc2235f Merge branch 'windows-support' of github.com:420verfl0w/MacroLibX into windows-support 2023-12-09 13:25:30 +01:00
Kbz-8
1a9a6ec6f8 adding build readme for xmake, fixing windows workflow 2023-12-09 13:24:40 +01:00
kbz_8
d59d9f285a removing exe file 2023-12-08 23:34:19 +01:00
kbz_8
d16af1c4a8 fixing windows dll issues 2023-12-08 23:33:26 +01:00
Kbz-8
5dcc2045d6 adding symbols to dll on windows 2023-12-08 19:13:25 +01:00
Kbz-8
19ce912afe adding symbols to dll on windows 2023-12-08 18:56:33 +01:00
Kbz-8
890e301b78 fixing cross compilation issue 2023-12-08 18:09:08 +01:00
Kbz-8
218a97e4ec debugging windows CI 2023-12-08 16:37:42 +01:00
Kbz-8
74e5e35f5a debugging windows CI 2023-12-08 15:57:45 +01:00
Kbz-8
e6298b1dc3 fixing syntax error in windows workflow 2023-12-08 14:48:28 +01:00
Kbz-8
df860a5a64 removing garbage files 2023-12-08 14:12:41 +01:00
Kbz-8
b22064035a adding xmake support and windows workflow 2023-12-08 14:11:48 +01:00
kbz_8
197c71021b Merge pull request #3 from 420verfl0w/indev
Merge from dev to master
2023-12-08 13:00:24 +01:00
Kbz-8
d5fa70d7ab fixing issue in 42 header 2023-12-08 12:56:59 +01:00
Kbz-8
fd8e98f1ce adding mouse wheel support 2023-12-08 12:24:20 +01:00
Kbz-8
0e10e5f8e1 removing garbage files 2023-12-07 23:20:25 +01:00
Kbz-8
689c9b3ed4 fixing memory leaks, begenning xmake support to build on windows 2023-12-07 23:19:56 +01:00
Kbz-8
ecd43dedc5 fixing weird X in logo 2023-11-25 14:26:05 +01:00
kbz_8
dea507ec0e Update README.md 2023-11-25 13:13:57 +01:00
555 changed files with 295487 additions and 2211 deletions

11
.github/dependabot.yml vendored git.filemode.normal_file
View 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
View File

@@ -0,0 +1,29 @@
name: Fetch Dependencies
on:
schedule:
- cron: '0 0 * * *' # Runs daily
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@v5
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
View 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.

View File

@@ -35,8 +35,8 @@ jobs:
# Build the lib
- name: Build MacroLibX
run: make -j
run: make -j && make fclean && make -j DEBUG=true
# 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

View File

@@ -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=true -j
# 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

View File

@@ -41,9 +41,9 @@ jobs:
# Build the lib
- name: Build MacroLibX
run: make -j
run: make -j && make fclean && make DEBUG=true -j
# 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

63
.github/workflows/windows.yml vendored git.filemode.normal_file
View File

@@ -0,0 +1,63 @@
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
# Install system dependencies
- name: Install Vulkan SDK
uses: humbletim/install-vulkan-sdk@v1.1.1
with:
version: 1.3.204.1
cache: true
# 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

17
.gitignore vendored
View File

@@ -4,5 +4,20 @@
*.a
*.so
*.out
*.dll
*.lib
*.exp
*.json
*.tmp
*.ilk
*.pdb
*.exe
*vgcore
.gdb_history
.vs/
.xmake/
.cache/
test/.gdb_history
objs/
build/
example/.gdb_history
example/Test

17
CONTRIBUTING.md git.filemode.normal_file
View 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.

View File

@@ -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

View File

@@ -6,7 +6,7 @@
# By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2022/10/04 16:43:41 by maldavid #+# #+# #
# Updated: 2023/11/24 10:03:17 by maldavid ### ########.fr #
# Updated: 2024/01/10 14:20:30 by maldavid ### ########.fr #
# #
# **************************************************************************** #
@@ -17,7 +17,7 @@ SRCS += $(wildcard $(addsuffix /*.cpp, ./src/platform))
SRCS += $(wildcard $(addsuffix /*.cpp, ./src/renderer))
SRCS += $(wildcard $(addsuffix /*.cpp, ./src/renderer/**))
OBJ_DIR = objs
OBJ_DIR = objs/makefile
OBJS = $(addprefix $(OBJ_DIR)/, $(SRCS:.cpp=.o))
OS = $(shell uname -s)
@@ -26,22 +26,28 @@ TOOLCHAIN ?= clang
IMAGES_OPTIMIZED ?= true
FORCE_INTEGRATED_GPU ?= false
GRAPHICS_MEMORY_DUMP ?= false
PROFILER ?= false
MODE = "release"
CXX = clang++
ifeq ($(TOOLCHAIN), gcc)
CXX = g++
endif
CXXFLAGS = -std=c++17 -O3 -fPIC
CXXFLAGS = -std=c++17 -O3 -fPIC -Wall -Wextra -Werror -DSDL_MAIN_HANDLED
INCLUDES = -I./includes -I./src -I./third_party
LDLIBS =
ifeq ($(TOOLCHAIN), gcc)
CXX = g++
CXXFLAGS += -Wno-error=cpp
else
CXXFLAGS += -Wno-error=#warning
endif
ifeq ($(OS), Darwin)
LDLIBS += -lSDL2
LDLIBS += -L /opt/homebrew/lib -lSDL2
CXXFLAGS += -I /opt/homebrew/include
NAME = libmlx.dylib
endif
ifeq ($(DEBUG), true)
@@ -61,6 +67,10 @@ ifeq ($(GRAPHICS_MEMORY_DUMP), true)
CXXFLAGS += -D GRAPHICS_MEMORY_DUMP
endif
ifeq ($(PROFILER), true)
CXXFLAGS += -D PROFILER
endif
RM = rm -rf
$(OBJ_DIR)/%.o: %.cpp

View File

@@ -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
View 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>

File diff suppressed because it is too large Load Diff

BIN
example/42_logo.bmp git.filemode.normal_file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
example/42_logo.jpg git.filemode.normal_file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

12
example/build.sh git.filemode.executable_file
View 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

170
example/main.c git.filemode.normal_file
View File

@@ -0,0 +1,170 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* main.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/04 17:55:21 by maldavid #+# #+# */
/* Updated: 2024/01/19 05:34:23 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;
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(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_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
View File

@@ -0,0 +1,4 @@
#!/bin/bash
bash ./build.sh
./a.out

View File

@@ -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/01/18 14:36:12 by maldavid ### ########.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,8 @@ 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 Gives a function to be executed at each loop turn
@@ -56,8 +63,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 +73,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,21 +83,24 @@ 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
@@ -101,7 +112,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 +124,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 +138,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 +148,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 +167,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 +183,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 +205,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 +224,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 +235,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 +248,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 +261,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 +274,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 +284,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 +297,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 +325,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 +336,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 +345,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
}

215
includes/mlx_profile.h git.filemode.normal_file
View File

@@ -0,0 +1,215 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* 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");
#elif defined(MLX_COMPILER_GCC)
#define STATIC_ASSERT(cnd, descr) \
({ \
extern int __attribute__((error("static assert failed: (" #cnd ") (" #descr ")"))) compile_time_check(void); \
((cnd) ? 0 : compile_time_check()), 0; \
})
#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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
res/screenshot_test_windows.png git.filemode.normal_file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

31
scripts/fetch_dependencies.sh git.filemode.executable_file
View 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
View 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<uint64_t> uniform_distribution;
UUID::UUID() : _uuid(uniform_distribution(engine)) {}
UUID::UUID(uint64_t uuid) : _uuid(uuid) {}
}

33
src/core/UUID.h git.filemode.normal_file
View 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(uint64_t uuid);
inline operator uint64_t() const { return _uuid; }
private:
uint64_t _uuid;
};
}
#endif

View File

@@ -6,21 +6,34 @@
/* 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/01/20 08:21:37 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());
}
@@ -29,20 +42,29 @@ namespace mlx::core
{
while(_in->is_running())
{
if(!_fps.update())
continue;
_in->update();
for(auto& gs : _graphics)
gs->beginRender();
if(_loop_hook)
_loop_hook(_param);
for(auto& gs : _graphics)
gs->endRender();
gs->render();
}
Render_Core::get().getSingleTimeCmdManager().updateSingleTimesCmdBuffersSubmitState();
for(auto& gs : _graphics)
{
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 +75,34 @@ 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, "wrong texture (NULL)");
return;
}
Texture* texture = static_cast<Texture*>(ptr);
if(!texture->isInit())
core::error::report(e_kind::error, "trying to destroy a texture");
else
texture->destroy();
}
Application::~Application()
{
TextLibrary::get().clearLibrary();
FontLibrary::get().clearLibrary();
if(__drop_sdl_responsability)
return;
SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS);
SDL_Quit();
}
}

View File

@@ -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/01/18 14:59:47 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -24,6 +24,9 @@
#include <core/graphics.h>
#include <platform/inputs.h>
#include <mlx_profile.h>
#include <core/profiler.h>
#include <core/fps.h>
namespace mlx::core
{
@@ -37,14 +40,16 @@ 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(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 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 stringPut(void* win, int x, int y, 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, ...)
@@ -63,12 +68,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;
};
}

View File

@@ -12,6 +12,18 @@
#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 {}\
namespace mlx::core
{
void Application::getMousePos(int* x, int* y) noexcept
@@ -22,71 +34,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::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(uint32_t fps) noexcept
{
_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
{
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, 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);
if(img == nullptr)
{
core::error::report(e_kind::error, "wrong texture (NULL)");
return;
}
Texture* texture = static_cast<Texture*>(img);
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();
if(img == nullptr)
{
core::error::report(e_kind::error, "wrong texture (NULL)");
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)
{
MLX_PROFILE_FUNCTION();
if(img == nullptr)
{
core::error::report(e_kind::error, "wrong texture (NULL)");
return;
}
Texture* texture = static_cast<Texture*>(img);
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);
}

View File

@@ -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/01/19 05:35:38 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -15,207 +15,286 @@
#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)
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);
return static_cast<mlx::core::Application*>(mlx)->getTexturePixel(img, x, y);
}
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<uint32_t>(fps));
return 0;
}
}

View File

@@ -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 */
/* */
/* ************************************************************************** */

View File

@@ -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
View 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/01/18 15:20:03 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<uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count());
_fps_now = static_cast<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<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));
return false;
}
}

41
src/core/fps.h git.filemode.normal_file
View 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(uint32_t fps) noexcept { _max_fps = fps; _ns = 1000000000.0 / fps; }
~FpsManager() = default;
private:
double _ns = 1000000000.0 / 1'337'000.0;
uint64_t _timer = 0;
uint64_t _fps_before = 0;
uint64_t _fps_now = 0;
uint32_t _max_fps = 1'337'000;
uint32_t _fps_elapsed_time = 0;
};
}
#endif

View File

@@ -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/01/11 04:38:53 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -14,51 +14,58 @@
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);
}
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);
static 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
@@ -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();
}
}

View File

@@ -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/01/11 15:47:05 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -23,39 +23,58 @@
#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
{
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 stringPut(int x, int y, 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 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;
};
}

View File

@@ -10,57 +10,58 @@
/* */
/* ************************************************************************** */
#include "renderer/images/texture.h"
#include <core/graphics.h>
#include <type_traits>
#include <iostream>
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
{
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, 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);
}
}

65
src/core/memory.cpp git.filemode.normal_file
View 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
View 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

View File

@@ -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
View 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
View 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/01/10 18:36:46 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 <sstream>
#include <fstream>
#include <iomanip>
#include <unordered_map>
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 srcIndex = 0;
std::size_t dstIndex = 0;
while(srcIndex < N)
{
std::size_t matchIndex = 0;
while(matchIndex < K - 1 && srcIndex + matchIndex < N - 1 && expr[srcIndex + matchIndex] == remove[matchIndex])
matchIndex++;
if(matchIndex == K - 1)
srcIndex += matchIndex;
result.data[dstIndex++] = expr[srcIndex] == '"' ? '\'' : expr[srcIndex];
srcIndex++;
}
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

View File

@@ -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/01/16 07:59:15 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;
@@ -39,7 +34,7 @@ namespace mlx
}
uint32_t id = _event.window.windowID;
if(!_events_hooks.count(id))
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];

View File

@@ -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/01/16 07:59:08 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; }
@@ -66,11 +62,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<uint32_t, std::array<Hook, 6>> _events_hooks;
SDL_Event _event;
std::array<uint8_t, 8> _mouse;
int _x = 0;
int _y = 0;

View File

@@ -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 */
/* */
/* ************************************************************************** */
@@ -30,6 +30,8 @@ namespace mlx
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)
SDL_DestroyWindow(_win);
if(_icon)
SDL_FreeSurface(_icon);
}
MLX_Window::~MLX_Window()
if(_win != nullptr)
{
destroy();
SDL_DestroyWindow(_win);
_win = nullptr;
}
if(_icon != nullptr)
{
SDL_FreeSurface(_icon);
_icon = nullptr;
}
}
}

View File

@@ -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
{
@@ -30,7 +31,7 @@ namespace mlx
void destroy() noexcept;
~MLX_Window();
~MLX_Window() = default;
private:
SDL_Surface* _icon = nullptr;

View File

@@ -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/01/11 05:21:20 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,22 +46,29 @@ 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();
// not creating destroyer in `create` as some image may be copied (and so `this` will be invalid)
//CmdResource::setDestroyer([this]()
//{
if(_is_mapped)
unmapMem();
if(_buffer != VK_NULL_HANDLE)
Render_Core::get().getAllocator().destroyBuffer(_allocation, _buffer);
_buffer = VK_NULL_HANDLE;
//});
//CmdResource::requireDestroy();
}
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 +82,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 +91,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 +131,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, &copyRegion);
cmdBuffer.endRecord();
cmdBuffer.submitIdle();
cmdBuffer.destroy();
cmdpool.destroy();
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 +157,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)

View File

@@ -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; }

View File

@@ -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>
@@ -23,7 +24,7 @@ namespace mlx
{
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 bind(Renderer& renderer) noexcept { renderer.getActiveCmdBuffer().bindIndexBuffer(*this); }
};
}

View File

@@ -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, uint32_t size, [[maybe_unused]] const char* name)
{
MLX_PROFILE_FUNCTION();
_renderer = renderer;
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
@@ -37,11 +39,13 @@ namespace mlx
void UBO::setData(uint32_t size, const void* data)
{
MLX_PROFILE_FUNCTION();
std::memcpy(_maps[_renderer->getActiveImageIndex()], data, static_cast<size_t>(size));
}
void UBO::setDynamicData(uint32_t size, const void* data)
{
MLX_PROFILE_FUNCTION();
std::memcpy(_maps[_renderer->getActiveImageIndex()], data, static_cast<size_t>(size));
_buffers[_renderer->getActiveImageIndex()].flush();
}

View File

@@ -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,6 +16,7 @@
#include "vk_buffer.h"
#include <array>
#include <cstddef>
#include <mlx_profile.h>
namespace mlx
{

View File

@@ -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 */
/* */
/* ************************************************************************** */
@@ -18,7 +18,10 @@ namespace mlx
void VBO::setData(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");
@@ -28,4 +31,25 @@ namespace mlx
std::memcpy(temp, data, static_cast<size_t>(size));
unmapMem();
}
void D_VBO::setData(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();
}
}

View File

@@ -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); }
inline void create(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(uint32_t size, const void* data);
inline void bind(Renderer& renderer) noexcept { vkCmdBindVertexBuffers(renderer.getActiveCmdBuffer().get(), 0, 1, &_buffer, &_offset); }
inline void bind(Renderer& renderer) noexcept { renderer.getActiveCmdBuffer().bindVertexBuffer(*this); }
};
class D_VBO : public Buffer
{
public:
inline void create(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(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 bind(Renderer& renderer) noexcept { renderer.getActiveCmdBuffer().bindVertexBuffer(*this); }
};
}

View File

@@ -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)

View File

@@ -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>

View File

@@ -0,0 +1,63 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* single_time_cmd_manager.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/12/15 19:57:49 by maldavid #+# #+# */
/* Updated: 2024/01/11 03:13:21 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();
}
}

View 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 uint8_t BASE_POOL_SIZE = 16;
private:
std::vector<CmdBuffer> _buffers;
CmdPool _pool;
};
}
#endif

View File

@@ -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/01/10 18:30:04 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, &copyRegion);
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, &region);
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, &region);
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();
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);
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;
}
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
}
}

View File

@@ -6,44 +6,82 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:25:42 by maldavid #+# #+# */
/* Updated: 2023/04/21 13:20:49 by maldavid ### ########.fr */
/* Updated: 2024/01/07 01:25:50 by maldavid ### ########.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>
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;
};
}

View File

@@ -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/01/03 13:13:25 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -22,8 +22,9 @@ namespace mlx
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
poolInfo.queueFamilyIndex = Render_Core::get().getQueue().getFamilies().graphicsFamily.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

View File

@@ -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

62
src/renderer/core/cmd_resource.h git.filemode.normal_file
View File

@@ -0,0 +1,62 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* cmd_resource.h :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/12/16 20:44:29 by maldavid #+# #+# */
/* Updated: 2024/01/11 05:12:42 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;
if(_destroy_required && _destroyer)
{
_destroyer();
_destroy_required = false;
}
}
inline void setDestroyer(func::function<void(void)> functor) { _destroyer = functor; }
inline void requireDestroy() noexcept
{
if(_state == state::out_cmd_buffer && _destroyer)
_destroyer();
else
_destroy_required = true;
}
inline UUID getUUID() const noexcept { return _uuid; }
virtual ~CmdResource() = default;
private:
UUID _uuid;
state _state = state::out_cmd_buffer;
func::function<void(void)> _destroyer;
bool _destroy_required = false;
};
}
#endif

32
src/renderer/core/drawable_resource.h git.filemode.normal_file
View 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

View File

@@ -6,25 +6,35 @@
/* 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/01/18 10:11:02 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <core/profile.h>
#include <mlx_profile.h>
#include <core/errors.h>
#include <core/profiler.h>
#include <cstdio>
#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 "-Wparentheses"
#include <renderer/core/memory.h>
#pragma GCC diagnostic pop
#else
#include <renderer/core/memory.h>
#endif
@@ -67,65 +77,85 @@ 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, (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, (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);
}
@@ -150,11 +180,21 @@ namespace mlx
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)", _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), please report, this should not happen", _active_buffers_allocations);
vmaDestroyAllocator(_allocator);
_active_buffers_allocations = 0;
_active_images_allocations = 0;
#ifdef DEBUG
core::error::report(e_kind::message, "Vulkan : destroyed a graphics allocator");
#endif
}
}

View File

@@ -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/01/03 15:25:56 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;
uint32_t _active_buffers_allocations = 0;
uint32_t _active_images_allocations = 0;
};
}

View File

@@ -6,26 +6,23 @@
/* 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/01/20 08:20:07 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
#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
{
@@ -45,11 +42,82 @@ 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(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 +126,7 @@ namespace mlx
volkLoadDevice(_device.get());
_queues.init();
_allocator.init();
_cmd_manager.init();
_is_init = true;
}
@@ -68,6 +137,8 @@ namespace mlx
vkDeviceWaitIdle(_device());
_pool_manager.destroyAllPools();
_cmd_manager.destroy();
_allocator.destroy();
_device.destroy();
_layers.destroy();

View File

@@ -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"
@@ -30,6 +34,8 @@ namespace mlx
namespace RCore
{
std::optional<uint32_t> findMemoryType(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;

View File

@@ -6,11 +6,13 @@
/* 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/01/20 05:34:15 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include "render_core.h"
#include <iterator>
#include <map>
#include <vector>
#include <set>
#include <SDL2/SDL.h>
@@ -56,8 +58,9 @@ namespace mlx
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(_physicalDevice, &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
@@ -82,30 +85,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)
_physicalDevice = 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);
core::error::report(e_kind::message, "Vulkan : picked a physical device, %s", props.deviceName);
#endif
Render_Core::get().getQueue().findQueueFamilies(_physicalDevice, 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)
@@ -122,6 +122,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 +133,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;
@@ -155,5 +162,8 @@ namespace mlx
{
vkDestroyDevice(_device, nullptr);
_device = VK_NULL_HANDLE;
#ifdef DEBUG
core::error::report(e_kind::message, "Vulkan : destroyed a logical device");
#endif
}
}

View File

@@ -6,13 +6,14 @@
/* 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/01/03 15:26:14 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#ifndef __MLX_VK_DEVICE__
#define __MLX_VK_DEVICE__
#include <mlx_profile.h>
#include <volk.h>
#include "vk_queues.h"

View File

@@ -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/01/06 16:57:26 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
}
}

View File

@@ -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;

View File

@@ -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/01/10 21:54:06 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -21,19 +21,19 @@ 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, 2, 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.ppEnabledExtensionNames = extensions.data();
createInfo.enabledLayerCount = 0; // will be replaced if validation layers are enabled
createInfo.pNext = nullptr;
VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo;
if constexpr(enableValidationLayers)
@@ -43,18 +43,13 @@ namespace mlx
createInfo.enabledLayerCount = static_cast<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");
@@ -89,5 +84,8 @@ namespace mlx
{
vkDestroyInstance(_instance, nullptr);
_instance = VK_NULL_HANDLE;
#ifdef DEBUG
core::error::report(e_kind::message, "Vulkan : destroyed an instance");
#endif
}
}

View File

@@ -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>

View File

@@ -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/01/10 21:54:54 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -38,7 +38,7 @@ namespace mlx
_families->presentFamily = i;
if(_families->isComplete())
break;
return *_families;
i++;
}
@@ -64,5 +64,8 @@ namespace mlx
}
vkGetDeviceQueue(Render_Core::get().getDevice().get(), _families->graphicsFamily.value(), 0, &_graphicsQueue);
vkGetDeviceQueue(Render_Core::get().getDevice().get(), _families->presentFamily.value(), 0, &_presentQueue);
#ifdef DEBUG
core::error::report(e_kind::message, "Vulkan : got graphics and present queues");
#endif
}
}

View File

@@ -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/01/08 23:46:23 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
{
@@ -36,7 +38,13 @@ namespace mlx
inline VkQueue& getGraphic() noexcept { return _graphicsQueue; }
inline VkQueue& getPresent() noexcept { return _presentQueue; }
inline QueueFamilyIndices getFamilies() noexcept { return *_families; }
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;

View File

@@ -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/01/10 21:55:12 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -21,11 +21,12 @@ 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, &_imageAvailableSemaphores)) != VK_SUCCESS ||
(res = vkCreateSemaphore(Render_Core::get().getDevice().get(), &semaphoreInfo, nullptr, &_renderFinishedSemaphores)) != 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
}
@@ -35,5 +36,8 @@ namespace mlx
_renderFinishedSemaphores = VK_NULL_HANDLE;
vkDestroySemaphore(Render_Core::get().getDevice().get(), _imageAvailableSemaphores, nullptr);
_imageAvailableSemaphores = VK_NULL_HANDLE;
#ifdef DEBUG
core::error::report(e_kind::message, "Vulkan : destroyed semaphores");
#endif
}
}

View File

@@ -6,13 +6,14 @@
/* 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/01/03 15:26:39 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#ifndef __MLX_VK_SEMAPHORE__
#define __MLX_VK_SEMAPHORE__
#include <mlx_profile.h>
#include <volk.h>
#include <vector>

View File

@@ -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
}
}

View File

@@ -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>

View File

@@ -3,19 +3,20 @@
/* ::: :::::::: */
/* 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/01/10 21:55:54 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,14 +25,33 @@ namespace mlx
if constexpr(!enableValidationLayers)
return;
VkDebugUtilsMessengerCreateInfoEXT createInfo;
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
real_vkSetDebugUtilsObjectNameEXT = (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(Render_Core::get().getInstance().get(), "vkSetDebugUtilsObjectNameEXT");
if(!real_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()
@@ -42,36 +62,28 @@ namespace mlx
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;
});
}
void ValidationLayers::destroy()
VkResult ValidationLayers::setDebugUtilsObjectNameEXT(VkObjectType object_type, uint64_t object_handle, const char* object_name)
{
if constexpr(!enableValidationLayers)
return;
destroyDebugUtilsMessengerEXT(nullptr);
}
if(!real_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 real_vkSetDebugUtilsObjectNameEXT(Render_Core::get().getDevice().get(), &name_info);
}
void ValidationLayers::populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo)
@@ -83,19 +95,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(messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
if constexpr(enableValidationLayers)
{
std::cout << '\n';
core::error::report(e_kind::error, std::string("Vulkan layer error: ") + pCallbackData->pMessage);
destroyDebugUtilsMessengerEXT(nullptr);
#ifdef DEBUG
core::error::report(e_kind::message, "Vulkan : destroyed validation layers");
#endif
}
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);
}
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;
}
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)
core::error::report(e_kind::error, pCallbackData->pMessage);
else if(messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)
core::error::report(e_kind::warning, pCallbackData->pMessage);
return VK_FALSE;
}

View File

@@ -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/01/07 00:21:42 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, 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);
private:
VkDebugUtilsMessengerEXT _debugMessenger;
PFN_vkSetDebugUtilsObjectNameEXT real_vkSetDebugUtilsObjectNameEXT = nullptr;
};
}

View 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();
}
}

View 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

View File

@@ -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::freeDescriptor(const DescriptorSet& set)
{
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
}
}

View File

@@ -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;
};
}

View File

@@ -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;
@@ -35,15 +39,17 @@ namespace mlx
allocInfo.descriptorSetCount = static_cast<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
}
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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/01/18 10:18:22 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -14,6 +14,7 @@
#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
@@ -31,9 +32,11 @@ namespace mlx
{
void Texture::create(uint8_t* pixels, uint32_t width, 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}},
@@ -53,23 +56,33 @@ namespace mlx
_ibo.create(sizeof(uint16_t) * indexData.size(), indexData.data(), nullptr);
#endif
if(pixels != nullptr)
{
Buffer staging_buffer;
std::size_t size = width * height * formatSize(format);
if(pixels != nullptr)
{
#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
}
else
{
std::vector<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
{
if(x < 0 || y < 0 || x > getWidth() || y > getHeight())
MLX_PROFILE_FUNCTION();
if(x < 0 || y < 0 || static_cast<uint32_t>(x) > getWidth() || static_cast<uint32_t>(y) > getHeight())
return;
if(_map == nullptr)
openCPUmap();
@@ -79,7 +92,8 @@ 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<uint32_t>(x) > getWidth() || static_cast<uint32_t>(y) > getHeight())
return 0;
if(_map == nullptr)
openCPUmap();
@@ -89,6 +103,7 @@ namespace mlx
void Texture::openCPUmap()
{
MLX_PROFILE_FUNCTION();
if(_map != nullptr)
return;
@@ -111,25 +126,36 @@ namespace mlx
#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<uint32_t>(_ibo.getSize() / sizeof(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,6 +164,7 @@ namespace mlx
Texture stbTextureLoad(std::filesystem::path file, int* w, int* h)
{
MLX_PROFILE_FUNCTION();
Texture texture;
int channels;
uint8_t* data = nullptr;
@@ -147,11 +174,13 @@ namespace mlx
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;

View File

@@ -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/01/11 01:18:25 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -21,6 +21,8 @@
#include <renderer/descriptors/vk_descriptor_set.h>
#include <renderer/buffers/vk_ibo.h>
#include <renderer/buffers/vk_vbo.h>
#include <mlx_profile.h>
#include <string>
namespace mlx
{
@@ -30,17 +32,17 @@ namespace mlx
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 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;
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;
@@ -58,33 +60,10 @@ namespace mlx
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

View File

@@ -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 */
/* */
/* ************************************************************************** */
@@ -25,18 +25,21 @@ namespace mlx
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)
{
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, uint32_t ibo_size) const
{
auto cmd = renderer.getActiveCmdBuffer().get();
@@ -48,5 +51,6 @@ namespace mlx
void TextureAtlas::destroy() noexcept
{
Image::destroy();
_set.destroy();
}
}

View File

@@ -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/01/18 02:47:30 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -16,6 +16,7 @@
#include <renderer/images/texture.h>
#include <array>
#include <glm/glm.hpp>
#include <mlx_profile.h>
namespace mlx
{
@@ -25,17 +26,21 @@ namespace mlx
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 render(class Renderer& renderer, int x, int y, 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
View 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

43
src/renderer/images/texture_manager.h git.filemode.normal_file
View File

@@ -0,0 +1,43 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* texture_manager.h :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/01/11 00:56:15 by maldavid #+# #+# */
/* Updated: 2024/01/11 01:49:12 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);
}
~TextureManager() = default;
private:
std::unordered_set<TextureRenderDescriptor> _texture_descriptors;
};
}
#endif

View File

@@ -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/01/18 09:47:26 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -99,43 +99,6 @@ 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)
{
_width = width;
@@ -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, (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, (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, &copy_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, &region);
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, &copy_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, &region);
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;
}
@@ -377,13 +251,17 @@ namespace mlx
void Image::destroy() noexcept
{
// not creating destroyer in `create` as some image may be copied (and so `this` will be invalid)
//CmdResource::setDestroyer([this]()
//{
destroySampler();
destroyImageView();
destroyCmdPool();
if(_image != VK_NULL_HANDLE)
Render_Core::get().getAllocator().destroyImage(_allocation, _image);
_image = VK_NULL_HANDLE;
//});
//CmdResource::requireDestroy();
}
uint32_t formatSize(VkFormat format)

View File

@@ -6,24 +6,33 @@
/* 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);
bool isStencilFormat(VkFormat format);
bool isDepthFormat(VkFormat format);
VkFormat bitsToFormat(uint32_t bits);
VkPipelineStageFlags layoutToAccessMask(VkImageLayout layout, bool isDestination);
class Image
class Image : public CmdResource
{
friend class SwapChain;
@@ -37,39 +46,40 @@ namespace mlx
_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 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 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 uint32_t getWidth() const noexcept { return _width; }
inline 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;

View File

@@ -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/01/16 07:45:15 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<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<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,
@@ -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;
@@ -305,8 +305,9 @@ namespace mlx
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, &_graphicsPipeline);
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
@@ -319,5 +320,9 @@ namespace mlx
{
vkDestroyPipeline(Render_Core::get().getDevice().get(), _graphicsPipeline, nullptr);
vkDestroyPipelineLayout(Render_Core::get().getDevice().get(), _pipelineLayout, nullptr);
_graphicsPipeline = VK_NULL_HANDLE;
#ifdef DEBUG
core::error::report(e_kind::message, "Vulkan : destroyed a graphics pipeline");
#endif
}
}

Some files were not shown because too many files have changed in this diff Show More