216 Commits

Author SHA1 Message Date
kbz_8
04330a10ac The bro did it again (#54) 2024-02-25 09:40:47 +01:00
kbz_8
a456ad15ce Merge branch 'master' into indev 2024-02-25 09:35:31 +01:00
Kbz-8
e621bb53d4 removing debug print 2024-02-25 09:30:30 +01:00
kbz_8
420ba21b4d merge to master (#53) 2024-02-25 09:15:29 +01:00
Kbz-8
f3de55d6e9 fixing issue with text destruction 2024-02-25 09:02:57 +01:00
Kbz-8
bc1e0fbba9 adding std namespace to all libstd provided primitive types 2024-02-25 08:04:44 +01:00
Kbz-8
80c0146ecd removing unecessary SDL window creation in Vulkan Instance creation 2024-02-24 04:47:05 +01:00
Kbz-8
dbe3bb3cb3 fixing weird color bug with mlx_get_image_pixel 2024-02-24 03:58:12 +01:00
kbz_8
83ecc6e498 update dependencies (#50)
Automated changes by
[create-pull-request](https://github.com/peter-evans/create-pull-request)
GitHub action
2024-02-18 21:42:23 +01:00
Kbz-8
8b2965f6dd [BOT] update dependencies 2024-02-17 01:02:17 +00:00
kbz_8
6c31d3347a sync (#49) 2024-02-10 03:12:08 +01:00
kbz_8
7f8ec481f1 Bump peter-evans/create-pull-request from 5 to 6 (#48)
Bumps
[peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request)
from 5 to 6.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/peter-evans/create-pull-request/releases">peter-evans/create-pull-request's
releases</a>.</em></p>
<blockquote>
<h2>Create Pull Request v6.0.0</h2>
<h2>Behaviour changes</h2>
<ul>
<li>The default values for <code>author</code> and
<code>committer</code> have changed. See &quot;What's new&quot; below
for details. If you are overriding the default values you will not be
affected by this change.</li>
<li>On completion, the action now removes the temporary git remote
configuration it adds when using <code>push-to-fork</code>. This should
not affect you unless you were using the temporary configuration for
some other purpose after the action completes.</li>
</ul>
<h2>What's new</h2>
<ul>
<li>Updated runtime to Node.js 20
<ul>
<li>The action now requires a minimum version of <a
href="https://github.com/actions/runner/releases/tag/v2.308.0">v2.308.0</a>
for the Actions runner. Update self-hosted runners to v2.308.0 or later
to ensure compatibility.</li>
</ul>
</li>
<li>The default value for <code>author</code> has been changed to
<code>${{ github.actor }} &lt;${{ github.actor_id }}+${{ github.actor
}}@users.noreply.github.com&gt;</code>. The change adds the <code>${{
github.actor_id }}+</code> prefix to the email address to align with
GitHub's standard format for the author email address.</li>
<li>The default value for <code>committer</code> has been changed to
<code>github-actions[bot]
&lt;41898282+github-actions[bot]@users.noreply.github.com&gt;</code>.
This is to align with the default GitHub Actions bot user account.</li>
<li>Adds input <code>git-token</code>, the <a
href="https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token">Personal
Access Token (PAT)</a> that the action will use for git operations. This
input defaults to the value of <code>token</code>. Use this input if you
would like the action to use a different token for git operations than
the one used for the GitHub API.</li>
<li><code>push-to-fork</code> now supports pushing to sibling
repositories in the same network.</li>
<li>Previously, when using <code>push-to-fork</code>, the action did not
remove temporary git remote configuration it adds during execution. This
has been fixed and the configuration is now removed when the action
completes.</li>
<li>If the pull request body is truncated due to exceeding the maximum
length, the action will now suffix the body with the message
&quot;...<em>[Pull request body truncated]</em>&quot; to indicate that
the body has been truncated.</li>
<li>The action now uses <code>--unshallow</code> only when necessary,
rather than as a default argument of <code>git fetch</code>. This should
improve performance, particularly for large git repositories with
extensive commit history.</li>
<li>The action can now be executed on one GitHub server and create pull
requests on a <em>different</em> GitHub server. Server products include
GitHub hosted (github.com), GitHub Enterprise Server (GHES), and GitHub
Enterprise Cloud (GHEC). For example, the action can be executed on
GitHub hosted and create pull requests on a GHES or GHEC instance.</li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>Update distribution by <a
href="https://github.com/actions-bot"><code>@​actions-bot</code></a> in
<a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/2086">peter-evans/create-pull-request#2086</a></li>
<li>fix crazy-max/ghaction-import-gp parameters by <a
href="https://github.com/fharper"><code>@​fharper</code></a> in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/2177">peter-evans/create-pull-request#2177</a></li>
<li>Update distribution by <a
href="https://github.com/actions-bot"><code>@​actions-bot</code></a> in
<a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/2364">peter-evans/create-pull-request#2364</a></li>
<li>Use checkout v4 by <a
href="https://github.com/okuramasafumi"><code>@​okuramasafumi</code></a>
in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/2521">peter-evans/create-pull-request#2521</a></li>
<li>Note about <code>delete-branch</code> by <a
href="https://github.com/dezren39"><code>@​dezren39</code></a> in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/2631">peter-evans/create-pull-request#2631</a></li>
<li>98 dependency updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/fharper"><code>@​fharper</code></a> made
their first contribution in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/2177">peter-evans/create-pull-request#2177</a></li>
<li><a
href="https://github.com/okuramasafumi"><code>@​okuramasafumi</code></a>
made their first contribution in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/2521">peter-evans/create-pull-request#2521</a></li>
<li><a href="https://github.com/dezren39"><code>@​dezren39</code></a>
made their first contribution in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/2631">peter-evans/create-pull-request#2631</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/peter-evans/create-pull-request/compare/v5.0.2...v6.0.0">https://github.com/peter-evans/create-pull-request/compare/v5.0.2...v6.0.0</a></p>
<h2>Create Pull Request v5.0.2</h2>
<p>⚙️ Fixes an issue that occurs when using <code>push-to-fork</code>
and both base and head repositories are in the same org/user
account.</p>
<h2>What's Changed</h2>
<ul>
<li>fix: specify head repo by <a
href="https://github.com/peter-evans"><code>@​peter-evans</code></a> in
<a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/2044">peter-evans/create-pull-request#2044</a></li>
<li>20 dependency updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/peter-evans/create-pull-request/compare/v5.0.1...v5.0.2">https://github.com/peter-evans/create-pull-request/compare/v5.0.1...v5.0.2</a></p>
<h2>Create Pull Request v5.0.1</h2>
<h2>What's Changed</h2>
<ul>
<li>fix: truncate body if exceeds max length by <a
href="https://github.com/peter-evans"><code>@​peter-evans</code></a> in
<a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/1915">peter-evans/create-pull-request#1915</a></li>
<li>12 dependency updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/peter-evans/create-pull-request/compare/v5.0.0...v5.0.1">https://github.com/peter-evans/create-pull-request/compare/v5.0.0...v5.0.1</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="b1ddad2c99"><code>b1ddad2</code></a>
feat: v6 (<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/2717">#2717</a>)</li>
<li><a
href="bb809027fd"><code>bb80902</code></a>
build(deps-dev): bump <code>@​types/node</code> from 18.19.8 to 18.19.10
(<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/2712">#2712</a>)</li>
<li><a
href="e0037d470c"><code>e0037d4</code></a>
build(deps): bump peter-evans/create-or-update-comment from 3 to 4 (<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/2702">#2702</a>)</li>
<li><a
href="94b1f99e3a"><code>94b1f99</code></a>
build(deps): bump peter-evans/find-comment from 2 to 3 (<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/2703">#2703</a>)</li>
<li><a
href="69c27eaf4a"><code>69c27ea</code></a>
build(deps-dev): bump ts-jest from 29.1.1 to 29.1.2 (<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/2685">#2685</a>)</li>
<li><a
href="7ea722a0f6"><code>7ea722a</code></a>
build(deps-dev): bump prettier from 3.2.2 to 3.2.4 (<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/2684">#2684</a>)</li>
<li><a
href="5ee839affd"><code>5ee839a</code></a>
build(deps-dev): bump <code>@​types/node</code> from 18.19.7 to 18.19.8
(<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/2683">#2683</a>)</li>
<li><a
href="60fc256c67"><code>60fc256</code></a>
build(deps-dev): bump eslint-plugin-prettier from 5.1.2 to 5.1.3 (<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/2660">#2660</a>)</li>
<li><a
href="0c67723361"><code>0c67723</code></a>
build(deps-dev): bump <code>@​types/node</code> from 18.19.5 to 18.19.7
(<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/2661">#2661</a>)</li>
<li><a
href="4e288e851b"><code>4e288e8</code></a>
build(deps-dev): bump prettier from 3.1.1 to 3.2.2 (<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/2659">#2659</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/peter-evans/create-pull-request/compare/v5...v6">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=peter-evans/create-pull-request&package-manager=github_actions&previous-version=5&new-version=6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>
2024-02-05 23:17:30 +01:00
dependabot[bot]
25bb57a973 Bump peter-evans/create-pull-request from 5 to 6
Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 5 to 6.
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](https://github.com/peter-evans/create-pull-request/compare/v5...v6)

---
updated-dependencies:
- dependency-name: peter-evans/create-pull-request
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-05 22:10:30 +00:00
kbz_8
39365f52a2 update dependencies (#47)
Automated changes by
[create-pull-request](https://github.com/peter-evans/create-pull-request)
GitHub action
2024-02-02 15:21:14 +01:00
Kbz-8
fafc94248d [BOT] update dependencies 2024-02-02 01:03:23 +00:00
kbz_8
edeaff793a adding check to texture pointers (#46) 2024-01-26 12:11:47 +01:00
kbz_8
2d5758419f Merge branch 'master' into indev 2024-01-26 12:07:15 +01:00
kbz_8
ba063dae3b update dependencies (#45)
Automated changes by
[create-pull-request](https://github.com/peter-evans/create-pull-request)
GitHub action
2024-01-26 12:01:23 +01:00
Kbz-8
e018cad851 adding check to texture pointers 2024-01-26 11:59:57 +01:00
Kbz-8
9ee8041710 [BOT] update dependencies 2024-01-26 01:04:35 +00:00
kbz_8
1b50e123c5 yes (#43) 2024-01-24 17:54:37 +01:00
kbz_8
77563b8449 Merge branch 'master' into indev 2024-01-24 17:49:53 +01:00
kbz_8
d0923320a3 yes 2024-01-24 17:49:38 +01:00
Kbz-8
d8cab7aa47 adding rule to gitignore 2024-01-20 08:54:28 +01:00
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
Kbz-8
39501f2940 update logo size 2023-11-25 12:48:16 +01:00
Kbz-8
372f818da4 working on readme 2023-11-25 12:47:07 +01:00
Kbz-8
1651f9ba97 working on readme 2023-11-25 12:31:09 +01:00
Kbz-8
c7e09f1d8c adding logo 2023-11-25 12:23:57 +01:00
Kbz-8
82529d6dc9 update readme 2023-11-25 10:44:51 +01:00
Kbz-8
4e30bd02bf adding screenshot te readme 2023-11-25 10:44:24 +01:00
Kbz-8
f8c2abb20b adding screenshot te readme 2023-11-25 10:44:00 +01:00
Kbz-8
880ac98ca9 adding screenshot te readme 2023-11-25 10:43:05 +01:00
Kbz-8
49c211cebc transparency management added 2023-11-25 10:31:06 +01:00
Kbz-8
38768c85c9 improving font management 2023-11-24 19:34:15 +01:00
Kbz-8
c7433ec419 removing gdb history 2023-11-23 14:37:58 +01:00
Kbz-8
d6b6dd955c new feature, font loading 2023-11-23 14:37:42 +01:00
kbz_8
c125dde951 Update README.md 2023-11-21 07:14:32 +01:00
kbz_8
9934b34bba Update README.md 2023-11-21 07:14:08 +01:00
kbz_8
3e3f20513f moving to MIT license 2023-11-21 07:13:15 +01:00
Kbz-8
c93d7854d0 fixing compilation error 2023-11-20 07:29:36 +01:00
Kbz-8
9fdb514541 fixing spaces in indentaions 2023-11-20 07:28:03 +01:00
kbz_8
35f5f41258 fixed error message for image file loading 2023-11-18 17:57:06 +01:00
Kbz-8
f6201014aa cleaning renderpass, framebuffers and swapchain code, setting all vulkan resources to NULL after destroy 2023-11-18 17:25:30 +01:00
Kbz-8
c583f1abc8 fixing GCC warning 2023-11-16 14:07:02 +01:00
Kbz-8
f7cf64cbb9 removing a trash file 2023-11-16 14:05:16 +01:00
Kbz-8
b882771a18 removing all memory dump strings informations in release mode 2023-11-16 14:04:51 +01:00
562 changed files with 308310 additions and 5801 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@v6
with:
title: update dependencies
commit-message: "[BOT] update dependencies"
committer: GitHub <noreply@github.com>
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
signoff: false
base: indev
branch: auto_deps_updates
labels: |
automated

25
.github/workflows/greetings.yml vendored git.filemode.normal_file
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 # Build the lib
- name: Build MacroLibX - name: Build MacroLibX
run: make -j run: make -j && make fclean && make -j DEBUG=true
# Build the test # Build the example
- name: Build Test - name: Build Example
run: cd test && clang main.c ../libmlx.so -lSDL2 run: cd example && bash ./build.sh

View File

@@ -35,9 +35,9 @@ jobs:
# Build the lib # Build the lib
- name: Build MacroLibX - name: Build MacroLibX
run: make TOOLCHAIN=gcc -j run: make TOOLCHAIN=gcc -j && make fclean && make TOOLCHAIN=gcc DEBUG=true -j
# Build the test # Build the example
- name: Build Test - name: Build Example
run: cd test && gcc main.c ../libmlx.so -lSDL2 run: cd example && bash ./build.sh

View File

@@ -41,9 +41,9 @@ jobs:
# Build the lib # Build the lib
- name: Build MacroLibX - name: Build MacroLibX
run: make -j run: make -j && make fclean && make DEBUG=true -j
# Build the test # Build the example
- name: Build Test - name: Build Example
run: cd test && clang main.c ../libmlx.so -lSDL2 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

15
.gitignore vendored
View File

@@ -4,4 +4,19 @@
*.a *.a
*.so *.so
*.out *.out
*.dll
*.lib
*.exp
*.json
*.tmp
*.ilk
*.pdb
*.exe
*vgcore
*.gdb_history
.vs/
.xmake/
.cache/ .cache/
objs/
build/
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.

354
LICENSE
View File

@@ -1,340 +1,20 @@
GNU GENERAL PUBLIC LICENSE MIT License
Version 2, June 1991 Copyright (c) 2022-2024 kbz_8
Copyright (C) 1989, 1991 Free Software Foundation, Inc., Permission is hereby granted, free of charge, to any person obtaining a copy
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA of this software and associated documentation files (the "Software"), to deal
Everyone is permitted to copy and distribute verbatim copies in the Software without restriction, including without limitation the rights
of this license document, but changing it is not allowed. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
Preamble The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -6,7 +6,7 @@
# By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ # # By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ # # +#+#+#+#+#+ +#+ #
# Created: 2022/10/04 16:43:41 by maldavid #+# #+# # # Created: 2022/10/04 16:43:41 by maldavid #+# #+# #
# Updated: 2023/11/13 06:08:16 by maldavid ### ########.fr # # Updated: 2024/01/10 14:20:30 by maldavid ### ########.fr #
# # # #
# **************************************************************************** # # **************************************************************************** #
@@ -17,7 +17,8 @@ SRCS += $(wildcard $(addsuffix /*.cpp, ./src/platform))
SRCS += $(wildcard $(addsuffix /*.cpp, ./src/renderer)) SRCS += $(wildcard $(addsuffix /*.cpp, ./src/renderer))
SRCS += $(wildcard $(addsuffix /*.cpp, ./src/renderer/**)) SRCS += $(wildcard $(addsuffix /*.cpp, ./src/renderer/**))
OBJS = $(SRCS:.cpp=.o) OBJ_DIR = objs/makefile
OBJS = $(addprefix $(OBJ_DIR)/, $(SRCS:.cpp=.o))
OS = $(shell uname -s) OS = $(shell uname -s)
DEBUG ?= false DEBUG ?= false
@@ -25,24 +26,33 @@ TOOLCHAIN ?= clang
IMAGES_OPTIMIZED ?= true IMAGES_OPTIMIZED ?= true
FORCE_INTEGRATED_GPU ?= false FORCE_INTEGRATED_GPU ?= false
GRAPHICS_MEMORY_DUMP ?= false GRAPHICS_MEMORY_DUMP ?= false
PROFILER ?= false
CXX = clang++ MODE = "release"
ifeq ($(TOOLCHAIN), gcc) CXX = clang++
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 INCLUDES = -I./includes -I./src -I./third_party
LDLIBS = LDLIBS =
ifeq ($(TOOLCHAIN), gcc)
CXX = g++
CXXFLAGS += -Wno-error=cpp
else
CXXFLAGS += -Wno-error=#warning
endif
ifeq ($(OS), Darwin) ifeq ($(OS), Darwin)
LDLIBS += -lSDL2 LDLIBS += -L /opt/homebrew/lib -lSDL2
CXXFLAGS += -I /opt/homebrew/include
NAME = libmlx.dylib
endif endif
ifeq ($(DEBUG), true) ifeq ($(DEBUG), true)
CXXFLAGS += -g -D DEBUG CXXFLAGS += -g -D DEBUG
MODE = "debug"
endif endif
ifeq ($(FORCE_INTEGRATED_GPU), true) ifeq ($(FORCE_INTEGRATED_GPU), true)
@@ -57,24 +67,34 @@ ifeq ($(GRAPHICS_MEMORY_DUMP), true)
CXXFLAGS += -D GRAPHICS_MEMORY_DUMP CXXFLAGS += -D GRAPHICS_MEMORY_DUMP
endif endif
RM = rm -f ifeq ($(PROFILER), true)
CXXFLAGS += -D PROFILER
endif
%.o: %.cpp RM = rm -rf
@echo "\e[1;32m[compiling... "$(CXX)"]\e[1;00m "$<
$(OBJ_DIR)/%.o: %.cpp
@printf "\033[1;32m[compiling... "$(MODE)" "$(CXX)"]\033[1;00m "$<"\n"
@$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@ @$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
all: $(NAME) all: $(NAME)
$(NAME): $(OBJS) $(NAME): $(OBJ_DIR) $(OBJS)
@echo "\e[1;32m[linking ...]\e[1;00m "$@ @printf "\033[1;32m[linking ... "$(MODE)"]\033[1;00m "$@"\n"
@$(CXX) -shared -o $(NAME) $(OBJS) $(LDLIBS) @$(CXX) -shared -o $(NAME) $(OBJS) $(LDLIBS)
@echo "\e[1;32m[build finished]\e[1;00m" @printf "\033[1;32m[build finished]\033[1;00m\n"
$(OBJ_DIR):
@mkdir -p $(sort $(addprefix $(OBJ_DIR)/, $(dir $(SRCS))))
@printf "\033[1;32m[created objs directory]\033[1;00m\n"
clean: clean:
@$(RM) $(OBJS) @$(RM) $(OBJ_DIR)
@printf "\033[1;32m[object files removed]\033[1;00m\n"
fclean: clean fclean: clean
@$(RM) $(NAME) @$(RM) $(NAME)
@printf "\033[1;32m["$(NAME)" removed]\033[1;00m\n"
re: fclean all re: fclean all

View File

@@ -1,16 +1,44 @@
# MacroLibX [![linux clang workflow][linux-clang_badge]][linux-clang_wf] [![linux gcc workflow][linux-gcc_badge]][linux-gcc_wf] [![macos workflow][macos_badge]][macos_wf] <div align="center">
###### A rewrite of 42 School's MiniLibX using SDL2 and Vulkan. <img src="./res/logo.png" alt="drawing" width="200"/>
<div align="center">
<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.
The goal of this version is to provide a light, fast, and modern graphical tool while keeping the same API. 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 ## 🖥️ Installation
### Dependencies ### Dependencies
You first need to install the proper dependencies for your operating-system. You first need to install the proper dependencies for your operating-system.
#### 🐧 Linux #### 🐧 Linux
Here are a few common cases for different Linux distributions: Here are a few common cases for different Linux distributions:
<details> <details>
@@ -30,56 +58,56 @@ sudo apt install libsdl2-2.0-0 libsdl2-dev build-essential
<pre><code>sudo pacman -S sdl2</code></pre> <pre><code>sudo pacman -S sdl2</code></pre>
</details> </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: [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 ```sh
brew install molten-vk brew install molten-vk
brew install SDL2 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. Finally, you can clone the Git repository. When inside it, run the GNU `make` command to compile MacroLibX.
```bash ```bash
git clone https://github.com/420verfl0w/MacroLibX.git git clone https://github.com/seekrs/MacroLibX.git
cd MacroLibX cd MacroLibX
make make
``` ```
If you want to build using GCC you can add `TOOLCHAIN=gcc` to your `make` command
```bash
make TOOLCHAIN=gcc
```
## 🔨 Compile your project ## 🔨 Compile your project
To compile your project with MacroLibX, you just provide the shared library path in your compilation/linking command: To compile your project with MacroLibX, you just provide the shared library path in your compilation/linking command:
```sh ```sh
clang myApp.c /path/to/MacroLibX/libmlx.so -lSDL2 clang myApp.c /path/to/MacroLibX/libmlx.so -lSDL2
``` ```
### ⚠️ Troubleshooting And you can enjoy your project
#### If you run into glitches when writing or reading pixels from images <p align="center">
<img src="./res/screenshot_test.png" alt="drawing" width="400"/>
</p>
You need to add `IMAGES_OPTIMIZED=false` to your `make` command: ## ⚙️ Some compilation configurations
```sh ### 📦 Compile mode
# In your cloned environment, inside the MacroLibX folder By default the mlx is built in release mode but you can switch to debug by using `make DEBUG=true`.
make IMAGES_OPTIMIZED=false
``` ### 🛠️ Set the toolchain
If you want to use `GCC` to build the mlx you can use `make TOOLCHAIN=gcc`
### ⚠️⚠️⚠️ 🖼️ 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 ## 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).
This project and all its files, except the [`third_party`](./third_party) directory or unless otherwise mentionned, are licenced under the [GNU GPL v2.0](./LICENSE).
<!-- Links -->
[linux-clang_badge]: https://github.com/420verfl0w/MacroLibX/actions/workflows/linux_clang.yml/badge.svg
[linux-gcc_badge]: https://github.com/420verfl0w/MacroLibX/actions/workflows/linux_gcc.yml/badge.svg
[macos_badge]: https://github.com/420verfl0w/MacroLibX/actions/workflows/macos_x86.yml/badge.svg
[linux-clang_wf]: https://github.com/420verfl0w/MacroLibX/actions/workflows/linux_clang.yml
[linux-gcc_wf]: https://github.com/420verfl0w/MacroLibX/actions/workflows/linux_gcc.yml
[macos_wf]: https://github.com/420verfl0w/MacroLibX/actions/workflows/macos_x86.yml

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

BIN
example/font.ttf git.filemode.normal_file

Binary file not shown.

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/02/24 01:07:56 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> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/04 16:56:35 by maldavid #+# #+# */ /* Created: 2022/10/04 16:56:35 by maldavid #+# #+# */
/* Updated: 2023/04/25 15:09:04 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__ #ifndef __MACRO_LIB_X_H__
#define __MACRO_LIB_X_H__ #define __MACRO_LIB_X_H__
#include "mlx_profile.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@@ -25,15 +28,18 @@ typedef enum
MLX_KEYUP = 1, MLX_KEYUP = 1,
MLX_MOUSEDOWN = 2, MLX_MOUSEDOWN = 2,
MLX_MOUSEUP = 3, MLX_MOUSEUP = 3,
MLX_WINDOW_EVENT = 4 MLX_MOUSEWHEEL = 4,
MLX_WINDOW_EVENT = 5
} mlx_event_type; } mlx_event_type;
/** /**
* @brief Initializes the MLX internal application * @brief Initializes the MLX internal application
* *
* @return (void*) An opaque pointer to the internal MLX application or NULL (0x0) in case of error * @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 * @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 * @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 * @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 * @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 * @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 * @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 * @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 * @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 * @brief Shows mouse cursor
* *
* @return (int) Always return 0, made this to copy the behaviour of the original MLX * @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 * @brief Hides mouse cursor
* *
* @return (int) Always return 0, made this to copy the behaviour of the original MLX * @return (int) Always return 0, made this to copy the behaviour of the original MLX
*/ */
int mlx_mouse_hide(); MLX_API int mlx_mouse_hide();
/** /**
* @brief Moves cursor to givent position * @brief Moves cursor to 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 * @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 * @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 * @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 * @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 win Internal window
* @param x X coordinate * @param x X coordinate
* @param y Y 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 * 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 * @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 * @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 * @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 /!\ * /!\ If you run into glitches when writing or reading pixels from images /!\
* You need to add IMAGES_OPTIMIZED=false to your make mlx command * 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 * ~ cd MacroLibX
* ~ make IMAGES_OPTIMIZED=false * ~ 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 * @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 /!\ * /!\ If you run into glitches when writing or reading pixels from images /!\
* You need to add IMAGES_OPTIMIZED=false to your make mlx command * 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 * ~ cd MacroLibX
* ~ make IMAGES_OPTIMIZED=false * ~ 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 * @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 * @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 * @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 * @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 * @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 * @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 * @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 * @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 * @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,37 @@ void* mlx_bmp_file_to_image(void* mlx, char* filename, int* width, int* height);
* @param win Internal window * @param win Internal window
* @param x X coordinate * @param x X coordinate
* @param y Y 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 * @param str Text to put
* *
* @return (int) Always return 0, made this to copy the behaviour of the original MLX * @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);
/**
* @brief Loads a font to be used by `mlx_string_put`
*
* @param mlx Internal MLX application
* @param win Internal window
* @param filepath Filepath to the font or "default" to reset to the embedded font
*
* @return (void)
*/
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 or "default" to reset to the embedded font
* @param scale Scale to apply to the font
*
* @return (void)
*/
MLX_API void mlx_set_font_scale(void* mlx, void* win, char* filepath, float scale);
/** /**
@@ -282,7 +325,7 @@ int mlx_string_put(void* mlx, void* win, int x, int y, int color, char* str);
* *
* @return (int) Always return 0, made this to copy the behaviour of the original MLX * @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);
/** /**
@@ -293,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 * @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 * @brief Destroy internal MLX application
@@ -302,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 * @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 mlx Internal MLX application
* @param x Get X size * @param win Internal window
* @param y Get Y size * @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 * @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 #ifdef __cplusplus
} }

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

@@ -0,0 +1,194 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* mlx_profile.h :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/11/10 08:49:17 by maldavid #+# #+# */
/* Updated: 2024/01/03 15:33:35 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#ifndef __MLX_PROFILE__
#define __MLX_PROFILE__
// Try to identify the compiler
#if defined(__BORLANDC__)
#define MLX_COMPILER_BORDLAND
#elif defined(__clang__)
#define MLX_COMPILER_CLANG
#ifdef __MINGW32__
#define MLX_COMPILER_MINGW
#ifdef __MINGW64_VERSION_MAJOR
#define MLX_COMPILER_MINGW_W64
#endif
#endif
#elif defined(__GNUC__) || defined(__MINGW32__)
#define MLX_COMPILER_GCC
#ifdef __MINGW32__
#define MLX_COMPILER_MINGW
#ifdef __MINGW64_VERSION_MAJOR
#define MLX_COMPILER_MINGW_W64
#endif
#endif
#elif defined(__INTEL_COMPILER) || defined(__ICL)
#define MLX_COMPILER_INTEL
#elif defined(_MSC_VER)
#define MLX_COMPILER_MSVC
#else
#define MLX_COMPILER_UNKNOWN
#warning "This compiler is not fully supported"
#endif
#if defined(_WIN32) || defined(__CYGWIN__)
#define MLX_PLAT_WINDOWS
#elif defined(__linux__)
#define MLX_PLAT_LINUX
#elif defined(__APPLE__) && defined(__MACH__)
#define MLX_PLAT_MACOS
#elif defined(unix) || defined(__unix__) || defined(__unix)
#define MLX_PLAT_UNIX
#else
#error "Unknown environment (not Windows, not Linux, not MacOS, not Unix)"
#endif
#ifdef MLX_PLAT_WINDOWS
#ifdef MLX_COMPILER_MSVC
#ifdef MLX_BUILD
#define MLX_API __declspec(dllexport)
#else
#define MLX_API __declspec(dllimport)
#endif
#elif defined(MLX_COMPILER_GCC)
#ifdef MLX_BUILD
#define MLX_API __attribute__((dllexport))
#else
#define MLX_API __attribute__((dllimport))
#endif
#else
#define MLX_API
#endif
#elif defined(MLX_COMPILER_GCC)
#define MLX_API __attribute__((visibility("default")))
#else
#define MLX_API
#endif
#if defined(__GNUC__) || (defined(__MWERKS__) && (__MWERKS__ >= 0x3000)) || (defined(__ICC) && (__ICC >= 600)) || defined(__ghs__)
#define MLX_FUNC_SIG __PRETTY_FUNCTION__
#elif defined(__DMC__) && (__DMC__ >= 0x810)
#define MLX_FUNC_SIG __PRETTY_FUNCTION__
#elif (defined(__FUNCSIG__) || (_MSC_VER))
#define MLX_FUNC_SIG __FUNCSIG__
#elif (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 600)) || (defined(__IBMCPP__) && (__IBMCPP__ >= 500))
#define MLX_FUNC_SIG __FUNCTION__
#elif defined(__BORLANDC__) && (__BORLANDC__ >= 0x550)
#define MLX_FUNC_SIG __FUNC__
#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901)
#define MLX_FUNC_SIG __func__
#elif defined(__cplusplus) && (__cplusplus >= 201103)
#define MLX_FUNC_SIG __func__
#else
#define MLX_FUNC_SIG "Unknown function"
#endif
#ifndef __cplusplus // if we compile in C
#ifdef __STDC__
#ifdef __STDC_VERSION__
#if __STDC_VERSION__ == 199409L
#define MLX_C_VERSION 1994
#elif __STDC_VERSION__ == 199901L
#define MLX_C_VERSION 1999
#elif __STDC_VERSION__ == 201112L
#define MLX_C_VERSION 2011
#elif __STDC_VERSION__ == 201710L
#define MLX_C_VERSION 2017
#elif __STDC_VERSION__ == 202311L
#define MLX_C_VERSION 2023
#else
#define MLX_C_VERSION 0
#endif
#else
#define MLX_C_VERSION 0
#endif
#else
#define MLX_C_VERSION 0
#endif
#else
#define MLX_C_VERSION 0
#endif
#if defined(MLX_PLAT_WINDOWS)
#define VK_USE_PLATFORM_WIN32_KHR
#ifdef __cplusplus
constexpr const char* VULKAN_LIB_NAME = "vulkan-1.dll";
#endif
#elif defined(MLX_PLAT_MACOS)
#define VK_USE_PLATFORM_MACOS_MVK
#define VK_USE_PLATFORM_METAL_EXT
#ifdef __cplusplus
constexpr const char* VULKAN_LIB_NAME = "libvulkan.dylib / libvulkan.1.dylib / libMoltenVK.dylib";
#endif
#else
#define VK_USE_PLATFORM_XLIB_KHR
#define VK_USE_PLATFORM_WAYLAND_KHR
#ifdef __cplusplus
constexpr const char* VULKAN_LIB_NAME = "libvulkan.so / libvulkan.so.1";
#endif
#endif
// Checking common assumptions
#ifdef __cplusplus
#include <climits>
#include <cstdint>
static_assert(CHAR_BIT == 8, "CHAR_BIT is expected to be 8");
static_assert(sizeof(int8_t) == 1, "int8_t is not of the correct size" );
static_assert(sizeof(int16_t) == 2, "int16_t is not of the correct size");
static_assert(sizeof(int32_t) == 4, "int32_t is not of the correct size");
static_assert(sizeof(int64_t) == 8, "int64_t is not of the correct size");
static_assert(sizeof(uint8_t) == 1, "uint8_t is not of the correct size" );
static_assert(sizeof(uint16_t) == 2, "uint16_t is not of the correct size");
static_assert(sizeof(uint32_t) == 4, "uint32_t is not of the correct size");
static_assert(sizeof(uint64_t) == 8, "uint64_t is not of the correct size");
#elif MLX_C_VERSION >= 2011
#if MLX_C_VERSION < 2023
#include <assert.h>
#endif
#include <limits.h>
#include <stdint.h>
static_assert(CHAR_BIT == 8, "CHAR_BIT is expected to be 8");
static_assert(sizeof(int8_t) == 1, "int8_t is not of the correct size" );
static_assert(sizeof(int16_t) == 2, "int16_t is not of the correct size");
static_assert(sizeof(int32_t) == 4, "int32_t is not of the correct size");
static_assert(sizeof(int64_t) == 8, "int64_t is not of the correct size");
static_assert(sizeof(uint8_t) == 1, "uint8_t is not of the correct size" );
static_assert(sizeof(uint16_t) == 2, "uint16_t is not of the correct size");
static_assert(sizeof(uint32_t) == 4, "uint32_t is not of the correct size");
static_assert(sizeof(uint64_t) == 8, "uint64_t is not of the correct size");
#else
#define STATIC_ASSERT(COND, MSG) typedef char static_assertion___##MSG[(COND)?1:-1]
#include <limits.h>
#include <stdint.h>
STATIC_ASSERT(CHAR_BIT == 8, CHAR_BIT_is_expected_to_be_8);
STATIC_ASSERT(sizeof(int8_t) == 1, int8_t_is_not_of_the_correct_size);
STATIC_ASSERT(sizeof(int16_t) == 2, int16_t_is_not_of_the_correct_size);
STATIC_ASSERT(sizeof(int32_t) == 4, int32_t_is_not_of_the_correct_size);
STATIC_ASSERT(sizeof(int64_t) == 8, int64_t_is_not_of_the_correct_size);
STATIC_ASSERT(sizeof(uint8_t) == 1, uint8_t_is_not_of_the_correct_size);
STATIC_ASSERT(sizeof(uint16_t) == 2, uint16_t_is_not_of_the_correct_size);
STATIC_ASSERT(sizeof(uint32_t) == 4, uint32_t_is_not_of_the_correct_size);
STATIC_ASSERT(sizeof(uint64_t) == 8, uint64_t_is_not_of_the_correct_size);
#endif
#endif

BIN
res/logo.png git.filemode.normal_file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
res/screenshot_test.png git.filemode.normal_file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 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<std::uint64_t> uniform_distribution;
UUID::UUID() : _uuid(uniform_distribution(engine)) {}
UUID::UUID(std::uint64_t uuid) : _uuid(uuid) {}
}

View File

@@ -1,27 +1,33 @@
/* ************************************************************************** */ /* ************************************************************************** */
/* */ /* */
/* ::: :::::::: */ /* ::: :::::::: */
/* endian.h :+: :+: :+: */ /* UUID.h :+: :+: :+: */
/* +:+ +:+ +:+ */ /* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/06 15:33:15 by maldavid #+# #+# */ /* Created: 2024/01/06 11:13:23 by maldavid #+# #+# */
/* Updated: 2023/04/06 15:35:25 by maldavid ### ########.fr */ /* Updated: 2024/01/07 01:44:21 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
#ifndef __MLX_ENDIAN__ #ifndef __MLX_UUID__
#define __MLX_ENDIAN__ #define __MLX_UUID__
#include <cstdint>
namespace mlx namespace mlx
{ {
inline bool isSystemBigEndian() class UUID
{ {
const int value = 0x01; public:
const void* address = static_cast<const void*>(&value); UUID();
const unsigned char* least_significant_address = static_cast<const unsigned char*>(address); UUID(std::uint64_t uuid);
return (*least_significant_address != 0x01);
} inline operator std::uint64_t() const { return _uuid; }
private:
std::uint64_t _uuid;
};
} }
#endif #endif

View File

@@ -6,63 +6,111 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/04 22:10:52 by maldavid #+# #+# */ /* Created: 2022/10/04 22:10:52 by maldavid #+# #+# */
/* Updated: 2023/11/14 03:20:40 by maldavid ### ########.fr */ /* Updated: 2024/02/25 07:52:04 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
#include "application.h" #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/images/texture.h>
#include <renderer/core/render_core.h> #include <renderer/core/render_core.h>
#include <array>
#include <core/errors.h> #include <core/errors.h>
#include <utils/endian.h> #include <mlx_profile.h>
#include <core/profile.h> #include <core/memory.h>
namespace mlx::core 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) 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()); error::report(e_kind::fatal_error, "SDL error : unable to init all subsystems : %s", SDL_GetError());
} }
void Application::run() noexcept void Application::run() noexcept
{ {
while(_in->is_running()) while(_in->isRunning())
{ {
if(!_fps.update())
continue;
_in->update(); _in->update();
for(auto& gs : _graphics)
gs->beginRender();
if(_loop_hook) if(_loop_hook)
_loop_hook(_param); _loop_hook(_param);
for(auto& gs : _graphics) 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) void* Application::newTexture(int w, int h)
{ {
_textures.emplace_front().create(nullptr, w, h, VK_FORMAT_R8G8B8A8_UNORM, "__mlx_unamed_user_texture"); MLX_PROFILE_FUNCTION();
#ifdef DEBUG
_textures.emplace_front().create(nullptr, w, h, VK_FORMAT_R8G8B8A8_UNORM, "__mlx_unamed_user_texture");
#else
_textures.emplace_front().create(nullptr, w, h, VK_FORMAT_R8G8B8A8_UNORM, nullptr);
#endif
return &_textures.front(); return &_textures.front();
} }
void* Application::newStbTexture(char* file, int* w, int* h) void* Application::newStbTexture(char* file, int* w, int* h)
{ {
MLX_PROFILE_FUNCTION();
_textures.emplace_front(stbTextureLoad(file, w, h)); _textures.emplace_front(stbTextureLoad(file, w, h));
return &_textures.front(); return &_textures.front();
} }
void Application::destroyTexture(void* ptr) void Application::destroyTexture(void* ptr)
{ {
vkDeviceWaitIdle(Render_Core::get().getDevice().get()); MLX_PROFILE_FUNCTION();
vkDeviceWaitIdle(Render_Core::get().getDevice().get()); // TODO : synchronize with another method than waiting for GPU to be idle
if(ptr == nullptr)
{
core::error::report(e_kind::error, "invalid image ptr (NULL)");
return;
}
else if(std::find_if(_textures.begin(), _textures.end(), [=](const Texture& texture)
{
return &texture == ptr;
}) == _textures.end())
{
core::error::report(e_kind::error, "invalid image ptr");
return;
}
Texture* texture = static_cast<Texture*>(ptr); Texture* texture = static_cast<Texture*>(ptr);
texture->destroy(); if(!texture->isInit())
core::error::report(e_kind::error, "trying to destroy a texture that has already been destroyed");
else
texture->destroy();
} }
Application::~Application() 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(); SDL_Quit();
} }
} }

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/04 21:49:46 by maldavid #+# #+# */ /* Created: 2022/10/04 21:49:46 by maldavid #+# #+# */
/* Updated: 2023/08/28 10:19:35 by maldavid ### ########.fr */ /* Updated: 2024/01/26 11:26:54 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@@ -15,15 +15,16 @@
#include <list> #include <list>
#include <memory> #include <memory>
#include <string>
#include <vector> #include <vector>
#include <utility>
#include <functional> #include <functional>
#include <core/errors.h> #include <core/errors.h>
#include <core/graphics.h> #include <core/graphics.h>
#include <platform/inputs.h> #include <platform/inputs.h>
#include <mlx_profile.h>
#include <core/profiler.h>
#include <core/fps.h>
namespace mlx::core namespace mlx::core
{ {
@@ -37,36 +38,40 @@ namespace mlx::core
inline void onEvent(void* win, int event, int (*funct_ptr)(int, void*), void* param) noexcept; inline void onEvent(void* win, int event, int (*funct_ptr)(int, void*), void* param) noexcept;
inline void getScreenSize(int* w, int* h) noexcept; inline void getScreenSize(void* win, int* w, int* h) noexcept;
inline void* newGraphicsSuport(std::size_t w, std::size_t h, std::string title); inline void setFPSCap(std::uint32_t fps) noexcept;
inline void* newGraphicsSuport(std::size_t w, std::size_t h, const char* title);
inline void clearGraphicsSupport(void* win); inline void clearGraphicsSupport(void* win);
inline void destroyGraphicsSupport(void* win); inline void destroyGraphicsSupport(void* win);
inline void pixelPut(void* win, int x, int y, uint32_t color) const noexcept; inline void pixelPut(void* win, int x, int y, std::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, std::uint32_t color, char* str);
void* newTexture(int w, int h); 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, ...) void* newStbTexture(char* file, int* w, int* h); // stb textures are format managed by stb image (png, jpg, bpm, ...)
inline void texturePut(void* win, void* img, int x, int y); inline void texturePut(void* win, void* img, int x, int y);
inline int getTexturePixel(void* img, int x, int y); inline int getTexturePixel(void* img, int x, int y);
inline void setTexturePixel(void* img, int x, int y, uint32_t color); inline void setTexturePixel(void* img, int x, int y, std::uint32_t color);
void destroyTexture(void* ptr); void destroyTexture(void* ptr);
inline void loopHook(int (*f)(void*), void* param); inline void loopHook(int (*f)(void*), void* param);
inline void loopEnd() noexcept; inline void loopEnd() noexcept;
inline void loadFont(void* win, const std::filesystem::path& filepath, float scale);
void run() noexcept; void run() noexcept;
~Application(); ~Application();
private: private:
FpsManager _fps;
std::list<Texture> _textures; std::list<Texture> _textures;
std::vector<std::unique_ptr<GraphicsSupport>> _graphics; std::vector<std::unique_ptr<GraphicsSupport>> _graphics;
std::function<int(void*)> _loop_hook; std::function<int(void*)> _loop_hook;
std::unique_ptr<Input> _in; std::unique_ptr<Input> _in;
void* _param = nullptr; void* _param = nullptr;
bool _is_loop_running = false;
}; };
} }

View File

@@ -12,6 +12,33 @@
#include <core/application.h> #include <core/application.h>
#define CHECK_WINDOW_PTR(win) \
if(win == nullptr) \
{ \
core::error::report(e_kind::error, "invalid window ptr (NULL)"); \
return; \
} \
else if(*static_cast<int*>(win) < 0 || *static_cast<int*>(win) > static_cast<int>(_graphics.size()))\
{ \
core::error::report(e_kind::error, "invalid window ptr"); \
return; \
} else {}
#define CHECK_IMAGE_PTR(img, retval) \
if(img == nullptr) \
{ \
core::error::report(e_kind::error, "invalid image ptr (NULL)"); \
retval; \
} \
else if(std::find_if(_textures.begin(), _textures.end(), [=](const Texture& texture) \
{ \
return &texture == img; \
}) == _textures.end()) \
{ \
core::error::report(e_kind::error, "invalid image ptr"); \
retval; \
} else {}
namespace mlx::core namespace mlx::core
{ {
void Application::getMousePos(int* x, int* y) noexcept void Application::getMousePos(int* x, int* y) noexcept
@@ -22,67 +49,142 @@ namespace mlx::core
void Application::mouseMove(void* win, int x, int y) noexcept 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_WarpMouseInWindow(_graphics[*static_cast<int*>(win)]->getWindow()->getNativeWindow(), x, y);
SDL_PumpEvents(); SDL_PumpEvents();
SDL_FlushEvent(SDL_MOUSEMOTION);
} }
void Application::onEvent(void* win, int event, int (*funct_ptr)(int, void*), void* param) noexcept 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); _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_DisplayMode DM;
SDL_GetDesktopDisplayMode(0, &DM); SDL_GetDesktopDisplayMode(SDL_GetWindowDisplayIndex(_graphics[*static_cast<int*>(win)]->getWindow()->getNativeWindow()), &DM);
*w = DM.w; *w = DM.w;
*h = DM.h; *h = DM.h;
} }
void* Application::newGraphicsSuport(std::size_t w, std::size_t h, std::string title) void Application::setFPSCap(std::uint32_t fps) noexcept
{ {
_graphics.emplace_back(std::make_unique<GraphicsSupport>(w, h, title, _graphics.size())); _fps.setMaxFPS(fps);
_in->addWindow(_graphics.back()->getWindow()); }
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()); return static_cast<void*>(&_graphics.back()->getID());
} }
void Application::clearGraphicsSupport(void* win) void Application::clearGraphicsSupport(void* win)
{ {
MLX_PROFILE_FUNCTION();
CHECK_WINDOW_PTR(win);
_graphics[*static_cast<int*>(win)]->clearRenderData(); _graphics[*static_cast<int*>(win)]->clearRenderData();
} }
void Application::destroyGraphicsSupport(void* win) void Application::destroyGraphicsSupport(void* win)
{ {
MLX_PROFILE_FUNCTION();
CHECK_WINDOW_PTR(win);
_graphics[*static_cast<int*>(win)].reset(); _graphics[*static_cast<int*>(win)].reset();
} }
void Application::pixelPut(void* win, int x, int y, uint32_t color) const noexcept void Application::pixelPut(void* win, int x, int y, std::uint32_t color) const noexcept
{ {
MLX_PROFILE_FUNCTION();
CHECK_WINDOW_PTR(win);
_graphics[*static_cast<int*>(win)]->pixelPut(x, y, color); _graphics[*static_cast<int*>(win)]->pixelPut(x, y, color);
} }
void Application::stringPut(void* win, int x, int y, int color, char* str) void Application::stringPut(void* win, int x, int y, std::uint32_t color, char* str)
{ {
MLX_PROFILE_FUNCTION();
CHECK_WINDOW_PTR(win);
if(str == nullptr)
{
core::error::report(e_kind::error, "wrong text (NULL)");
return;
}
if(std::strlen(str) == 0)
{
core::error::report(e_kind::warning, "trying to put an empty text");
return;
}
_graphics[*static_cast<int*>(win)]->stringPut(x, y, color, str); _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) void Application::texturePut(void* win, void* img, int x, int y)
{ {
MLX_PROFILE_FUNCTION();
CHECK_WINDOW_PTR(win);
CHECK_IMAGE_PTR(img, return);
Texture* texture = static_cast<Texture*>(img); Texture* texture = static_cast<Texture*>(img);
_graphics[*static_cast<int*>(win)]->texturePut(texture, x, y); if(!texture->isInit())
core::error::report(e_kind::error, "trying to put a texture that has been destroyed");
else
_graphics[*static_cast<int*>(win)]->texturePut(texture, x, y);
} }
int Application::getTexturePixel(void* img, int x, int y) int Application::getTexturePixel(void* img, int x, int y)
{ {
MLX_PROFILE_FUNCTION();
CHECK_IMAGE_PTR(img, return 0);
Texture* texture = static_cast<Texture*>(img); 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); return texture->getPixel(x, y);
} }
void Application::setTexturePixel(void* img, int x, int y, uint32_t color) void Application::setTexturePixel(void* img, int x, int y, std::uint32_t color)
{ {
MLX_PROFILE_FUNCTION();
CHECK_IMAGE_PTR(img, return);
Texture* texture = static_cast<Texture*>(img); Texture* texture = static_cast<Texture*>(img);
texture->setPixel(x, y, color); if(!texture->isInit())
core::error::report(e_kind::error, "trying to set a pixel on texture that has been destroyed");
else
texture->setPixel(x, y, color);
} }
void Application::loopHook(int (*f)(void*), void* param) void Application::loopHook(int (*f)(void*), void* param)

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/04 17:35:20 by maldavid #+# #+# */ /* Created: 2022/10/04 17:35:20 by maldavid #+# #+# */
/* Updated: 2023/11/14 11:43:30 by maldavid ### ########.fr */ /* Updated: 2024/02/23 22:37:24 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@@ -15,182 +15,292 @@
#include "application.h" #include "application.h"
#include <renderer/core/render_core.h> #include <renderer/core/render_core.h>
#include <filesystem> #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" extern "C"
{ {
void* mlx_init() void* mlx_init()
{ {
static bool init = false; if(__mlx_ptr != nullptr)
if(init)
{ {
mlx::core::error::report(e_kind::error, "MLX cannot be initialized multiple times"); mlx::core::error::report(e_kind::error, "MLX cannot be initialized multiple times");
return NULL; return NULL; // not nullptr for the C compatibility
} }
mlx::MemManager::get(); // just to initialize the C garbage collector
mlx::core::Application* app = new mlx::core::Application;
mlx::Render_Core::get().init(); mlx::Render_Core::get().init();
init = true; if(app == nullptr)
return new mlx::core::Application(); mlx::core::error::report(e_kind::fatal_error, "Tout a pété");
__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; 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; 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; return 0;
} }
int mlx_mouse_show() int mlx_mouse_show()
{ {
return SDL_ShowCursor(SDL_ENABLE); SDL_ShowCursor(SDL_ENABLE);
return 0;
} }
int mlx_mouse_hide() int mlx_mouse_hide()
{ {
return SDL_ShowCursor(SDL_DISABLE); SDL_ShowCursor(SDL_DISABLE);
}
int mlx_mouse_move(mlx::core::Application* mlx, void* win, int x, int y)
{
mlx->mouseMove(win, x, y);
return 0; 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; 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; return 0;
} }
void* mlx_new_image(mlx::core::Application* mlx, int width, int height) int mlx_on_event(void* mlx, void* win, mlx_event_type event, int (*funct_ptr)(int, void*), void* param)
{ {
return mlx->newTexture(width, height); MLX_CHECK_APPLICATION_POINTER(mlx);
static_cast<mlx::core::Application*>(mlx)->onEvent(win, static_cast<int>(event), funct_ptr, param);
return 0;
} }
int mlx_get_image_pixel(mlx::core::Application* mlx, void* img, int x, int y) void* mlx_new_image(void* mlx, int width, int height)
{ {
return mlx->getTexturePixel(img, x, y); MLX_CHECK_APPLICATION_POINTER(mlx);
if (width <= 0 || height <= 0)
mlx::core::error::report(e_kind::fatal_error, "invalid image size (%d x %d)", width, height);
return static_cast<mlx::core::Application*>(mlx)->newTexture(width, height);
} }
void mlx_set_image_pixel(mlx::core::Application* mlx, void* img, int x, int y, int color) int mlx_get_image_pixel(void* mlx, void* img, int x, int y)
{ {
MLX_CHECK_APPLICATION_POINTER(mlx);
int color = static_cast<mlx::core::Application*>(mlx)->getTexturePixel(img, x, y);
unsigned char color_bits[4];
color_bits[0] = (color & 0x000000FF);
color_bits[1] = (color & 0x0000FF00) >> 8;
color_bits[2] = (color & 0x00FF0000) >> 16;
color_bits[3] = (color & 0xFF000000) >> 24;
return *reinterpret_cast<int*>(color_bits);
}
void mlx_set_image_pixel(void* mlx, void* img, int x, int y, int color)
{
MLX_CHECK_APPLICATION_POINTER(mlx);
unsigned char color_bits[4]; unsigned char color_bits[4];
color_bits[0] = (color & 0x00FF0000) >> 16; color_bits[0] = (color & 0x00FF0000) >> 16;
color_bits[1] = (color & 0x0000FF00) >> 8; color_bits[1] = (color & 0x0000FF00) >> 8;
color_bits[2] = color & 0x000000FF; color_bits[2] = (color & 0x000000FF);
color_bits[3] = 0xFF; 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; 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; 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); std::filesystem::path file(filename);
if(file.extension() != ".png") if(file.extension() != ".png")
{ {
mlx::core::error::report(e_kind::error, "PNG loader : not a png file '%s'", filename); mlx::core::error::report(e_kind::error, "PNG loader : not a png file '%s'", filename);
return nullptr; 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); std::filesystem::path file(filename);
if(file.extension() != ".jpg" && file.extension() != ".jpeg") if(file.extension() != ".jpg" && file.extension() != ".jpeg")
{ {
mlx::core::error::report(e_kind::error, "PNG loader : not a jpg file '%s'", filename); mlx::core::error::report(e_kind::error, "JPG loader : not a jpg file '%s'", filename);
return nullptr; 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); std::filesystem::path file(filename);
if(file.extension() != ".bmp" && file.extension() != ".dib") if(file.extension() != ".bmp" && file.extension() != ".dib")
{ {
mlx::core::error::report(e_kind::error, "PNG loader : not a jpg file '%s'", filename); mlx::core::error::report(e_kind::error, "BMP loader : not a bmp file '%s'", filename);
return nullptr; 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]; unsigned char color_bits[4];
color_bits[0] = (color & 0x00FF0000) >> 16; color_bits[0] = (color & 0x00FF0000) >> 16;
color_bits[1] = (color & 0x0000FF00) >> 8; color_bits[1] = (color & 0x0000FF00) >> 8;
color_bits[2] = color & 0x000000FF; color_bits[2] = (color & 0x000000FF);
color_bits[3] = 0xFF; color_bits[3] = (color & 0xFF000000) >> 24;
mlx->pixelPut(win, x, y, *reinterpret_cast<unsigned int*>(color_bits)); static_cast<mlx::core::Application*>(mlx)->pixelPut(win, x, y, *reinterpret_cast<unsigned int*>(color_bits));
return 0; 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]; unsigned char color_bits[4];
color_bits[0] = (color & 0x00FF0000) >> 16; color_bits[0] = (color & 0x00FF0000) >> 16;
color_bits[1] = (color & 0x0000FF00) >> 8; color_bits[1] = (color & 0x0000FF00) >> 8;
color_bits[2] = color & 0x000000FF; color_bits[2] = (color & 0x000000FF);
color_bits[3] = 0xFF; color_bits[3] = (color & 0xFF000000) >> 24;
mlx->stringPut(win, x, y, *reinterpret_cast<unsigned int*>(color_bits), str); static_cast<mlx::core::Application*>(mlx)->stringPut(win, x, y, *reinterpret_cast<unsigned int*>(color_bits), str);
return 0; return 0;
} }
int mlx_clear_window(mlx::core::Application* mlx, void* win) void mlx_set_font(void* mlx, void* win, char* filepath)
{ {
mlx->clearGraphicsSupport(win); 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(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;
}
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(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(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;
}
static_cast<mlx::core::Application*>(mlx)->loadFont(win, file, scale);
}
int mlx_clear_window(void* mlx, void* win)
{
MLX_CHECK_APPLICATION_POINTER(mlx);
static_cast<mlx::core::Application*>(mlx)->clearGraphicsSupport(win);
return 0; 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; 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::Render_Core::get().destroy();
__mlx_ptr = nullptr;
return 0; return 0;
} }
int mlx_get_screens_size(mlx::core::Application* mlx, int* w, int* h) int mlx_get_screens_size(void* mlx, void* win, int* w, int* h)
{ {
mlx->getScreenSize(w, h); MLX_CHECK_APPLICATION_POINTER(mlx);
static_cast<mlx::core::Application*>(mlx)->getScreenSize(win, w, h);
return 0;
}
int mlx_set_fps_goal(void* mlx, int fps)
{
MLX_CHECK_APPLICATION_POINTER(mlx);
if(fps < 0)
{
mlx::core::error::report(e_kind::error, "You cannot set a negative FPS cap (nice try)");
fps = -fps;
}
if(fps == 0)
{
mlx::core::error::report(e_kind::error, "You cannot set a FPS cap to 0 (nice try)");
return 0;
}
static_cast<mlx::core::Application*>(mlx)->setFPSCap(static_cast<std::uint32_t>(fps));
return 0; return 0;
} }
} }

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/04 17:48:06 by maldavid #+# #+# */ /* 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> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/04 17:42:32 by maldavid #+# #+# */ /* 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__ #define __MLX_ERRORS__
#include <string> #include <string>
#include <mlx_profile.h>
enum class e_kind 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<std::uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count());
_fps_now = static_cast<std::uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count());
}
bool FpsManager::update()
{
using namespace std::chrono_literals;
_fps_now = static_cast<std::uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count());
if(SDL_GetTicks64() - _timer > 1000)
_timer += 1000;
_fps_elapsed_time = _fps_now - _fps_before;
if(_fps_elapsed_time >= _ns)
{
_fps_before += _ns;
return true;
}
std::this_thread::sleep_for(std::chrono::duration<double, std::nano>(_ns));
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(std::uint32_t fps) noexcept { _max_fps = fps; _ns = 1000000000.0 / fps; }
~FpsManager() = default;
private:
double _ns = 1000000000.0 / 1'337'000.0;
std::uint64_t _timer = 0;
std::uint64_t _fps_before = 0;
std::uint64_t _fps_now = 0;
std::uint32_t _max_fps = 1'337'000;
std::uint32_t _fps_elapsed_time = 0;
};
}
#endif

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/02 15:13:55 by maldavid #+# #+# */ /* Created: 2023/04/02 15:13:55 by maldavid #+# #+# */
/* Updated: 2023/11/14 06:59:12 by maldavid ### ########.fr */ /* Updated: 2024/01/11 04:38:53 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@@ -14,55 +14,62 @@
namespace mlx namespace mlx
{ {
GraphicsSupport::GraphicsSupport(std::size_t w, std::size_t h, const std::string& title, int id) : GraphicsSupport::GraphicsSupport(std::size_t w, std::size_t h, Texture* render_target, int id) :
_window(std::make_shared<MLX_Window>(w, h, title)), _window(nullptr),
_renderer(std::make_unique<Renderer>()), _text_put_pipeline(std::make_unique<TextPutPipeline>()), _renderer(std::make_unique<Renderer>()),
_id(id) _width(w),
_height(h),
_id(id),
_has_window(false)
{ {
_renderer->setWindow(_window.get()); MLX_PROFILE_FUNCTION();
_renderer->init(); _renderer->setWindow(nullptr);
_renderer->init(render_target);
_pixel_put_pipeline.init(w, h, *_renderer); _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 = { static std::array<VkDescriptorSet, 2> sets = {
_renderer->getVertDescriptorSet().get(), _renderer->getVertDescriptorSet().get(),
VK_NULL_HANDLE VK_NULL_HANDLE
}; };
for(auto& data : _textures_to_render) for(auto& data : _drawlist)
{ data->render(sets, *_renderer);
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);
}
_pixel_put_pipeline.present(); _pixel_put_pipeline.render(sets, *_renderer);
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();
_renderer->endFrame(); _renderer->endFrame();
for(auto& data : _textures_to_render) for(auto& data : _drawlist)
data.texture->resetUpdate(); data->resetUpdate();
#ifdef GRAPHICS_MEMORY_DUMP #ifdef GRAPHICS_MEMORY_DUMP
// dump memory to file every two seconds // dump memory to file every two seconds
static uint64_t timer = SDL_GetTicks64(); static std::uint64_t timer = SDL_GetTicks64();
if(SDL_GetTicks64() - timer > 2000) if(SDL_GetTicks64() - timer > 2000)
{ {
Render_Core::get().getAllocator().dumpMemoryToJson(); Render_Core::get().getAllocator().dumpMemoryToJson();
@@ -73,9 +80,12 @@ namespace mlx
GraphicsSupport::~GraphicsSupport() GraphicsSupport::~GraphicsSupport()
{ {
vkDeviceWaitIdle(Render_Core::get().getDevice().get()); MLX_PROFILE_FUNCTION();
vkDeviceWaitIdle(Render_Core::get().getDevice().get());
_text_manager.destroy();
_pixel_put_pipeline.destroy(); _pixel_put_pipeline.destroy();
_text_put_pipeline->destroy();
_renderer->destroy(); _renderer->destroy();
if(_window)
_window->destroy();
} }
} }

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/02 14:49:49 by maldavid #+# #+# */ /* Created: 2023/04/02 14:49:49 by maldavid #+# #+# */
/* Updated: 2023/11/14 11:39:55 by maldavid ### ########.fr */ /* Updated: 2024/01/11 15:47:05 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@@ -23,38 +23,58 @@
#include <platform/window.h> #include <platform/window.h>
#include <renderer/renderer.h> #include <renderer/renderer.h>
#include <renderer/pixel_put.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 <utils/non_copyable.h>
#include <renderer/images/texture.h> #include <renderer/images/texture.h>
#include <mlx_profile.h>
#include <core/profiler.h>
namespace mlx namespace mlx
{ {
class GraphicsSupport : public non_copyable class GraphicsSupport : public non_copyable
{ {
public: 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 int& getID() noexcept;
inline std::shared_ptr<MLX_Window> getWindow(); inline std::shared_ptr<MLX_Window> getWindow();
inline void beginRender() noexcept; void render() noexcept;
void endRender() noexcept;
inline void clearRenderData() noexcept; inline void clearRenderData() noexcept;
inline void pixelPut(int x, int y, uint32_t color) noexcept; inline void pixelPut(int x, int y, std::uint32_t color) noexcept;
inline void stringPut(int x, int y, int color, std::string str); inline void stringPut(int x, int y, std::uint32_t color, std::string str);
inline void texturePut(Texture* texture, int x, int y); inline void 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(); ~GraphicsSupport();
private: private:
std::unordered_set<TextureRenderData> _textures_to_render;
PixelPutPipeline _pixel_put_pipeline; PixelPutPipeline _pixel_put_pipeline;
std::vector<DrawableResource*> _drawlist;
TextManager _text_manager;
TextureManager _texture_manager;
glm::mat4 _proj = glm::mat4(1.0); glm::mat4 _proj = glm::mat4(1.0);
std::shared_ptr<MLX_Window> _window; 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::unique_ptr<Renderer> _renderer;
std::size_t _width = 0;
std::size_t _height = 0;
int _id; int _id;
bool _has_window;
}; };
} }

View File

@@ -11,39 +11,57 @@
/* ************************************************************************** */ /* ************************************************************************** */
#include <core/graphics.h> #include <core/graphics.h>
#include <iostream>
namespace mlx namespace mlx
{ {
int& GraphicsSupport::getID() noexcept { return _id; } int& GraphicsSupport::getID() noexcept { return _id; }
std::shared_ptr<MLX_Window> GraphicsSupport::getWindow() { return _window; } 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 void GraphicsSupport::clearRenderData() noexcept
{ {
_textures_to_render.clear(); MLX_PROFILE_FUNCTION();
_drawlist.clear();
_pixel_put_pipeline.clear(); _pixel_put_pipeline.clear();
_text_put_pipeline->clear(); _text_manager.clear();
_texture_manager.clear();
} }
void GraphicsSupport::pixelPut(int x, int y, uint32_t color) noexcept void GraphicsSupport::pixelPut(int x, int y, std::uint32_t color) noexcept
{ {
MLX_PROFILE_FUNCTION();
_pixel_put_pipeline.setPixel(x, y, color); _pixel_put_pipeline.setPixel(x, y, color);
} }
void GraphicsSupport::stringPut(int x, int y, int color, std::string str) void GraphicsSupport::stringPut(int x, int y, std::uint32_t color, std::string str)
{ {
_text_put_pipeline->put(x, y, color, str); MLX_PROFILE_FUNCTION();
std::pair<DrawableResource*, bool> res = _text_manager.registerText(x, y, color, str);
if(!res.second) // if this is not a completly new text draw
{
auto it = std::find(_drawlist.begin(), _drawlist.end(), res.first);
if(it != _drawlist.end())
_drawlist.erase(it);
}
_drawlist.push_back(res.first);
} }
void GraphicsSupport::texturePut(Texture* texture, int x, int y) void GraphicsSupport::texturePut(Texture* texture, int x, int y)
{ {
_textures_to_render.emplace(texture, x, y); MLX_PROFILE_FUNCTION();
auto res = _texture_manager.registerTexture(texture, x, y);
if(!res.second) // if this is not a completly new texture 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::loadFont(const std::filesystem::path& filepath, float 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> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/05 16:30:19 by maldavid #+# #+# */ /* Created: 2022/10/05 16:30:19 by maldavid #+# #+# */
/* Updated: 2023/08/28 10:49:03 by maldavid ### ########.fr */ /* Updated: 2024/02/23 22:27:30 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
#include "inputs.h" #include "inputs.h"
#include <mlx.h> #include <mlx.h>
#include <cstring> #include <core/profiler.h>
namespace mlx namespace mlx
{ {
Input::Input()
{
std::memset(_keys.data(), 0, SDL_NUM_SCANCODES);
std::memset(_mouse.data(), 0, 8);
}
void Input::update() void Input::update()
{ {
MLX_PROFILE_FUNCTION();
_xRel = 0; _xRel = 0;
_yRel = 0; _yRel = 0;
@@ -38,8 +33,8 @@ namespace mlx
_yRel = _event.motion.yrel; _yRel = _event.motion.yrel;
} }
uint32_t id = _event.window.windowID; std::uint32_t id = _event.window.windowID;
if(!_events_hooks.count(id)) if(_events_hooks.find(id) == _events_hooks.end())
continue; continue;
auto& hooks = _events_hooks[id]; auto& hooks = _events_hooks[id];
@@ -47,7 +42,6 @@ namespace mlx
{ {
case SDL_KEYDOWN: case SDL_KEYDOWN:
{ {
_keys[_event.key.keysym.scancode] = static_cast<uint8_t>(action::down);
if(hooks[MLX_KEYDOWN].hook) if(hooks[MLX_KEYDOWN].hook)
hooks[MLX_KEYDOWN].hook(_event.key.keysym.scancode, hooks[MLX_KEYDOWN].param); hooks[MLX_KEYDOWN].hook(_event.key.keysym.scancode, hooks[MLX_KEYDOWN].param);
break; break;
@@ -55,7 +49,6 @@ namespace mlx
case SDL_KEYUP: case SDL_KEYUP:
{ {
_keys[_event.key.keysym.scancode] = static_cast<uint8_t>(action::up);
if(hooks[MLX_KEYUP].hook) if(hooks[MLX_KEYUP].hook)
hooks[MLX_KEYUP].hook(_event.key.keysym.scancode, hooks[MLX_KEYUP].param); hooks[MLX_KEYUP].hook(_event.key.keysym.scancode, hooks[MLX_KEYUP].param);
break; break;
@@ -63,7 +56,6 @@ namespace mlx
case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONDOWN:
{ {
_mouse[_event.button.button] = static_cast<uint8_t>(action::down);
if(hooks[MLX_MOUSEDOWN].hook) if(hooks[MLX_MOUSEDOWN].hook)
hooks[MLX_MOUSEDOWN].hook(_event.button.button, hooks[MLX_MOUSEDOWN].param); hooks[MLX_MOUSEDOWN].hook(_event.button.button, hooks[MLX_MOUSEDOWN].param);
break; break;
@@ -71,12 +63,28 @@ namespace mlx
case SDL_MOUSEBUTTONUP: case SDL_MOUSEBUTTONUP:
{ {
_mouse[_event.button.button] = static_cast<uint8_t>(action::up);
if(hooks[MLX_MOUSEUP].hook) if(hooks[MLX_MOUSEUP].hook)
hooks[MLX_MOUSEUP].hook(_event.button.button, hooks[MLX_MOUSEUP].param); hooks[MLX_MOUSEUP].hook(_event.button.button, hooks[MLX_MOUSEUP].param);
break; 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: case SDL_WINDOWEVENT:
{ {
auto& win_hook = hooks[MLX_WINDOW_EVENT]; auto& win_hook = hooks[MLX_WINDOW_EVENT];
@@ -115,19 +123,19 @@ namespace mlx
case SDL_WINDOWEVENT_FOCUS_GAINED: case SDL_WINDOWEVENT_FOCUS_GAINED:
{ {
if(win_hook.hook) if(win_hook.hook)
win_hook.hook(4, win_hook.param); win_hook.hook(5, win_hook.param);
break; break;
} }
case SDL_WINDOWEVENT_LEAVE: case SDL_WINDOWEVENT_LEAVE:
{ {
if(win_hook.hook) if(win_hook.hook)
win_hook.hook(5, win_hook.param); win_hook.hook(6, win_hook.param);
break; break;
} }
case SDL_WINDOWEVENT_FOCUS_LOST: case SDL_WINDOWEVENT_FOCUS_LOST:
{ {
if(win_hook.hook) if(win_hook.hook)
win_hook.hook(4, win_hook.param); win_hook.hook(7, win_hook.param);
break; break;
} }

View File

@@ -6,40 +6,36 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/05 16:27:35 by maldavid #+# #+# */ /* Created: 2022/10/05 16:27:35 by maldavid #+# #+# */
/* Updated: 2023/04/19 12:14:43 by maldavid ### ########.fr */ /* Updated: 2024/02/25 07:51:55 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
#include <array> #include <array>
#include <memory> #include <memory>
#include <vector>
#include <cstdint> #include <cstdint>
#include <functional> #include <function.h>
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <unordered_map> #include <unordered_map>
#include <mlx_profile.h>
#include "window.h" #include "window.h"
namespace mlx namespace mlx
{ {
enum class action : uint8_t { up = (1 << 1), down = (1 << 2) };
struct Hook struct Hook
{ {
std::function<int(int, void*)> hook; func::function<int(int, void*)> hook;
void* param = nullptr; void* param = nullptr;
}; };
class Input class Input
{ {
public: public:
Input(); Input() = default;
void update(); 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 bool isMouseMoving() const noexcept { return _xRel || _yRel; }
inline int getX() const noexcept { return _x; } inline int getX() const noexcept { return _x; }
@@ -48,7 +44,7 @@ namespace mlx
inline int getXRel() const noexcept { return _xRel; } inline int getXRel() const noexcept { return _xRel; }
inline int getYRel() const noexcept { return _yRel; } inline int getYRel() const noexcept { return _yRel; }
inline bool is_running() const noexcept { return !_end; } inline bool isRunning() const noexcept { return !_end; }
inline constexpr void finish() noexcept { _end = true; } inline constexpr void finish() noexcept { _end = true; }
inline void addWindow(std::shared_ptr<MLX_Window> window) inline void addWindow(std::shared_ptr<MLX_Window> window)
@@ -57,7 +53,7 @@ namespace mlx
_events_hooks[window->getID()] = {}; _events_hooks[window->getID()] = {};
} }
inline void onEvent(uint32_t id, int event, int (*funct_ptr)(int, void*), void* param) noexcept inline void onEvent(std::uint32_t id, int event, int (*funct_ptr)(int, void*), void* param) noexcept
{ {
_events_hooks[id][event].hook = funct_ptr; _events_hooks[id][event].hook = funct_ptr;
_events_hooks[id][event].param = param; _events_hooks[id][event].param = param;
@@ -66,11 +62,9 @@ namespace mlx
~Input() = default; ~Input() = default;
private: private:
std::array<uint8_t, SDL_NUM_SCANCODES> _keys; std::unordered_map<std::uint32_t, std::shared_ptr<MLX_Window>> _windows;
std::unordered_map<uint32_t, std::shared_ptr<MLX_Window>> _windows; std::unordered_map<std::uint32_t, std::array<Hook, 6>> _events_hooks;
std::unordered_map<uint32_t, std::array<Hook, 5>> _events_hooks;
SDL_Event _event; SDL_Event _event;
std::array<uint8_t, 8> _mouse;
int _x = 0; int _x = 0;
int _y = 0; int _y = 0;

View File

@@ -6,31 +6,51 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/04 17:36:44 by maldavid #+# #+# */ /* Created: 2022/10/04 17:36:44 by maldavid #+# #+# */
/* Updated: 2023/11/08 20:24:38 by maldavid ### ########.fr */ /* Updated: 2024/01/16 07:59:21 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
#include <platform/window.h> #include <platform/window.h>
#include <core/errors.h> #include <core/errors.h>
#include <utils/icon_mlx.h>
namespace mlx namespace mlx
{ {
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
constexpr const std::uint32_t rmask = 0xff000000;
constexpr const std::uint32_t gmask = 0x00ff0000;
constexpr const std::uint32_t bmask = 0x0000ff00;
constexpr const std::uint32_t amask = 0x000000ff;
#else
constexpr const std::uint32_t rmask = 0x000000ff;
constexpr const std::uint32_t gmask = 0x0000ff00;
constexpr const std::uint32_t bmask = 0x00ff0000;
constexpr const std::uint32_t amask = 0xff000000;
#endif
MLX_Window::MLX_Window(std::size_t w, std::size_t h, const std::string& title) : _width(w), _height(h) 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); _win = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h, SDL_WINDOW_VULKAN | SDL_WINDOW_SHOWN);
if(!_win) if(!_win)
core::error::report(e_kind::fatal_error, std::string("unable to open a new window, ") + SDL_GetError()); core::error::report(e_kind::fatal_error, std::string("unable to open a new window, ") + SDL_GetError());
_id = SDL_GetWindowID(_win); _id = SDL_GetWindowID(_win);
_icon = SDL_CreateRGBSurfaceFrom(static_cast<void*>(logo_mlx), logo_mlx_width, logo_mlx_height, 32, 4 * logo_mlx_width, rmask, gmask, bmask, amask);
SDL_SetWindowIcon(_win, _icon);
} }
void MLX_Window::destroy() noexcept void MLX_Window::destroy() noexcept
{ {
if(_win) if(_win != nullptr)
{
SDL_DestroyWindow(_win); SDL_DestroyWindow(_win);
} _win = nullptr;
}
MLX_Window::~MLX_Window() if(_icon != nullptr)
{ {
destroy(); SDL_FreeSurface(_icon);
_icon = nullptr;
}
} }
} }

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/04 21:53:12 by maldavid #+# #+# */ /* Created: 2022/10/04 21:53:12 by maldavid #+# #+# */
/* Updated: 2023/11/08 20:24:46 by maldavid ### ########.fr */ /* Updated: 2023/12/21 00:24:26 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@@ -15,6 +15,7 @@
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <string> #include <string>
#include <mlx_profile.h>
namespace mlx namespace mlx
{ {
@@ -26,17 +27,18 @@ namespace mlx
inline SDL_Window* getNativeWindow() const noexcept { return _win; } inline SDL_Window* getNativeWindow() const noexcept { return _win; }
inline int getWidth() const noexcept { return _width; } inline int getWidth() const noexcept { return _width; }
inline int getHeight() const noexcept { return _height; } inline int getHeight() const noexcept { return _height; }
inline uint32_t getID() const noexcept { return _id; } inline std::uint32_t getID() const noexcept { return _id; }
void destroy() noexcept; void destroy() noexcept;
~MLX_Window(); ~MLX_Window() = default;
private: private:
SDL_Surface* _icon = nullptr;
SDL_Window* _win = nullptr; SDL_Window* _win = nullptr;
int _width = 0; int _width = 0;
int _height = 0; int _height = 0;
uint32_t _id = -1; std::uint32_t _id = -1;
}; };
} }

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/08 18:55:57 by maldavid #+# #+# */ /* Created: 2022/10/08 18:55:57 by maldavid #+# #+# */
/* Updated: 2023/11/14 09:31:58 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_pool.h>
#include <renderer/command/vk_cmd_buffer.h> #include <renderer/command/vk_cmd_buffer.h>
#include <renderer/core/render_core.h> #include <renderer/core/render_core.h>
#include <core/profiler.h>
#include <vma.h> #include <vma.h>
#include <cstring> #include <cstring>
#include <iostream>
namespace mlx namespace mlx
{ {
void Buffer::create(Buffer::kind type, VkDeviceSize size, VkBufferUsageFlags usage, const char* name, const void* data) void Buffer::create(Buffer::kind type, VkDeviceSize size, VkBufferUsageFlags usage, const char* name, const void* data)
{ {
MLX_PROFILE_FUNCTION();
_usage = usage; _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)"); core::error::report(e_kind::warning, "Vulkan : trying to create constant buffer without data (constant buffers cannot be modified after creation)");
return; return;
@@ -45,70 +46,93 @@ namespace mlx
mapMem(&mapped); mapMem(&mapped);
std::memcpy(mapped, data, size); std::memcpy(mapped, data, size);
unmapMem(); unmapMem();
if(type == Buffer::kind::constant) if(type == Buffer::kind::constant || type == Buffer::kind::dynamic_device_local)
pushToGPU(); pushToGPU();
} }
} }
void Buffer::destroy() noexcept void Buffer::destroy() noexcept
{ {
if(_is_mapped) MLX_PROFILE_FUNCTION();
unmapMem(); // not creating destroyer in `create` as some image may be copied (and so `this` will be invalid)
if(_buffer != VK_NULL_HANDLE) //CmdResource::setDestroyer([this]()
Render_Core::get().getAllocator().destroyBuffer(_allocation, _buffer); //{
_buffer = VK_NULL_HANDLE; 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{}; VkBufferCreateInfo bufferInfo{};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = size; bufferInfo.size = size;
bufferInfo.usage = usage; bufferInfo.usage = usage;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
_name = name; #ifdef DEBUG
std::string alloc_name = _name; _name = name;
if(usage & VK_BUFFER_USAGE_INDEX_BUFFER_BIT) std::string alloc_name = _name;
alloc_name.append("_index_buffer"); if(usage & VK_BUFFER_USAGE_INDEX_BUFFER_BIT)
else if(usage & VK_BUFFER_USAGE_VERTEX_BUFFER_BIT) alloc_name.append("_index_buffer");
alloc_name.append("_vertex_buffer"); else if(usage & VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)
else if((usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) != 1) alloc_name.append("_vertex_buffer");
alloc_name.append("_buffer"); else if(!(usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT))
_allocation = Render_Core::get().getAllocator().createBuffer(&bufferInfo, &info, _buffer, alloc_name.c_str()); alloc_name.append("_buffer");
_allocation = Render_Core::get().getAllocator().createBuffer(&bufferInfo, &info, _buffer, alloc_name.c_str());
#else
_allocation = Render_Core::get().getAllocator().createBuffer(&bufferInfo, &info, _buffer, nullptr);
#endif
_size = size; _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 void Buffer::pushToGPU() noexcept
{ {
MLX_PROFILE_FUNCTION();
VmaAllocationCreateInfo alloc_info{}; VmaAllocationCreateInfo alloc_info{};
alloc_info.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; alloc_info.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
std::string new_name = _name + "_GPU";
Buffer newBuffer; Buffer newBuffer;
newBuffer._usage = (_usage & 0xFFFFFFFC) | VK_BUFFER_USAGE_TRANSFER_DST_BIT; newBuffer._usage = (_usage & 0xFFFFFFFC) | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
newBuffer.createBuffer(newBuffer._usage, alloc_info, _size, new_name.c_str()); #ifdef DEBUG
std::string new_name = _name + "_GPU";
CmdPool cmdpool; newBuffer.createBuffer(newBuffer._usage, alloc_info, _size, new_name.c_str());
cmdpool.init(); #else
CmdBuffer cmdBuffer; newBuffer.createBuffer(newBuffer._usage, alloc_info, _size, nullptr);
cmdBuffer.init(&cmdpool); #endif
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();
this->swap(newBuffer);
if(newBuffer.copyFromBuffer(*this)) // if the copy succeded we swap the buffers, otherwise the new one is deleted
this->swap(newBuffer);
newBuffer.destroy(); newBuffer.destroy();
} }
@@ -133,6 +157,12 @@ namespace mlx
VkBufferUsageFlags temp_u = _usage; VkBufferUsageFlags temp_u = _usage;
_usage = buffer._usage; _usage = buffer._usage;
buffer._usage = temp_u; 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) void Buffer::flush(VkDeviceSize size, VkDeviceSize offset)

View File

@@ -6,22 +6,24 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 23:18:52 by maldavid #+# #+# */ /* Created: 2022/10/06 23:18:52 by maldavid #+# #+# */
/* Updated: 2023/11/14 03:24:12 by maldavid ### ########.fr */ /* Updated: 2024/01/11 05:16:58 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
#ifndef __MLX_VK_BUFFER__ #ifndef __MLX_VK_BUFFER__
#define __MLX_VK_BUFFER__ #define __MLX_VK_BUFFER__
#include <mlx_profile.h>
#include <volk.h> #include <volk.h>
#include <renderer/core/render_core.h> #include <renderer/core/render_core.h>
#include <renderer/core/cmd_resource.h>
namespace mlx namespace mlx
{ {
class Buffer class Buffer : public CmdResource
{ {
public: 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 create(kind type, VkDeviceSize size, VkBufferUsageFlags usage, const char* name, const void* data = nullptr);
void destroy() noexcept; void destroy() noexcept;
@@ -31,6 +33,7 @@ namespace mlx
inline void unmapMem() noexcept { Render_Core::get().getAllocator().unmapMemory(_allocation); _is_mapped = false; } inline void unmapMem() noexcept { Render_Core::get().getAllocator().unmapMemory(_allocation); _is_mapped = false; }
void flush(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0); void flush(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
bool copyFromBuffer(const Buffer& buffer) noexcept;
inline VkBuffer& operator()() noexcept { return _buffer; } inline VkBuffer& operator()() noexcept { return _buffer; }
inline VkBuffer& get() noexcept { return _buffer; } inline VkBuffer& get() noexcept { return _buffer; }
@@ -51,7 +54,9 @@ namespace mlx
void createBuffer(VkBufferUsageFlags usage, VmaAllocationCreateInfo info, VkDeviceSize size, const char* name); void createBuffer(VkBufferUsageFlags usage, VmaAllocationCreateInfo info, VkDeviceSize size, const char* name);
private: private:
std::string _name; #ifdef DEBUG
std::string _name;
#endif
VkBufferUsageFlags _usage = 0; VkBufferUsageFlags _usage = 0;
bool _is_mapped = false; bool _is_mapped = false;
}; };

View File

@@ -6,13 +6,14 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2023/01/25 15:05:05 by maldavid #+# #+# */ /* 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__ #ifndef __VK_IBO__
#define __VK_IBO__ #define __VK_IBO__
#include <mlx_profile.h>
#include <volk.h> #include <volk.h>
#include "vk_buffer.h" #include "vk_buffer.h"
#include <renderer/renderer.h> #include <renderer/renderer.h>
@@ -22,8 +23,8 @@ namespace mlx
class C_IBO : public Buffer class C_IBO : public Buffer
{ {
public: 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 create(std::uint32_t size, const std::uint16_t* data, const char* name) { Buffer::create(Buffer::kind::constant, size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, name, data); }
inline void bind(Renderer& renderer) noexcept { vkCmdBindIndexBuffer(renderer.getActiveCmdBuffer().get(), _buffer, _offset, VK_INDEX_TYPE_UINT16); } inline void bind(Renderer& renderer) noexcept { renderer.getActiveCmdBuffer().bindIndexBuffer(*this); }
}; };
} }

View File

@@ -6,39 +6,47 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:45:52 by maldavid #+# #+# */ /* Created: 2022/10/06 18:45:52 by maldavid #+# #+# */
/* Updated: 2023/11/14 03:27:08 by maldavid ### ########.fr */ /* Updated: 2024/01/10 18:30:57 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
#include "vk_ubo.h" #include "vk_ubo.h"
#include <cstring> #include <cstring>
#include <renderer/renderer.h> #include <renderer/renderer.h>
#include <core/profiler.h>
namespace mlx namespace mlx
{ {
void UBO::create(Renderer* renderer, uint32_t size, const char* name) void UBO::create(Renderer* renderer, std::uint32_t size, [[maybe_unused]] const char* name)
{ {
MLX_PROFILE_FUNCTION();
_renderer = renderer; _renderer = renderer;
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
{ {
std::string name_frame = name; #ifdef DEBUG
name_frame.append(std::to_string(i)); std::string name_frame = name;
_buffers[i].create(Buffer::kind::uniform, size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, name_frame.c_str()); name_frame.append(std::to_string(i));
_buffers[i].create(Buffer::kind::uniform, size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, name_frame.c_str());
#else
_buffers[i].create(Buffer::kind::uniform, size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, nullptr);
#endif
_buffers[i].mapMem(&_maps[i]); _buffers[i].mapMem(&_maps[i]);
if(_maps[i] == nullptr) if(_maps[i] == nullptr)
core::error::report(e_kind::fatal_error, "Vulkan : unable to map a uniform buffer"); core::error::report(e_kind::fatal_error, "Vulkan : unable to map a uniform buffer");
} }
} }
void UBO::setData(uint32_t size, const void* data) void UBO::setData(std::uint32_t size, const void* data)
{ {
std::memcpy(_maps[_renderer->getActiveImageIndex()], data, static_cast<size_t>(size)); MLX_PROFILE_FUNCTION();
std::memcpy(_maps[_renderer->getActiveImageIndex()], data, static_cast<std::size_t>(size));
} }
void UBO::setDynamicData(uint32_t size, const void* data) void UBO::setDynamicData(std::uint32_t size, const void* data)
{ {
std::memcpy(_maps[_renderer->getActiveImageIndex()], data, static_cast<size_t>(size)); MLX_PROFILE_FUNCTION();
std::memcpy(_maps[_renderer->getActiveImageIndex()], data, static_cast<std::size_t>(size));
_buffers[_renderer->getActiveImageIndex()].flush(); _buffers[_renderer->getActiveImageIndex()].flush();
} }

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:45:29 by maldavid #+# #+# */ /* Created: 2022/10/06 18:45:29 by maldavid #+# #+# */
/* Updated: 2023/11/14 03:26:10 by maldavid ### ########.fr */ /* Updated: 2023/12/08 19:06:28 by kbz_8 ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@@ -16,16 +16,17 @@
#include "vk_buffer.h" #include "vk_buffer.h"
#include <array> #include <array>
#include <cstddef> #include <cstddef>
#include <mlx_profile.h>
namespace mlx namespace mlx
{ {
class UBO class UBO
{ {
public: public:
void create(class Renderer* renderer, uint32_t size, const char* name); void create(class Renderer* renderer, std::uint32_t size, const char* name);
void setData(uint32_t size, const void* data); void setData(std::uint32_t size, const void* data);
void setDynamicData(uint32_t size, const void* data); void setDynamicData(std::uint32_t size, const void* data);
void destroy() noexcept; void destroy() noexcept;

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:28:08 by maldavid #+# #+# */ /* Created: 2022/10/06 18:28:08 by maldavid #+# #+# */
/* Updated: 2023/11/10 08:33:52 by maldavid ### ########.fr */ /* Updated: 2023/12/12 22:17:14 by kbz_8 ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@@ -15,17 +15,41 @@
namespace mlx namespace mlx
{ {
void VBO::setData(uint32_t size, const void* data) void VBO::setData(std::uint32_t size, const void* data)
{ {
if(size > getSize()) 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()); 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) if(data == nullptr)
core::error::report(e_kind::warning, "Vulkan : mapping null data in a vertex buffer"); core::error::report(e_kind::warning, "Vulkan : mapping null data in a vertex buffer");
void* temp = nullptr; void* temp = nullptr;
mapMem(&temp); mapMem(&temp);
std::memcpy(temp, data, static_cast<size_t>(size)); std::memcpy(temp, data, static_cast<std::size_t>(size));
unmapMem(); unmapMem();
} }
void D_VBO::setData(std::uint32_t size, const void* data)
{
if(size > getSize())
{
core::error::report(e_kind::error, "Vulkan : trying to store to much data in a vertex buffer (%d bytes in %d bytes)", size, getSize());
return;
}
if(data == nullptr)
core::error::report(e_kind::warning, "Vulkan : mapping null data in a vertex buffer");
Buffer tmp_buf;
#ifdef DEBUG
tmp_buf.create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, "tmp_buffer", data);
#else
tmp_buf.create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, nullptr, data);
#endif
copyFromBuffer(tmp_buf);
tmp_buf.destroy();
}
} }

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:27:38 by maldavid #+# #+# */ /* 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 "vk_buffer.h"
#include <renderer/renderer.h> #include <renderer/renderer.h>
#include <mlx_profile.h>
namespace mlx namespace mlx
{ {
class VBO : public Buffer class VBO : public Buffer
{ {
public: 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(std::uint32_t size, const void* data, const char* name) { Buffer::create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, name, data); }
void setData(uint32_t size, const void* data); void setData(std::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(std::uint32_t size, const void* data, const char* name) { Buffer::create(Buffer::kind::dynamic_device_local, size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, name, data); }
void setData(std::uint32_t size, const void* data);
inline void bind(Renderer& renderer) noexcept { renderer.getActiveCmdBuffer().bindVertexBuffer(*this); }
}; };
class C_VBO : public Buffer class C_VBO : public Buffer
{ {
public: 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 create(std::uint32_t size, const void* data, const char* name) { Buffer::create(Buffer::kind::constant, size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, name, data); }
inline void bind(Renderer& renderer) noexcept { 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> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/02 17:50:52 by maldavid #+# #+# */ /* 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(); _cmd_pool.init();
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) 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) void CmdManager::beginRecord(int active_image_index)

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/02 17:48:52 by maldavid #+# #+# */ /* 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 <array>
#include <mlx_profile.h>
#include <volk.h> #include <volk.h>
#include <renderer/core/render_core.h> #include <renderer/core/render_core.h>
#include <renderer/command/vk_cmd_pool.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 std::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> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:26:06 by maldavid #+# #+# */ /* Created: 2022/10/06 18:26:06 by maldavid #+# #+# */
/* Updated: 2023/11/08 20:17:49 by maldavid ### ########.fr */ /* Updated: 2024/02/25 08:02:26 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
#include "vk_cmd_buffer.h" #include "vk_cmd_buffer.h"
#include <renderer/core/cmd_resource.h>
#include <renderer/core/render_core.h> #include <renderer/core/render_core.h>
#include <renderer/command/cmd_manager.h> #include <renderer/command/cmd_manager.h>
#include <renderer/core/vk_semaphore.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 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; _pool = pool;
VkCommandBufferAllocateInfo allocInfo{}; VkCommandBufferAllocateInfo allocInfo{};
@@ -32,18 +53,23 @@ namespace mlx
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = 1; allocInfo.commandBufferCount = 1;
if(vkAllocateCommandBuffers(Render_Core::get().getDevice().get(), &allocInfo, &_cmd_buffer) != VK_SUCCESS) VkResult res = vkAllocateCommandBuffers(Render_Core::get().getDevice().get(), &allocInfo, &_cmd_buffer);
core::error::report(e_kind::fatal_error, "Vulkan : failed to allocate command buffer"); if(res != VK_SUCCESS)
core::error::report(e_kind::fatal_error, "Vulkan : failed to allocate command buffer, %s", RCore::verbaliseResultVk(res));
#ifdef DEBUG #ifdef DEBUG
core::error::report(e_kind::message, "Vulkan : created new command buffer"); core::error::report(e_kind::message, "Vulkan : created new command buffer");
#endif #endif
_fence.init(); _fence.init();
_state = state::idle;
} }
void CmdBuffer::beginRecord(VkCommandBufferUsageFlags usage) 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; return;
VkCommandBufferBeginInfo beginInfo{}; VkCommandBufferBeginInfo beginInfo{};
@@ -52,62 +78,291 @@ namespace mlx
if(vkBeginCommandBuffer(_cmd_buffer, &beginInfo) != VK_SUCCESS) if(vkBeginCommandBuffer(_cmd_buffer, &beginInfo) != VK_SUCCESS)
core::error::report(e_kind::fatal_error, "Vulkan : failed to begin recording command buffer"); 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() 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; return;
if(vkEndCommandBuffer(_cmd_buffer) != VK_SUCCESS) if(vkEndCommandBuffer(_cmd_buffer) != VK_SUCCESS)
core::error::report(e_kind::fatal_error, "Vulkan : failed to end recording command buffer"); core::error::report(e_kind::fatal_error, "Vulkan : failed to end recording command buffer");
_is_recording = false; _state = state::idle;
} }
void CmdBuffer::submitIdle() noexcept void CmdBuffer::submitIdle(bool shouldWaitForExecution) noexcept
{ {
auto device = Render_Core::get().getDevice().get(); MLX_PROFILE_FUNCTION();
if(_type != kind::single_time)
{
core::error::report(e_kind::error, "Vulkan : try to perform an idle submit on a command buffer that is not single-time, this is not allowed");
return;
}
VkSubmitInfo submitInfo = {}; _fence.reset();
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &_cmd_buffer;
VkFenceCreateInfo fenceCreateInfo = {};
fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
VkFence fence;
vkCreateFence(device, &fenceCreateInfo, nullptr, &fence);
vkResetFences(device, 1, &fence);
vkQueueSubmit(Render_Core::get().getQueue().getGraphic(), 1, &submitInfo, fence);
vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX);
vkDestroyFence(device, fence, nullptr);
}
void CmdBuffer::submit(Semaphore& semaphores) noexcept
{
VkSemaphore signalSemaphores[] = { semaphores.getRenderImageSemaphore() };
VkSemaphore waitSemaphores[] = { semaphores.getImageSemaphore() };
VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
VkSubmitInfo submitInfo{}; VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.waitSemaphoreCount = 1; submitInfo.commandBufferCount = 1;
submitInfo.pWaitSemaphores = waitSemaphores; 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.pWaitDstStageMask = waitStages;
submitInfo.commandBufferCount = 1; submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &_cmd_buffer; submitInfo.pCommandBuffers = &_cmd_buffer;
submitInfo.signalSemaphoreCount = 1; submitInfo.signalSemaphoreCount = (semaphores == nullptr ? 0 : signalSemaphores.size());
submitInfo.pSignalSemaphores = signalSemaphores; submitInfo.pSignalSemaphores = signalSemaphores.data();
if(vkQueueSubmit(Render_Core::get().getQueue().getGraphic(), 1, &submitInfo, _fence.get()) != VK_SUCCESS) VkResult res = vkQueueSubmit(Render_Core::get().getQueue().getGraphic(), 1, &submitInfo, _fence.get());
core::error::report(e_kind::fatal_error, "Vulkan error : failed to submit draw command buffer"); 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 void CmdBuffer::destroy() noexcept
{ {
MLX_PROFILE_FUNCTION();
_fence.destroy(); _fence.destroy();
_cmd_buffer = VK_NULL_HANDLE; _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> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:25:42 by maldavid #+# #+# */ /* 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__ #ifndef __MLX_VK_CMD_BUFFER__
#define __MLX_VK_CMD_BUFFER__ #define __MLX_VK_CMD_BUFFER__
#include <mlx_profile.h>
#include <volk.h> #include <volk.h>
#include <renderer/core/vk_fence.h> #include <renderer/core/vk_fence.h>
#include <vector>
namespace mlx namespace mlx
{ {
class Buffer;
class Image;
class CmdBuffer class CmdBuffer
{ {
public: public:
void init(class CmdManager* manager); enum class state
void init(class CmdPool* pool); {
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 destroy() noexcept;
void beginRecord(VkCommandBufferUsageFlags usage = 0); void beginRecord(VkCommandBufferUsageFlags usage = 0);
void submit(class Semaphore& semaphores) noexcept; void submit(class Semaphore* semaphores) noexcept;
void submitIdle() noexcept; void submitIdle(bool shouldWaitForExecution = true) noexcept; // TODO : handle `shouldWaitForExecution` as false by default (needs to modify CmdResources lifetimes to do so)
inline void waitForExecution() noexcept { _fence.waitAndReset(); } void updateSubmitState() noexcept;
inline void waitForExecution() noexcept { _fence.wait(); updateSubmitState(); _state = state::ready; }
inline void reset() noexcept { vkResetCommandBuffer(_cmd_buffer, 0); } inline void reset() noexcept { vkResetCommandBuffer(_cmd_buffer, 0); }
void endRecord(); void endRecord();
inline bool isRecording() const noexcept { return _is_recording; } void bindVertexBuffer(Buffer& buffer) noexcept;
inline bool isInit() const noexcept { return _cmd_buffer != VK_NULL_HANDLE; } 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& operator()() noexcept { return _cmd_buffer; }
inline VkCommandBuffer& get() noexcept { return _cmd_buffer; } inline VkCommandBuffer& get() noexcept { return _cmd_buffer; }
inline Fence& getFence() noexcept { return _fence; } inline Fence& getFence() noexcept { return _fence; }
private: private:
void preTransferBarrier() noexcept;
void postTransferBarrier() noexcept;
private:
std::vector<class CmdResource*> _cmd_resources;
Fence _fence; Fence _fence;
VkCommandBuffer _cmd_buffer = VK_NULL_HANDLE; VkCommandBuffer _cmd_buffer = VK_NULL_HANDLE;
class CmdPool* _pool = nullptr; 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> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:24:33 by maldavid #+# #+# */ /* Created: 2022/10/06 18:24:33 by maldavid #+# #+# */
/* Updated: 2022/12/18 22:56:26 by maldavid ### ########.fr */ /* Updated: 2024/01/03 13:13:25 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@@ -22,12 +22,14 @@ namespace mlx
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
poolInfo.queueFamilyIndex = Render_Core::get().getQueue().getFamilies().graphicsFamily.value(); poolInfo.queueFamilyIndex = Render_Core::get().getQueue().getFamilies().graphicsFamily.value();
if(vkCreateCommandPool(Render_Core::get().getDevice().get(), &poolInfo, nullptr, &_cmd_pool) != VK_SUCCESS) VkResult res = vkCreateCommandPool(Render_Core::get().getDevice().get(), &poolInfo, nullptr, &_cmd_pool);
core::error::report(e_kind::fatal_error, "Vulkan : failed to create command 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 void CmdPool::destroy() noexcept
{ {
vkDestroyCommandPool(Render_Core::get().getDevice().get(), _cmd_pool, nullptr); vkDestroyCommandPool(Render_Core::get().getDevice().get(), _cmd_pool, nullptr);
_cmd_pool = VK_NULL_HANDLE;
} }
} }

View File

@@ -6,13 +6,14 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:24:12 by maldavid #+# #+# */ /* 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__ #ifndef __MLX_VK_CMD_POOL__
#define __MLX_VK_CMD_POOL__ #define __MLX_VK_CMD_POOL__
#include <mlx_profile.h>
#include <volk.h> #include <volk.h>
namespace mlx 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

View File

@@ -1,34 +1,32 @@
/* ************************************************************************** */ /* ************************************************************************** */
/* */ /* */
/* ::: :::::::: */ /* ::: :::::::: */
/* vk_imageview.h :+: :+: :+: */ /* drawable_resource.h :+: :+: :+: */
/* +:+ +:+ +:+ */ /* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:20:19 by maldavid #+# #+# */ /* Created: 2024/01/10 21:00:37 by maldavid #+# #+# */
/* Updated: 2022/12/18 19:54:44 by maldavid ### ########.fr */ /* Updated: 2024/01/11 01:21:15 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
#ifndef __MLX_VK_IMAGE_VIEW__ #ifndef __MLX_DRAWABLE_RESOURCE__
#define __MLX_VK_IMAGE_VIEW__ #define __MLX_DRAWABLE_RESOURCE__
#include <mlx_profile.h>
#include <volk.h> #include <volk.h>
#include <array>
namespace mlx namespace mlx
{ {
class ImageView class DrawableResource
{ {
public: public:
void init(class SwapChain& swapchain, VkImage& image); DrawableResource() = default;
void destroy() noexcept; virtual void render(std::array<VkDescriptorSet, 2>& sets, class Renderer& renderer) = 0;
virtual void resetUpdate() {}
inline VkImageView& operator()() noexcept { return _image; } virtual ~DrawableResource() = default;
inline VkImageView& get() noexcept { return _image; }
private:
VkImageView _image = VK_NULL_HANDLE;
}; };
} }
#endif // __MLX_VK_IMAGE_VIEW__ #endif

View File

@@ -6,25 +6,35 @@
/* By: kbz_8 <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: kbz_8 <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2023/10/20 22:02:37 by kbz_8 #+# #+# */ /* 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/errors.h>
#include <core/profiler.h>
#include <cstdio> #include <cstdio>
#define VMA_STATIC_VULKAN_FUNCTIONS 0 #define VMA_STATIC_VULKAN_FUNCTIONS 0
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 0 #define VMA_DYNAMIC_VULKAN_FUNCTIONS 0
#define VMA_VULKAN_VERSION 1002000 #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 #define VMA_IMPLEMENTATION
#ifdef MLX_COMPILER_CLANG #ifdef MLX_COMPILER_CLANG
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnullability-completeness" #pragma clang diagnostic ignored "-Weverything"
#include <renderer/core/memory.h> #include <renderer/core/memory.h>
#pragma clang diagnostic pop #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 #else
#include <renderer/core/memory.h> #include <renderer/core/memory.h>
#endif #endif
@@ -67,71 +77,91 @@ namespace mlx
allocatorCreateInfo.instance = Render_Core::get().getInstance().get(); allocatorCreateInfo.instance = Render_Core::get().getInstance().get();
allocatorCreateInfo.pVulkanFunctions = &vma_vulkan_func; allocatorCreateInfo.pVulkanFunctions = &vma_vulkan_func;
if(vmaCreateAllocator(&allocatorCreateInfo, &_allocator) != VK_SUCCESS) VkResult res = vmaCreateAllocator(&allocatorCreateInfo, &_allocator);
core::error::report(e_kind::fatal_error, "Vulkan : failed to create graphics memory 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 #ifdef DEBUG
core::error::report(e_kind::message, "Vulkan : created new allocator"); core::error::report(e_kind::message, "Graphics allocator : created new allocator");
#endif #endif
} }
VmaAllocation GPUallocator::createBuffer(const VkBufferCreateInfo* binfo, const VmaAllocationCreateInfo* vinfo, VkBuffer& buffer, const char* name) noexcept VmaAllocation GPUallocator::createBuffer(const VkBufferCreateInfo* binfo, const VmaAllocationCreateInfo* vinfo, VkBuffer& buffer, const char* name) noexcept
{ {
MLX_PROFILE_FUNCTION();
VmaAllocation allocation; VmaAllocation allocation;
if(vmaCreateBuffer(_allocator, binfo, vinfo, &buffer, &allocation, nullptr) != VK_SUCCESS) VkResult res = vmaCreateBuffer(_allocator, binfo, vinfo, &buffer, &allocation, nullptr);
core::error::report(e_kind::fatal_error, "Vulkan : failed to allocate a buffer"); 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) if(name != nullptr)
{
Render_Core::get().getLayers().setDebugUtilsObjectNameEXT(VK_OBJECT_TYPE_BUFFER, (std::uint64_t)buffer, name);
vmaSetAllocationName(_allocator, allocation, name); vmaSetAllocationName(_allocator, allocation, name);
}
#ifdef DEBUG #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 #endif
_active_buffers_allocations++;
return allocation; return allocation;
} }
void GPUallocator::destroyBuffer(VmaAllocation allocation, VkBuffer buffer) noexcept void GPUallocator::destroyBuffer(VmaAllocation allocation, VkBuffer buffer) noexcept
{ {
MLX_PROFILE_FUNCTION();
vkDeviceWaitIdle(Render_Core::get().getDevice().get()); vkDeviceWaitIdle(Render_Core::get().getDevice().get());
vmaDestroyBuffer(_allocator, buffer, allocation); vmaDestroyBuffer(_allocator, buffer, allocation);
#ifdef DEBUG #ifdef DEBUG
core::error::report(e_kind::message, "Graphics Allocator : destroyed buffer"); core::error::report(e_kind::message, "Graphics Allocator : destroyed buffer");
#endif #endif
_active_buffers_allocations--;
} }
VmaAllocation GPUallocator::createImage(const VkImageCreateInfo* iminfo, const VmaAllocationCreateInfo* vinfo, VkImage& image, const char* name) noexcept VmaAllocation GPUallocator::createImage(const VkImageCreateInfo* iminfo, const VmaAllocationCreateInfo* vinfo, VkImage& image, const char* name) noexcept
{ {
MLX_PROFILE_FUNCTION();
VmaAllocation allocation; VmaAllocation allocation;
if(vmaCreateImage(_allocator, iminfo, vinfo, &image, &allocation, nullptr) != VK_SUCCESS) VkResult res = vmaCreateImage(_allocator, iminfo, vinfo, &image, &allocation, nullptr);
core::error::report(e_kind::fatal_error, "Vulkan : failed to allocate an image"); 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) if(name != nullptr)
{
Render_Core::get().getLayers().setDebugUtilsObjectNameEXT(VK_OBJECT_TYPE_IMAGE, (std::uint64_t)image, name);
vmaSetAllocationName(_allocator, allocation, name); vmaSetAllocationName(_allocator, allocation, name);
}
#ifdef DEBUG #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 #endif
_active_images_allocations++;
return allocation; return allocation;
} }
void GPUallocator::destroyImage(VmaAllocation allocation, VkImage image) noexcept void GPUallocator::destroyImage(VmaAllocation allocation, VkImage image) noexcept
{ {
MLX_PROFILE_FUNCTION();
vkDeviceWaitIdle(Render_Core::get().getDevice().get()); vkDeviceWaitIdle(Render_Core::get().getDevice().get());
vmaDestroyImage(_allocator, image, allocation); vmaDestroyImage(_allocator, image, allocation);
#ifdef DEBUG #ifdef DEBUG
core::error::report(e_kind::message, "Graphics Allocator : destroyed image"); core::error::report(e_kind::message, "Graphics Allocator : destroyed image");
#endif #endif
_active_images_allocations--;
} }
void GPUallocator::mapMemory(VmaAllocation allocation, void** data) noexcept void GPUallocator::mapMemory(VmaAllocation allocation, void** data) noexcept
{ {
if(vmaMapMemory(_allocator, allocation, data) != VK_SUCCESS) MLX_PROFILE_FUNCTION();
core::error::report(e_kind::fatal_error, "Graphics allocator : unable to map GPU memory to CPU memory"); 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 void GPUallocator::unmapMemory(VmaAllocation allocation) noexcept
{ {
MLX_PROFILE_FUNCTION();
vmaUnmapMemory(_allocator, allocation); vmaUnmapMemory(_allocator, allocation);
} }
void GPUallocator::dumpMemoryToJson() void GPUallocator::dumpMemoryToJson()
{ {
static uint32_t id = 0; static std::uint32_t id = 0;
std::string name("memory_dump"); std::string name("memory_dump");
name.append(std::to_string(id) + ".json"); name.append(std::to_string(id) + ".json");
std::ofstream file(name); std::ofstream file(name);
@@ -150,11 +180,21 @@ namespace mlx
void GPUallocator::flush(VmaAllocation allocation, VkDeviceSize size, VkDeviceSize offset) noexcept void GPUallocator::flush(VmaAllocation allocation, VkDeviceSize size, VkDeviceSize offset) noexcept
{ {
MLX_PROFILE_FUNCTION();
vmaFlushAllocation(_allocator, allocation, offset, size); vmaFlushAllocation(_allocator, allocation, offset, size);
} }
void GPUallocator::destroy() noexcept 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); 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> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2023/10/20 02:13:03 by maldavid #+# #+# */ /* 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__ #ifndef __MLX_VK_MEMORY__
#define __MLX_VK_MEMORY__ #define __MLX_VK_MEMORY__
#include <mlx_profile.h>
#include <volk.h> #include <volk.h>
#include <vma.h> #include <vma.h>
@@ -43,6 +44,8 @@ namespace mlx
private: private:
VmaAllocator _allocator; VmaAllocator _allocator;
std::uint32_t _active_buffers_allocations = 0;
std::uint32_t _active_images_allocations = 0;
}; };
} }

View File

@@ -6,37 +6,34 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/12/17 23:33:34 by maldavid #+# #+# */ /* Created: 2022/12/17 23:33:34 by maldavid #+# #+# */
/* Updated: 2023/11/14 08:15:42 by maldavid ### ########.fr */ /* Updated: 2024/01/20 08:20:07 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
#define VOLK_IMPLEMENTATION #define VOLK_IMPLEMENTATION
#if defined(_WIN32) || defined(_WIN64) #include <mlx_profile.h>
#define VK_USE_PLATFORM_WIN32_KHR #include <renderer/core/render_core.h>
#elif defined(__APPLE__) || defined(__MACH__) #include <renderer/command/vk_cmd_buffer.h>
#define VK_USE_PLATFORM_MACOS_MVK
#else
#define VK_USE_PLATFORM_XLIB_KHR
#endif
#include "render_core.h"
#include <mutex>
#ifdef DEBUG #ifdef DEBUG
#warning MLX is being compiled in debug mode, this activates Vulkan's validation layers and debug messages which may impact rendering performances #ifdef MLX_COMPILER_MSVC
#pragma NOTE("MLX is being compiled in debug mode, this activates Vulkan's validation layers and debug messages which may impact rendering performances")
#else
#warning "MLX is being compiled in debug mode, this activates Vulkan's validation layers and debug messages which may impact rendering performances"
#endif
#endif #endif
namespace mlx namespace mlx
{ {
namespace RCore namespace RCore
{ {
std::optional<uint32_t> findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties, bool error) std::optional<std::uint32_t> findMemoryType(std::uint32_t typeFilter, VkMemoryPropertyFlags properties, bool error)
{ {
VkPhysicalDeviceMemoryProperties memProperties; VkPhysicalDeviceMemoryProperties memProperties;
vkGetPhysicalDeviceMemoryProperties(Render_Core::get().getDevice().getPhysicalDevice(), &memProperties); vkGetPhysicalDeviceMemoryProperties(Render_Core::get().getDevice().getPhysicalDevice(), &memProperties);
for(uint32_t i = 0; i < memProperties.memoryTypeCount; i++) for(std::uint32_t i = 0; i < memProperties.memoryTypeCount; i++)
{ {
if((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) if((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties)
return i; return i;
@@ -45,11 +42,82 @@ namespace mlx
core::error::report(e_kind::fatal_error, "Vulkan : failed to find suitable memory type"); core::error::report(e_kind::fatal_error, "Vulkan : failed to find suitable memory type");
return std::nullopt; 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() 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(); _instance.init();
volkLoadInstance(_instance.get()); volkLoadInstance(_instance.get());
@@ -58,6 +126,7 @@ namespace mlx
volkLoadDevice(_device.get()); volkLoadDevice(_device.get());
_queues.init(); _queues.init();
_allocator.init(); _allocator.init();
_cmd_manager.init();
_is_init = true; _is_init = true;
} }
@@ -68,6 +137,8 @@ namespace mlx
vkDeviceWaitIdle(_device()); vkDeviceWaitIdle(_device());
_pool_manager.destroyAllPools();
_cmd_manager.destroy();
_allocator.destroy(); _allocator.destroy();
_device.destroy(); _device.destroy();
_layers.destroy(); _layers.destroy();

View File

@@ -6,16 +6,20 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/08 19:16:32 by maldavid #+# #+# */ /* Created: 2022/10/08 19:16:32 by maldavid #+# #+# */
/* Updated: 2023/11/14 05:00:44 by maldavid ### ########.fr */ /* Updated: 2024/01/20 08:17:58 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
#ifndef __MLX_RENDER_CORE__ #ifndef __MLX_RENDER_CORE__
#define __MLX_RENDER_CORE__ #define __MLX_RENDER_CORE__
#include <mlx_profile.h>
#include <volk.h> #include <volk.h>
#include <optional> #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_queues.h"
#include "vk_device.h" #include "vk_device.h"
#include "vk_instance.h" #include "vk_instance.h"
@@ -29,43 +33,55 @@ namespace mlx
{ {
namespace RCore namespace RCore
{ {
std::optional<uint32_t> findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties, bool error = true); std::optional<std::uint32_t> findMemoryType(std::uint32_t typeFilter, VkMemoryPropertyFlags properties, bool error = true);
const char* verbaliseResultVk(VkResult result);
VkPipelineStageFlags accessFlagsToPipelineStage(VkAccessFlags accessFlags, VkPipelineStageFlags stageFlags);
} }
#ifdef DEBUG #ifdef DEBUG
constexpr const bool enableValidationLayers = true; constexpr const bool enableValidationLayers = true;
#else #else
constexpr const bool enableValidationLayers = false; constexpr const bool enableValidationLayers = false;
#endif #endif
const std::vector<const char*> validationLayers = { "VK_LAYER_KHRONOS_validation" }; const std::vector<const char*> validationLayers = { "VK_LAYER_KHRONOS_validation" };
constexpr const int MAX_FRAMES_IN_FLIGHT = 3; 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> class Render_Core : public Singleton<Render_Core>
{ {
public: friend class Singleton<Render_Core>;
Render_Core() = default;
void init(); public:
void destroy(); void init();
void destroy();
inline Instance& getInstance() noexcept { return _instance; } inline bool isInit() const noexcept { return _is_init; }
inline Device& getDevice() noexcept { return _device; } inline Instance& getInstance() noexcept { return _instance; }
inline Queues& getQueue() noexcept { return _queues; } inline Device& getDevice() noexcept { return _device; }
inline Queues& getQueue() noexcept { return _queues; }
inline GPUallocator& getAllocator() noexcept { return _allocator; } inline GPUallocator& getAllocator() noexcept { return _allocator; }
inline ValidationLayers& getLayers() noexcept { return _layers; } 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; ~Render_Core() = default;
private: private:
ValidationLayers _layers; ValidationLayers _layers;
Queues _queues; SingleTimeCmdManager _cmd_manager;
Device _device; Queues _queues;
Instance _instance; DescriptorPoolManager _pool_manager;
Device _device;
Instance _instance;
GPUallocator _allocator; GPUallocator _allocator;
bool _is_init = false; bool _is_init = false;
}; };
} }
#endif // __MLX_RENDER_CORE__ #endif // __MLX_RENDER_CORE__

View File

@@ -6,11 +6,13 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/08 19:14:29 by maldavid #+# #+# */ /* Created: 2022/10/08 19:14:29 by maldavid #+# #+# */
/* Updated: 2023/11/11 10:38:01 by maldavid ### ########.fr */ /* Updated: 2024/01/20 05:34:15 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
#include "render_core.h" #include "render_core.h"
#include <iterator>
#include <map>
#include <vector> #include <vector>
#include <set> #include <set>
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
@@ -29,10 +31,10 @@ namespace mlx
Queues::QueueFamilyIndices indices = Render_Core::get().getQueue().getFamilies(); Queues::QueueFamilyIndices indices = Render_Core::get().getQueue().getFamilies();
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos; std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
std::set<uint32_t> uniqueQueueFamilies = { indices.graphicsFamily.value(), indices.presentFamily.value() }; std::set<std::uint32_t> uniqueQueueFamilies = { indices.graphicsFamily.value(), indices.presentFamily.value() };
float queuePriority = 1.0f; float queuePriority = 1.0f;
for(uint32_t queueFamily : uniqueQueueFamilies) for(std::uint32_t queueFamily : uniqueQueueFamilies)
{ {
VkDeviceQueueCreateInfo queueCreateInfo{}; VkDeviceQueueCreateInfo queueCreateInfo{};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
@@ -47,17 +49,18 @@ namespace mlx
VkDeviceCreateInfo createInfo{}; VkDeviceCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size()); createInfo.queueCreateInfoCount = static_cast<std::uint32_t>(queueCreateInfos.size());
createInfo.pQueueCreateInfos = queueCreateInfos.data(); createInfo.pQueueCreateInfos = queueCreateInfos.data();
createInfo.pEnabledFeatures = &deviceFeatures; createInfo.pEnabledFeatures = &deviceFeatures;
createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size()); createInfo.enabledExtensionCount = static_cast<std::uint32_t>(deviceExtensions.size());
createInfo.ppEnabledExtensionNames = deviceExtensions.data(); createInfo.ppEnabledExtensionNames = deviceExtensions.data();
createInfo.enabledLayerCount = 0; createInfo.enabledLayerCount = 0;
if(vkCreateDevice(_physicalDevice, &createInfo, nullptr, &_device) != VK_SUCCESS) VkResult res;
core::error::report(e_kind::fatal_error, "Vulkan : failed to create logcal device"); 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 #ifdef DEBUG
core::error::report(e_kind::message, "Vulkan : created new logical device"); core::error::report(e_kind::message, "Vulkan : created new logical device");
#endif #endif
@@ -65,7 +68,7 @@ namespace mlx
void Device::pickPhysicalDevice() void Device::pickPhysicalDevice()
{ {
uint32_t deviceCount = 0; std::uint32_t deviceCount = 0;
vkEnumeratePhysicalDevices(Render_Core::get().getInstance().get(), &deviceCount, nullptr); vkEnumeratePhysicalDevices(Render_Core::get().getInstance().get(), &deviceCount, nullptr);
if(deviceCount == 0) if(deviceCount == 0)
@@ -82,30 +85,27 @@ namespace mlx
if(SDL_Vulkan_CreateSurface(window, Render_Core::get().getInstance().get(), &surface) != SDL_TRUE) 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"); 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) 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) if(devices_score.rbegin()->first > 0)
_physicalDevice = devices_score.front().second; _physicalDevice = devices_score.rbegin()->second;
else
if(_physicalDevice == VK_NULL_HANDLE)
core::error::report(e_kind::fatal_error, "Vulkan : failed to find a suitable GPU"); core::error::report(e_kind::fatal_error, "Vulkan : failed to find a suitable GPU");
#ifdef DEBUG #ifdef DEBUG
VkPhysicalDeviceProperties props; VkPhysicalDeviceProperties props;
vkGetPhysicalDeviceProperties(_physicalDevice, &props); vkGetPhysicalDeviceProperties(_physicalDevice, &props);
core::error::report(e_kind::message, "Vulkan : picked a physical device, %s", props.deviceName); core::error::report(e_kind::message, "Vulkan : picked a physical device, %s", props.deviceName);
#endif #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) int Device::deviceScore(VkPhysicalDevice device, VkSurfaceKHR surface)
@@ -113,7 +113,7 @@ namespace mlx
Queues::QueueFamilyIndices indices = Render_Core::get().getQueue().findQueueFamilies(device, surface); Queues::QueueFamilyIndices indices = Render_Core::get().getQueue().findQueueFamilies(device, surface);
bool extensionsSupported = checkDeviceExtensionSupport(device); bool extensionsSupported = checkDeviceExtensionSupport(device);
uint32_t formatCount = 0; std::uint32_t formatCount = 0;
if(extensionsSupported) if(extensionsSupported)
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr); vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
@@ -122,6 +122,9 @@ namespace mlx
if(!indices.isComplete() || !extensionsSupported || formatCount == 0) if(!indices.isComplete() || !extensionsSupported || formatCount == 0)
return -1; return -1;
VkPhysicalDeviceFeatures features;
vkGetPhysicalDeviceFeatures(device, &features);
int score = 0; int score = 0;
#ifndef FORCE_INTEGRATED_GPU #ifndef FORCE_INTEGRATED_GPU
if(props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_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) if(props.deviceType != VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU)
return -1; return -1;
#endif #endif
if(!features.geometryShader)
return -1;
score += props.limits.maxImageDimension2D; score += props.limits.maxImageDimension2D;
score += props.limits.maxBoundDescriptorSets; score += props.limits.maxBoundDescriptorSets;
return score; return score;
@@ -137,7 +144,7 @@ namespace mlx
bool Device::checkDeviceExtensionSupport(VkPhysicalDevice device) bool Device::checkDeviceExtensionSupport(VkPhysicalDevice device)
{ {
uint32_t extensionCount; std::uint32_t extensionCount;
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr); vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
std::vector<VkExtensionProperties> availableExtensions(extensionCount); std::vector<VkExtensionProperties> availableExtensions(extensionCount);
@@ -154,5 +161,9 @@ namespace mlx
void Device::destroy() noexcept void Device::destroy() noexcept
{ {
vkDestroyDevice(_device, nullptr); 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> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/08 19:13:42 by maldavid #+# #+# */ /* 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__ #ifndef __MLX_VK_DEVICE__
#define __MLX_VK_DEVICE__ #define __MLX_VK_DEVICE__
#include <mlx_profile.h>
#include <volk.h> #include <volk.h>
#include "vk_queues.h" #include "vk_queues.h"

View File

@@ -6,25 +6,24 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/02 17:53:06 by maldavid #+# #+# */ /* Created: 2023/04/02 17:53:06 by maldavid #+# #+# */
/* Updated: 2023/11/08 20:14:23 by maldavid ### ########.fr */ /* Updated: 2024/02/25 08:02:45 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
#include <renderer/core/vk_fence.h> #include <renderer/core/vk_fence.h>
#include <renderer/core/render_core.h>
namespace mlx namespace mlx
{ {
void Fence::init() void Fence::init()
{ {
VkSemaphoreCreateInfo semaphoreInfo{};
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
VkFenceCreateInfo fenceInfo{}; VkFenceCreateInfo fenceInfo{};
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
if(vkCreateFence(Render_Core::get().getDevice().get(), &fenceInfo, nullptr, &_fence) != VK_SUCCESS) VkResult res;
core::error::report(e_kind::fatal_error, "Vulkan : failed to create CPU synchronization object"); 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 #ifdef DEBUG
core::error::report(e_kind::message, "Vulkan : created new fence"); core::error::report(e_kind::message, "Vulkan : created new fence");
#endif #endif
@@ -40,8 +39,18 @@ namespace mlx
vkResetFences(Render_Core::get().getDevice().get(), 1, &_fence); 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 void Fence::destroy() noexcept
{ {
vkDestroyFence(Render_Core::get().getDevice().get(), _fence, nullptr); 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> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/02 17:52:09 by maldavid #+# #+# */ /* 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__ #ifndef __MLX_VK_FENCE__
#define __MLX_VK_FENCE__ #define __MLX_VK_FENCE__
#include <mlx_profile.h>
#include <volk.h> #include <volk.h>
#include <renderer/core/render_core.h>
namespace mlx namespace mlx
{ {
@@ -28,6 +28,7 @@ namespace mlx
inline VkFence& get() noexcept { return _fence; } inline VkFence& get() noexcept { return _fence; }
void wait() noexcept; void wait() noexcept;
void reset() noexcept; void reset() noexcept;
bool isReady() const noexcept;
inline void waitAndReset() noexcept { wait(); reset(); } inline void waitAndReset() noexcept { wait(); reset(); }
void destroy() noexcept; void destroy() noexcept;

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/08 19:04:21 by maldavid #+# #+# */ /* Created: 2022/10/08 19:04:21 by maldavid #+# #+# */
/* Updated: 2023/11/08 20:13:30 by maldavid ### ########.fr */ /* Updated: 2024/02/24 21:10:32 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@@ -21,40 +21,35 @@ namespace mlx
{ {
VkApplicationInfo appInfo{}; VkApplicationInfo appInfo{};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = "MacroLibX";
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "MacroLibX"; appInfo.pEngineName = "MacroLibX";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); appInfo.engineVersion = VK_MAKE_VERSION(1, 3, 1);
appInfo.apiVersion = VK_API_VERSION_1_2; appInfo.apiVersion = VK_API_VERSION_1_2;
auto extensions = getRequiredExtensions();
VkInstanceCreateInfo createInfo{}; VkInstanceCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.pApplicationInfo = &appInfo; createInfo.pApplicationInfo = &appInfo;
createInfo.enabledExtensionCount = static_cast<std::uint32_t>(extensions.size());
auto extensions = getRequiredExtensions();
createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
createInfo.ppEnabledExtensionNames = extensions.data(); createInfo.ppEnabledExtensionNames = extensions.data();
createInfo.enabledLayerCount = 0; // will be replaced if validation layers are enabled
createInfo.pNext = nullptr;
VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo; VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo;
if constexpr(enableValidationLayers) if constexpr(enableValidationLayers)
{ {
if(Render_Core::get().getLayers().checkValidationLayerSupport()) if(Render_Core::get().getLayers().checkValidationLayerSupport())
{ {
createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size()); createInfo.enabledLayerCount = static_cast<std::uint32_t>(validationLayers.size());
createInfo.ppEnabledLayerNames = validationLayers.data(); createInfo.ppEnabledLayerNames = validationLayers.data();
Render_Core::get().getLayers().populateDebugMessengerCreateInfo(debugCreateInfo); 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; VkResult res;
if((res = vkCreateInstance(&createInfo, nullptr, &_instance)) != VK_SUCCESS) 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); volkLoadInstance(_instance);
#ifdef DEBUG #ifdef DEBUG
core::error::report(e_kind::message, "Vulkan : created new instance"); core::error::report(e_kind::message, "Vulkan : created new instance");
@@ -63,30 +58,43 @@ namespace mlx
std::vector<const char*> Instance::getRequiredExtensions() std::vector<const char*> Instance::getRequiredExtensions()
{ {
unsigned int count = 0; std::vector<const char*> extensions;
SDL_Window* window = SDL_CreateWindow("", 0, 0, 1, 1, SDL_WINDOW_VULKAN | SDL_WINDOW_HIDDEN); extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
if(!window)
core::error::report(e_kind::fatal_error, "Vulkan : cannot get instance extentions from window : %s", SDL_GetError());
if(!SDL_Vulkan_GetInstanceExtensions(window, &count, nullptr)) #ifdef VK_USE_PLATFORM_XCB_KHR
core::error::report(e_kind::fatal_error, "Vulkan : cannot get instance extentions from window : %s", SDL_GetError()); extensions.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
#endif
std::vector<const char*> extensions = { VK_EXT_DEBUG_REPORT_EXTENSION_NAME }; #ifdef VK_USE_PLATFORM_XLIB_KHR
size_t additional_extension_count = extensions.size(); extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
extensions.resize(additional_extension_count + count); #endif
if(!SDL_Vulkan_GetInstanceExtensions(window, &count, extensions.data() + additional_extension_count)) #ifdef VK_USE_PLATFORM_WAYLAND_KHR
core::error::report(e_kind::error, "Vulkan : cannot get instance extentions from window : %s", SDL_GetError()); extensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
#endif
#ifdef VK_USE_PLATFORM_WIN32_KHR
extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#endif
#ifdef VK_USE_PLATFORM_METAL_EXT
extensions.push_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
#endif
if constexpr(enableValidationLayers) if constexpr(enableValidationLayers)
{
extensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
}
SDL_DestroyWindow(window);
return extensions; return extensions;
} }
void Instance::destroy() noexcept void Instance::destroy() noexcept
{ {
vkDestroyInstance(_instance, nullptr); 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> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/08 19:03:04 by maldavid #+# #+# */ /* 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__ #ifndef __MLX_VK_INSTANCE__
#define __MLX_VK_INSTANCE__ #define __MLX_VK_INSTANCE__
#include <mlx_profile.h>
#include <volk.h> #include <volk.h>
#include <vector> #include <vector>

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/08 19:02:42 by maldavid #+# #+# */ /* 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 */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@@ -18,7 +18,7 @@ namespace mlx
{ {
Queues::QueueFamilyIndices Queues::findQueueFamilies(VkPhysicalDevice device, VkSurfaceKHR surface) Queues::QueueFamilyIndices Queues::findQueueFamilies(VkPhysicalDevice device, VkSurfaceKHR surface)
{ {
uint32_t queueFamilyCount = 0; std::uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr); vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount); std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
@@ -38,7 +38,7 @@ namespace mlx
_families->presentFamily = i; _families->presentFamily = i;
if(_families->isComplete()) if(_families->isComplete())
break; return *_families;
i++; 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->graphicsFamily.value(), 0, &_graphicsQueue);
vkGetDeviceQueue(Render_Core::get().getDevice().get(), _families->presentFamily.value(), 0, &_presentQueue); 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> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/08 19:01:49 by maldavid #+# #+# */ /* 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__ #ifndef __MLX_VK_QUEUES__
#define __MLX_VK_QUEUES__ #define __MLX_VK_QUEUES__
#include <mlx_profile.h>
#include <volk.h> #include <volk.h>
#include <optional> #include <optional>
#include <cstdint> #include <cstdint>
#include <core/errors.h>
namespace mlx namespace mlx
{ {
@@ -24,8 +26,8 @@ namespace mlx
public: public:
struct QueueFamilyIndices struct QueueFamilyIndices
{ {
std::optional<uint32_t> graphicsFamily; std::optional<std::uint32_t> graphicsFamily;
std::optional<uint32_t> presentFamily; std::optional<std::uint32_t> presentFamily;
inline bool isComplete() { return graphicsFamily.has_value() && presentFamily.has_value(); } inline bool isComplete() { return graphicsFamily.has_value() && presentFamily.has_value(); }
}; };
@@ -36,7 +38,13 @@ namespace mlx
inline VkQueue& getGraphic() noexcept { return _graphicsQueue; } inline VkQueue& getGraphic() noexcept { return _graphicsQueue; }
inline VkQueue& getPresent() noexcept { return _presentQueue; } 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: private:
VkQueue _graphicsQueue; VkQueue _graphicsQueue;

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/08 19:01:08 by maldavid #+# #+# */ /* Created: 2022/10/08 19:01:08 by maldavid #+# #+# */
/* Updated: 2023/11/08 20:14:36 by maldavid ### ########.fr */ /* Updated: 2024/01/10 21:55:12 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@@ -21,17 +21,23 @@ namespace mlx
VkSemaphoreCreateInfo semaphoreInfo{}; VkSemaphoreCreateInfo semaphoreInfo{};
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
if( vkCreateSemaphore(Render_Core::get().getDevice().get(), &semaphoreInfo, nullptr, &_imageAvailableSemaphores) != VK_SUCCESS || VkResult res;
vkCreateSemaphore(Render_Core::get().getDevice().get(), &semaphoreInfo, nullptr, &_renderFinishedSemaphores) != VK_SUCCESS) if( (res = vkCreateSemaphore(Render_Core::get().getDevice().get(), &semaphoreInfo, nullptr, &_imageAvailableSemaphores)) != VK_SUCCESS ||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create GPU synchronization object"); (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 #ifdef DEBUG
core::error::report(e_kind::message, "Vulkan : created new semaphore"); core::error::report(e_kind::message, "Vulkan : created new semaphores");
#endif #endif
} }
void Semaphore::destroy() noexcept void Semaphore::destroy() noexcept
{ {
vkDestroySemaphore(Render_Core::get().getDevice().get(), _renderFinishedSemaphores, nullptr); vkDestroySemaphore(Render_Core::get().getDevice().get(), _renderFinishedSemaphores, nullptr);
_renderFinishedSemaphores = VK_NULL_HANDLE;
vkDestroySemaphore(Render_Core::get().getDevice().get(), _imageAvailableSemaphores, nullptr); 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> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/08 18:59:38 by maldavid #+# #+# */ /* 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__ #ifndef __MLX_VK_SEMAPHORE__
#define __MLX_VK_SEMAPHORE__ #define __MLX_VK_SEMAPHORE__
#include <mlx_profile.h>
#include <volk.h> #include <volk.h>
#include <vector> #include <vector>

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/08 18:58:49 by maldavid #+# #+# */ /* Created: 2022/10/08 18:58:49 by maldavid #+# #+# */
/* Updated: 2023/11/08 20:14:48 by maldavid ### ########.fr */ /* Updated: 2024/01/10 21:55:21 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@@ -15,6 +15,7 @@
#include <renderer/renderer.h> #include <renderer/renderer.h>
#include <SDL2/SDL_vulkan.h> #include <SDL2/SDL_vulkan.h>
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <algorithm>
namespace mlx namespace mlx
{ {
@@ -29,17 +30,20 @@ namespace mlx
VkSurfaceFormatKHR Surface::chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats) 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 format.format == VK_FORMAT_R8G8B8A8_SRGB && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
return availableFormat; });
}
return availableFormats[0]; return (it == availableFormats.end() ? availableFormats[0] : *it);
} }
void Surface::destroy() noexcept void Surface::destroy() noexcept
{ {
vkDestroySurfaceKHR(Render_Core::get().getInstance().get(), _surface, nullptr); 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> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/08 18:57:55 by maldavid #+# #+# */ /* 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__ #ifndef __MLX_VK_SURFACE__
#define __MLX_VK_SURFACE__ #define __MLX_VK_SURFACE__
#include <mlx_profile.h>
#include <volk.h> #include <volk.h>
#include <vector> #include <vector>

View File

@@ -3,19 +3,20 @@
/* ::: :::::::: */ /* ::: :::::::: */
/* vk_validation_layers.cpp :+: :+: :+: */ /* 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 #+# #+# */ /* Created: 2022/12/19 14:05:25 by maldavid #+# #+# */
/* Updated: 2023/11/08 20:15:36 by maldavid ### ########.fr */ /* Updated: 2024/01/10 21:55:54 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
#include "vk_validation_layers.h"
#include "render_core.h" #include "render_core.h"
#include "vulkan/vulkan_core.h"
#include <core/errors.h> #include <core/errors.h>
#include <iostream> #include <iostream>
#include <cstring> #include <cstring>
#include <algorithm>
namespace mlx namespace mlx
{ {
@@ -24,78 +25,99 @@ namespace mlx
if constexpr(!enableValidationLayers) if constexpr(!enableValidationLayers)
return; return;
VkDebugUtilsMessengerCreateInfoEXT createInfo; std::uint32_t extensionCount;
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
std::vector<VkExtensionProperties> extensions(extensionCount);
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
if(!std::any_of(extensions.begin(), extensions.end(), [=](VkExtensionProperties ext) { return std::strcmp(ext.extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0; }))
{
core::error::report(e_kind::warning , "Vulkan : %s not present, debug utils are disabled", VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
return;
}
VkDebugUtilsMessengerCreateInfoEXT createInfo{};
populateDebugMessengerCreateInfo(createInfo); populateDebugMessengerCreateInfo(createInfo);
if(createDebugUtilsMessengerEXT(&createInfo, nullptr) != VK_SUCCESS) VkResult res = createDebugUtilsMessengerEXT(&createInfo, nullptr);
core::error::report(e_kind::error, "Vulkan : failed to set up debug messenger"); if(res != VK_SUCCESS)
core::error::report(e_kind::warning, "Vulkan : failed to set up debug messenger, %s", RCore::verbaliseResultVk(res));
#ifdef DEBUG #ifdef DEBUG
else else
core::error::report(e_kind::message, "Vulkan : enabled validation layers"); core::error::report(e_kind::message, "Vulkan : enabled validation layers");
#endif #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() bool ValidationLayers::checkValidationLayerSupport()
{
uint32_t layerCount;
vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
std::vector<VkLayerProperties> availableLayers(layerCount);
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
for(const char* layerName : validationLayers)
{
bool layerFound = false;
for(const auto& layerProperties : availableLayers)
{
if(std::strcmp(layerName, layerProperties.layerName) == 0)
{
layerFound = true;
break;
}
}
if(!layerFound)
return false;
}
return true;
}
void ValidationLayers::destroy()
{ {
if constexpr(!enableValidationLayers) std::uint32_t layerCount;
return; vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
destroyDebugUtilsMessengerEXT(nullptr);
std::vector<VkLayerProperties> availableLayers(layerCount);
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
return std::all_of(validationLayers.begin(), validationLayers.end(), [&](const char* layerName)
{
if(!std::any_of(availableLayers.begin(), availableLayers.end(), [=](VkLayerProperties props) { return std::strcmp(layerName, props.layerName) == 0; }))
{
core::error::report(e_kind::error, "Vulkan : a validation layer was requested but was not found ('%s')", layerName);
return false;
}
return true;
});
} }
VkResult ValidationLayers::createDebugUtilsMessengerEXT(const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator) VkResult ValidationLayers::setDebugUtilsObjectNameEXT(VkObjectType object_type, std::uint64_t object_handle, const char* object_name)
{ {
auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(Render_Core::get().getInstance().get(), "vkCreateDebugUtilsMessengerEXT"); if(!real_vkSetDebugUtilsObjectNameEXT)
return func != nullptr ? func(Render_Core::get().getInstance().get(), pCreateInfo, pAllocator, &_debugMessenger) : VK_ERROR_EXTENSION_NOT_PRESENT; return 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) void ValidationLayers::populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo)
{ {
createInfo = {}; createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
createInfo.pfnUserCallback = ValidationLayers::debugCallback; createInfo.pfnUserCallback = ValidationLayers::debugCallback;
} }
VKAPI_ATTR VkBool32 VKAPI_CALL ValidationLayers::debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) void ValidationLayers::destroy()
{
if constexpr(enableValidationLayers)
{
destroyDebugUtilsMessengerEXT(nullptr);
#ifdef DEBUG
core::error::report(e_kind::message, "Vulkan : destroyed validation layers");
#endif
}
}
VkResult ValidationLayers::createDebugUtilsMessengerEXT(const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator)
{
auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(Render_Core::get().getInstance().get(), "vkCreateDebugUtilsMessengerEXT");
return func != nullptr ? func(Render_Core::get().getInstance().get(), pCreateInfo, pAllocator, &_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) if(messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
{ core::error::report(e_kind::error, pCallbackData->pMessage);
std::cout << '\n';
core::error::report(e_kind::error, std::string("Vulkan layer error: ") + pCallbackData->pMessage);
}
else if(messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) else if(messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)
{ core::error::report(e_kind::warning, pCallbackData->pMessage);
std::cout << '\n';
core::error::report(e_kind::warning, std::string("Vulkan layer warning: ") + pCallbackData->pMessage);
}
return VK_FALSE; return VK_FALSE;
} }

View File

@@ -6,13 +6,14 @@
/* By: maldavid <marvin@42.fr> +#+ +:+ +#+ */ /* By: maldavid <marvin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2022/12/19 14:04:25 by maldavid #+# #+# */ /* 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__ #ifndef __VK_VALIDATION_LAYERS__
#define __VK_VALIDATION_LAYERS__ #define __VK_VALIDATION_LAYERS__
#include <mlx_profile.h>
#include <volk.h> #include <volk.h>
namespace mlx namespace mlx
@@ -20,17 +21,26 @@ namespace mlx
class ValidationLayers class ValidationLayers
{ {
public: public:
ValidationLayers() = default;
void init(); void init();
void destroy(); void destroy();
bool checkValidationLayerSupport(); bool checkValidationLayerSupport();
void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo); void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo);
VkResult setDebugUtilsObjectNameEXT(VkObjectType object_type, std::uint64_t object_handle, const char* object_name);
~ValidationLayers() = default;
private: private:
VkResult createDebugUtilsMessengerEXT(const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator); VkResult createDebugUtilsMessengerEXT(const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator);
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData); static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData);
void destroyDebugUtilsMessengerEXT(const VkAllocationCallbacks* pAllocator); void destroyDebugUtilsMessengerEXT(const VkAllocationCallbacks* pAllocator);
private:
VkDebugUtilsMessengerEXT _debugMessenger; 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> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2023/01/23 18:34:23 by maldavid #+# #+# */ /* Created: 2023/01/23 18:34:23 by maldavid #+# #+# */
/* Updated: 2023/01/23 18:44:51 by maldavid ### ########.fr */ /* Updated: 2024/01/20 07:40:40 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
#include "vk_descriptor_pool.h" #include "vk_descriptor_pool.h"
#include <renderer/descriptors/vk_descriptor_set.h>
#include <renderer/core/render_core.h> #include <renderer/core/render_core.h>
namespace mlx namespace mlx
@@ -21,14 +22,34 @@ namespace mlx
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
poolInfo.poolSizeCount = n; poolInfo.poolSizeCount = n;
poolInfo.pPoolSizes = size; 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) VkResult res = vkCreateDescriptorPool(Render_Core::get().getDevice().get(), &poolInfo, nullptr, &_pool);
core::error::report(e_kind::fatal_error, "Vulkan : failed to create descriptor 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 void DescriptorPool::destroy() noexcept
{ {
vkDestroyDescriptorPool(Render_Core::get().getDevice().get(), _pool, nullptr); 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> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2023/01/23 18:32:43 by maldavid #+# #+# */ /* 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__ #ifndef __VK_DESCRIPTOR_POOL__
#define __VK_DESCRIPTOR_POOL__ #define __VK_DESCRIPTOR_POOL__
#include <mlx_profile.h>
#include <volk.h> #include <volk.h>
#include <cstddef> #include <cstddef>
@@ -21,14 +22,23 @@ namespace mlx
class DescriptorPool class DescriptorPool
{ {
public: public:
DescriptorPool() = default;
void init(std::size_t n, VkDescriptorPoolSize* size); void init(std::size_t n, VkDescriptorPoolSize* size);
void freeDescriptor(const class DescriptorSet& set);
void destroy() noexcept; void destroy() noexcept;
inline VkDescriptorPool& operator()() noexcept { return _pool; } inline VkDescriptorPool& operator()() noexcept { return _pool; }
inline VkDescriptorPool& get() 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: private:
VkDescriptorPool _pool = VK_NULL_HANDLE; 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> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2023/01/23 18:40:44 by maldavid #+# #+# */ /* 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 "vk_descriptor_set.h"
#include "renderer/core/render_core.h"
#include "vk_descriptor_pool.h" #include "vk_descriptor_pool.h"
#include "vk_descriptor_set_layout.h" #include "vk_descriptor_set_layout.h"
#include <renderer/buffers/vk_ubo.h> #include <renderer/buffers/vk_ubo.h>
#include <renderer/renderer.h> #include <renderer/renderer.h>
#include <renderer/images/vk_image.h>
#include <core/profiler.h>
namespace mlx namespace mlx
{ {
void DescriptorSet::init(Renderer* renderer, DescriptorPool* pool, DescriptorSetLayout* layout) void DescriptorSet::init(Renderer* renderer, DescriptorPool* pool, DescriptorSetLayout* layout)
{ {
MLX_PROFILE_FUNCTION();
_renderer = renderer; _renderer = renderer;
_layout = layout; _layout = layout;
_pool = pool; _pool = pool;
@@ -32,18 +36,20 @@ namespace mlx
VkDescriptorSetAllocateInfo allocInfo{}; VkDescriptorSetAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocInfo.descriptorPool = _pool->get(); allocInfo.descriptorPool = _pool->get();
allocInfo.descriptorSetCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT); allocInfo.descriptorSetCount = static_cast<std::uint32_t>(MAX_FRAMES_IN_FLIGHT);
allocInfo.pSetLayouts = layouts.data(); allocInfo.pSetLayouts = layouts.data();
if(vkAllocateDescriptorSets(device, &allocInfo, _desc_set.data()) != VK_SUCCESS) VkResult res = vkAllocateDescriptorSets(device, &allocInfo, _desc_set.data());
core::error::report(e_kind::fatal_error, "Vulkan : failed to allocate descriptor set"); if(res != VK_SUCCESS)
core::error::report(e_kind::fatal_error, "Vulkan : failed to allocate descriptor set, %s", RCore::verbaliseResultVk(res));
#ifdef DEBUG #ifdef DEBUG
core::error::report(e_kind::message, "Vulkan : created new descriptor set"); core::error::report(e_kind::message, "Vulkan : created new descriptor set");
#endif #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(); auto device = Render_Core::get().getDevice().get();
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) 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(); auto device = Render_Core::get().getDevice().get();
VkDescriptorImageInfo imageInfo{}; VkDescriptorImageInfo imageInfo{};
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; imageInfo.imageLayout = image.getLayout();
imageInfo.imageView = view; imageInfo.imageView = image.getImageView();
imageInfo.sampler = sampler; imageInfo.sampler = image.getSampler();
VkWriteDescriptorSet descriptorWrite{}; VkWriteDescriptorSet descriptorWrite{};
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
@@ -89,8 +96,9 @@ namespace mlx
DescriptorSet DescriptorSet::duplicate() DescriptorSet DescriptorSet::duplicate()
{ {
MLX_PROFILE_FUNCTION();
DescriptorSet set; DescriptorSet set;
set.init(_renderer, _pool, _layout); set.init(_renderer, &Render_Core::get().getDescriptorPool(), _layout);
return set; return set;
} }
@@ -98,8 +106,24 @@ namespace mlx
{ {
return _desc_set[_renderer->getActiveImageIndex()]; return _desc_set[_renderer->getActiveImageIndex()];
} }
VkDescriptorSet& DescriptorSet::get() noexcept VkDescriptorSet& DescriptorSet::get() noexcept
{ {
return _desc_set[_renderer->getActiveImageIndex()]; 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> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2023/01/23 18:39:36 by maldavid #+# #+# */ /* 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__ #ifndef __VK_DESCRIPTOR_SET__
#define __VK_DESCRIPTOR_SET__ #define __VK_DESCRIPTOR_SET__
#include <mlx_profile.h>
#include <volk.h> #include <volk.h>
#include <array> #include <array>
#include <renderer/core/render_core.h> #include <renderer/core/render_core.h>
@@ -22,18 +23,26 @@ namespace mlx
class DescriptorSet class DescriptorSet
{ {
public: public:
DescriptorSet() = default;
void init(class Renderer* renderer, class DescriptorPool* pool, class DescriptorSetLayout* layout); void init(class Renderer* renderer, class DescriptorPool* pool, class DescriptorSetLayout* layout);
void writeDescriptor(int binding, class UBO* ubo) noexcept; void writeDescriptor(int binding, class UBO* ubo) const noexcept;
void writeDescriptor(int binding, VkImageView view, VkSampler sampler) 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(); DescriptorSet duplicate();
VkDescriptorSet& operator()() noexcept; VkDescriptorSet& operator()() noexcept;
VkDescriptorSet& get() noexcept; VkDescriptorSet& get() noexcept;
inline const std::array<VkDescriptorSet, MAX_FRAMES_IN_FLIGHT>& getAllFramesDescriptorSets() const { return _desc_set; }
void destroy() noexcept;
~DescriptorSet() = default;
private: private:
std::array<VkDescriptorSet, MAX_FRAMES_IN_FLIGHT> _desc_set; std::array<VkDescriptorSet, MAX_FRAMES_IN_FLIGHT> _desc_set;
class DescriptorPool* _pool = nullptr; class DescriptorPool* _pool = nullptr;

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2023/01/23 18:37:28 by maldavid #+# #+# */ /* Created: 2023/01/23 18:37:28 by maldavid #+# #+# */
/* Updated: 2023/03/31 16:37:09 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) void DescriptorSetLayout::init(std::vector<std::pair<int, VkDescriptorType>> binds, VkShaderStageFlagBits stage)
{ {
std::vector<VkDescriptorSetLayoutBinding> bindings(binds.size()); 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].binding = binds[i].first;
bindings[i].descriptorCount = 1; bindings[i].descriptorCount = 1;
@@ -34,12 +34,14 @@ namespace mlx
layoutInfo.bindingCount = _bindings.size(); layoutInfo.bindingCount = _bindings.size();
layoutInfo.pBindings = bindings.data(); layoutInfo.pBindings = bindings.data();
if(vkCreateDescriptorSetLayout(Render_Core::get().getDevice().get(), &layoutInfo, nullptr, &_layout) != VK_SUCCESS) VkResult res = vkCreateDescriptorSetLayout(Render_Core::get().getDevice().get(), &layoutInfo, nullptr, &_layout);
core::error::report(e_kind::fatal_error, "Vulkan : failed to create descriptor set 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 void DescriptorSetLayout::destroy() noexcept
{ {
vkDestroyDescriptorSetLayout(Render_Core::get().getDevice().get(), _layout, nullptr); vkDestroyDescriptorSetLayout(Render_Core::get().getDevice().get(), _layout, nullptr);
_layout = VK_NULL_HANDLE;
} }
} }

View File

@@ -6,23 +6,24 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2023/01/23 18:36:22 by maldavid #+# #+# */ /* 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__ #ifndef __VK_DESCRIPTOR_SET_LAYOUT__
#define __VK_DESCRIPTOR_SET_LAYOUT__ #define __VK_DESCRIPTOR_SET_LAYOUT__
#include <mlx_profile.h>
#include <volk.h> #include <volk.h>
#include <cstddef>
#include <vector> #include <vector>
#include <map>
namespace mlx namespace mlx
{ {
class DescriptorSetLayout class DescriptorSetLayout
{ {
public: public:
DescriptorSetLayout() = default;
void init(std::vector<std::pair<int, VkDescriptorType>> binds, VkShaderStageFlagBits stage); void init(std::vector<std::pair<int, VkDescriptorType>> binds, VkShaderStageFlagBits stage);
void destroy() noexcept; void destroy() noexcept;
@@ -30,6 +31,8 @@ namespace mlx
inline VkDescriptorSetLayout& get() noexcept { return _layout; } inline VkDescriptorSetLayout& get() noexcept { return _layout; }
inline const std::vector<std::pair<int, VkDescriptorType>>& getBindings() const noexcept { return _bindings; } inline const std::vector<std::pair<int, VkDescriptorType>>& getBindings() const noexcept { return _bindings; }
~DescriptorSetLayout() = default;
private: private:
VkDescriptorSetLayout _layout = VK_NULL_HANDLE; VkDescriptorSetLayout _layout = VK_NULL_HANDLE;
std::vector<std::pair<int, VkDescriptorType>> _bindings; std::vector<std::pair<int, VkDescriptorType>> _bindings;

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2023/03/31 18:03:35 by maldavid #+# #+# */ /* Created: 2023/03/31 18:03:35 by maldavid #+# #+# */
/* Updated: 2023/11/14 04:57:55 by maldavid ### ########.fr */ /* Updated: 2024/02/24 03:51:59 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@@ -14,6 +14,7 @@
#include <renderer/images/texture.h> #include <renderer/images/texture.h>
#include <renderer/buffers/vk_buffer.h> #include <renderer/buffers/vk_buffer.h>
#include <renderer/renderer.h> #include <renderer/renderer.h>
#include <core/profiler.h>
#include <cstring> #include <cstring>
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
@@ -29,11 +30,13 @@
namespace mlx namespace mlx
{ {
void Texture::create(uint8_t* pixels, uint32_t width, uint32_t height, VkFormat format, const char* name, bool dedicated_memory) void Texture::create(std::uint8_t* pixels, std::uint32_t width, std::uint32_t height, VkFormat format, const char* name, bool dedicated_memory)
{ {
Image::create(width, height, format, TILING, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, name, dedicated_memory); MLX_PROFILE_FUNCTION();
Image::create(width, height, format, TILING, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, name, dedicated_memory);
Image::createImageView(VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT); Image::createImageView(VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT);
Image::createSampler(); Image::createSampler();
transitionLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
std::vector<Vertex> vertexData = { std::vector<Vertex> vertexData = {
{{0, 0}, {1.f, 1.f, 1.f, 1.f}, {0.0f, 0.0f}}, {{0, 0}, {1.f, 1.f, 1.f, 1.f}, {0.0f, 0.0f}},
@@ -42,25 +45,44 @@ namespace mlx
{{0, height}, {1.f, 1.f, 1.f, 1.f}, {0.0f, 1.0f}} {{0, height}, {1.f, 1.f, 1.f, 1.f}, {0.0f, 1.0f}}
}; };
std::vector<uint16_t> indexData = { 0, 1, 2, 2, 3, 0 }; std::vector<std::uint16_t> indexData = { 0, 1, 2, 2, 3, 0 };
_vbo.create(sizeof(Vertex) * vertexData.size(), vertexData.data(), name); #ifdef DEBUG
_ibo.create(sizeof(uint16_t) * indexData.size(), indexData.data(), name); _vbo.create(sizeof(Vertex) * vertexData.size(), vertexData.data(), name);
_ibo.create(sizeof(std::uint16_t) * indexData.size(), indexData.data(), name);
_name = name;
#else
_vbo.create(sizeof(Vertex) * vertexData.size(), vertexData.data(), nullptr);
_ibo.create(sizeof(std::uint16_t) * indexData.size(), indexData.data(), nullptr);
#endif
Buffer staging_buffer;
std::size_t size = width * height * formatSize(format);
if(pixels != nullptr) if(pixels != nullptr)
{ {
Buffer staging_buffer; #ifdef DEBUG
std::size_t size = width * height * formatSize(format); staging_buffer.create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, name, pixels);
staging_buffer.create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, name, pixels); #else
Image::copyFromBuffer(staging_buffer); staging_buffer.create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, nullptr, pixels);
staging_buffer.destroy(); #endif
} }
_name = name; else
{
std::vector<std::uint32_t> default_pixels(width * height, 0x00000000);
#ifdef DEBUG
staging_buffer.create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, name, default_pixels.data());
#else
staging_buffer.create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, nullptr, default_pixels.data());
#endif
}
Image::copyFromBuffer(staging_buffer);
staging_buffer.destroy();
} }
void Texture::setPixel(int x, int y, uint32_t color) noexcept void Texture::setPixel(int x, int y, std::uint32_t color) noexcept
{ {
if(x < 0 || y < 0 || x > getWidth() || y > getHeight()) MLX_PROFILE_FUNCTION();
if(x < 0 || y < 0 || static_cast<std::uint32_t>(x) > getWidth() || static_cast<std::uint32_t>(y) > getHeight())
return; return;
if(_map == nullptr) if(_map == nullptr)
openCPUmap(); openCPUmap();
@@ -70,16 +92,22 @@ namespace mlx
int Texture::getPixel(int x, int y) noexcept int Texture::getPixel(int x, int y) noexcept
{ {
if(x < 0 || y < 0 || x > getWidth() || y > getHeight()) MLX_PROFILE_FUNCTION();
if(x < 0 || y < 0 || static_cast<std::uint32_t>(x) > getWidth() || static_cast<std::uint32_t>(y) > getHeight())
return 0; return 0;
if(_map == nullptr) if(_map == nullptr)
openCPUmap(); openCPUmap();
uint32_t color = _cpu_map[(y * getWidth()) + x]; std::uint32_t color = _cpu_map[(y * getWidth()) + x];
return (color); std::uint8_t* bytes = reinterpret_cast<std::uint8_t*>(&color);
std::uint8_t tmp = bytes[0];
bytes[0] = bytes[2];
bytes[2] = tmp;
return *reinterpret_cast<int*>(bytes);
} }
void Texture::openCPUmap() void Texture::openCPUmap()
{ {
MLX_PROFILE_FUNCTION();
if(_map != nullptr) if(_map != nullptr)
return; return;
@@ -88,35 +116,50 @@ namespace mlx
#endif #endif
std::size_t size = getWidth() * getHeight() * formatSize(getFormat()); std::size_t size = getWidth() * getHeight() * formatSize(getFormat());
_buf_map.emplace(); _buf_map.emplace();
_buf_map->create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, _name.c_str()); #ifdef DEBUG
_buf_map->create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, _name.c_str());
#else
_buf_map->create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, nullptr);
#endif
Image::copyToBuffer(*_buf_map); Image::copyToBuffer(*_buf_map);
_buf_map->mapMem(&_map); _buf_map->mapMem(&_map);
_cpu_map = std::vector<uint32_t>(getWidth() * getHeight(), 0); _cpu_map = std::vector<std::uint32_t>(getWidth() * getHeight(), 0);
std::memcpy(_cpu_map.data(), _map, size); std::memcpy(_cpu_map.data(), _map, size);
#ifdef DEBUG #ifdef DEBUG
core::error::report(e_kind::message, "Texture : mapped CPU memory using staging buffer"); core::error::report(e_kind::message, "Texture : mapped CPU memory using staging buffer");
#endif #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) if(_has_been_modified)
{ {
std::memcpy(_map, _cpu_map.data(), _cpu_map.size() * formatSize(getFormat())); std::memcpy(_map, _cpu_map.data(), _cpu_map.size() * formatSize(getFormat()));
Image::copyFromBuffer(*_buf_map); Image::copyFromBuffer(*_buf_map);
_has_been_modified = false; _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); _vbo.bind(renderer);
_ibo.bind(renderer); _ibo.bind(renderer);
glm::vec2 translate(x, y); glm::vec2 translate(x, y);
vkCmdPushConstants(cmd, renderer.getPipeline().getPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(translate), &translate); vkCmdPushConstants(cmd.get(), 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); sets[1] = _set.get();
vkCmdBindDescriptorSets(renderer.getActiveCmdBuffer().get(), VK_PIPELINE_BIND_POINT_GRAPHICS, renderer.getPipeline().getPipelineLayout(), 0, sets.size(), sets.data(), 0, nullptr);
vkCmdDrawIndexed(cmd.get(), static_cast<std::uint32_t>(_ibo.getSize() / sizeof(std::uint16_t)), 1, 0, 0, 0);
} }
void Texture::destroy() noexcept void Texture::destroy() noexcept
{ {
MLX_PROFILE_FUNCTION();
Image::destroy(); Image::destroy();
_set.destroy();
if(_buf_map.has_value()) if(_buf_map.has_value())
_buf_map->destroy(); _buf_map->destroy();
_vbo.destroy(); _vbo.destroy();
@@ -125,17 +168,24 @@ namespace mlx
Texture stbTextureLoad(std::filesystem::path file, int* w, int* h) Texture stbTextureLoad(std::filesystem::path file, int* w, int* h)
{ {
MLX_PROFILE_FUNCTION();
Texture texture; Texture texture;
int channels; int channels;
uint8_t* data = nullptr; std::uint8_t* data = nullptr;
std::string filename = file.string(); std::string filename = file.string();
if(!std::filesystem::exists(std::move(file))) if(!std::filesystem::exists(std::move(file)))
core::error::report(e_kind::fatal_error, "Image : file not found '%s'", filename.c_str()); core::error::report(e_kind::fatal_error, "Image : file not found '%s'", filename.c_str());
if(stbi_is_hdr(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()); 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;
texture.create(data, *w, *h, VK_FORMAT_R8G8B8A8_UNORM, filename.c_str()); 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 == nullptr ? dummy_w : *w), (h == nullptr ? dummy_h : *h), VK_FORMAT_R8G8B8A8_UNORM, filename.c_str());
#else
texture.create(data, (w == nullptr ? dummy_w : *w), (h == nullptr ? dummy_h : *h), VK_FORMAT_R8G8B8A8_UNORM, nullptr);
#endif
stbi_image_free(data); stbi_image_free(data);
return texture; return texture;
} }

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2023/03/08 02:24:58 by maldavid #+# #+# */ /* Created: 2023/03/08 02:24:58 by maldavid #+# #+# */
/* Updated: 2023/11/14 04:57:39 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/descriptors/vk_descriptor_set.h>
#include <renderer/buffers/vk_ibo.h> #include <renderer/buffers/vk_ibo.h>
#include <renderer/buffers/vk_vbo.h> #include <renderer/buffers/vk_vbo.h>
#include <mlx_profile.h>
#include <string>
namespace mlx namespace mlx
{ {
@@ -29,18 +31,18 @@ namespace mlx
public: public:
Texture() = default; Texture() = default;
void create(uint8_t* pixels, uint32_t width, uint32_t height, VkFormat format, const char* name, bool dedicated_memory = false); void create(std::uint8_t* pixels, std::uint32_t width, std::uint32_t height, VkFormat format, const char* name, bool dedicated_memory = false);
void render(class Renderer& renderer, int x, int y); void render(std::array<VkDescriptorSet, 2>& sets, class Renderer& renderer, int x, int y);
void destroy() noexcept override; void destroy() noexcept override;
void setPixel(int x, int y, uint32_t color) noexcept; void setPixel(int x, int y, std::uint32_t color) noexcept;
int getPixel(int x, int y) noexcept; 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 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 void updateSet(int binding) noexcept { _set.writeDescriptor(binding, *this); _has_set_been_updated = true; }
inline bool hasBeenUpdated() const noexcept { return _has_been_updated; } inline bool hasBeenUpdated() const noexcept { return _has_set_been_updated; }
inline constexpr void resetUpdate() noexcept { _has_been_updated = false; } inline constexpr void resetUpdate() noexcept { _has_set_been_updated = false; }
~Texture() = default; ~Texture() = default;
@@ -50,38 +52,18 @@ namespace mlx
private: private:
C_VBO _vbo; C_VBO _vbo;
C_IBO _ibo; C_IBO _ibo;
std::string _name; #ifdef DEBUG
std::string _name;
#endif
DescriptorSet _set; DescriptorSet _set;
std::vector<uint32_t> _cpu_map; std::vector<std::uint32_t> _cpu_map;
std::optional<Buffer> _buf_map = std::nullopt; std::optional<Buffer> _buf_map = std::nullopt;
void* _map = nullptr; void* _map = nullptr;
bool _has_been_modified = false; 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); Texture stbTextureLoad(std::filesystem::path file, int* w, int* h);
struct TextureRenderData
{
Texture* texture;
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 #endif

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/07 16:40:09 by maldavid #+# #+# */ /* Created: 2023/04/07 16:40:09 by maldavid #+# #+# */
/* Updated: 2023/11/14 05:36:46 by maldavid ### ########.fr */ /* Updated: 2024/01/18 10:18:08 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@@ -20,33 +20,37 @@
namespace mlx namespace mlx
{ {
void TextureAtlas::create(uint8_t* pixels, uint32_t width, uint32_t height, VkFormat format, const char* name, bool dedicated_memory) void TextureAtlas::create(std::uint8_t* pixels, std::uint32_t width, std::uint32_t height, VkFormat format, const char* name, bool dedicated_memory)
{ {
Image::create(width, height, format, TILING, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, name, dedicated_memory); Image::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::createImageView(VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT);
Image::createSampler(); Image::createSampler();
transitionLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
if(pixels != nullptr) if(pixels == nullptr)
{ {
Buffer staging_buffer; 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");
std::size_t size = width * height * formatSize(format); return;
staging_buffer.create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, name, pixels);
Image::copyFromBuffer(staging_buffer);
staging_buffer.destroy();
} }
Buffer staging_buffer;
std::size_t size = width * height * formatSize(format);
staging_buffer.create(Buffer::kind::dynamic, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, name, pixels);
Image::copyFromBuffer(staging_buffer);
staging_buffer.destroy();
} }
void TextureAtlas::render(Renderer& renderer, int x, int y, uint32_t ibo_size) void TextureAtlas::render(Renderer& renderer, int x, int y, std::uint32_t ibo_size) const
{ {
auto cmd = renderer.getActiveCmdBuffer().get(); auto cmd = renderer.getActiveCmdBuffer().get();
glm::vec2 translate(x, y); glm::vec2 translate(x, y);
vkCmdPushConstants(cmd, renderer.getPipeline().getPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(translate), &translate); vkCmdPushConstants(cmd, renderer.getPipeline().getPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(translate), &translate);
vkCmdDrawIndexed(cmd, ibo_size / sizeof(uint16_t), 1, 0, 0, 0); vkCmdDrawIndexed(cmd, ibo_size / sizeof(std::uint16_t), 1, 0, 0, 0);
} }
void TextureAtlas::destroy() noexcept void TextureAtlas::destroy() noexcept
{ {
Image::destroy(); Image::destroy();
_set.destroy();
} }
} }

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/07 16:36:33 by maldavid #+# #+# */ /* 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 <renderer/images/texture.h>
#include <array> #include <array>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <mlx_profile.h>
namespace mlx namespace mlx
{ {
@@ -24,18 +25,22 @@ namespace mlx
public: public:
TextureAtlas() = default; TextureAtlas() = default;
void create(uint8_t* pixels, uint32_t width, uint32_t height, VkFormat format, const char* name, bool dedicated_memory = false); void create(std::uint8_t* pixels, std::uint32_t width, std::uint32_t height, VkFormat format, const char* name, bool dedicated_memory = false);
void render(class Renderer& renderer, int x, int y, uint32_t ibo_size); void render(class Renderer& renderer, int x, int y, std::uint32_t ibo_size) const;
void destroy() noexcept override; void destroy() noexcept override;
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 VkDescriptorSet getVkSet() noexcept { return _set.isInit() ? _set.get() : VK_NULL_HANDLE; }
inline void updateSet(int binding) noexcept { _set.writeDescriptor(binding, getImageView(), getSampler()); } 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; ~TextureAtlas() = default;
private: private:
DescriptorSet _set; 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> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2023/01/25 11:59:07 by maldavid #+# #+# */ /* Created: 2023/01/25 11:59:07 by maldavid #+# #+# */
/* Updated: 2023/11/14 09:31:39 by maldavid ### ########.fr */ /* Updated: 2024/02/25 08:03:47 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@@ -18,7 +18,88 @@
namespace mlx namespace mlx
{ {
void Image::create(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, const char* name, bool dedicated_memory) bool isStencilFormat(VkFormat format)
{
switch(format)
{
case VK_FORMAT_D32_SFLOAT_S8_UINT:
case VK_FORMAT_D24_UNORM_S8_UINT:
return true;
default: return false;
}
}
bool isDepthFormat(VkFormat format)
{
switch(format)
{
case VK_FORMAT_D16_UNORM:
case VK_FORMAT_D32_SFLOAT:
case VK_FORMAT_D32_SFLOAT_S8_UINT:
case VK_FORMAT_D24_UNORM_S8_UINT:
case VK_FORMAT_D16_UNORM_S8_UINT:
return true;
default: return false;
}
}
VkFormat bitsToFormat(std::uint32_t bits)
{
switch(bits)
{
case 8: return VK_FORMAT_R8_UNORM;
case 16: return VK_FORMAT_R8G8_UNORM;
case 24: return VK_FORMAT_R8G8B8_UNORM;
case 32: return VK_FORMAT_R8G8B8A8_UNORM;
case 48: return VK_FORMAT_R16G16B16_SFLOAT;
case 64: return VK_FORMAT_R16G16B16A16_SFLOAT;
case 96: return VK_FORMAT_R32G32B32_SFLOAT;
case 128: return VK_FORMAT_R32G32B32A32_SFLOAT;
default:
core::error::report(e_kind::fatal_error, "Vulkan : unsupported image bit-depth");
return VK_FORMAT_R8G8B8A8_UNORM;
}
}
VkPipelineStageFlags layoutToAccessMask(VkImageLayout layout, bool isDestination)
{
VkPipelineStageFlags accessMask = 0;
switch(layout)
{
case VK_IMAGE_LAYOUT_UNDEFINED:
if(isDestination)
core::error::report(e_kind::error, "Vulkan : the new layout used in a transition must not be VK_IMAGE_LAYOUT_UNDEFINED");
break;
case VK_IMAGE_LAYOUT_GENERAL: accessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; break;
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: accessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; break;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: accessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; break;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
accessMask = VK_ACCESS_SHADER_READ_BIT; // VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
break;
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: accessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; break;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: accessMask = VK_ACCESS_TRANSFER_READ_BIT; break;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: accessMask = VK_ACCESS_TRANSFER_WRITE_BIT; break;
case VK_IMAGE_LAYOUT_PREINITIALIZED:
if(!isDestination)
accessMask = VK_ACCESS_HOST_WRITE_BIT;
else
core::error::report(e_kind::error, "Vulkan : the new layout used in a transition must not be VK_IMAGE_LAYOUT_PREINITIALIZED");
break;
case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL: accessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; break;
case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL: accessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; break;
case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: accessMask = VK_ACCESS_MEMORY_READ_BIT; break;
default: core::error::report(e_kind::error, "Vulkan : unexpected image layout"); break;
}
return accessMask;
}
void Image::create(std::uint32_t width, std::uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, const char* name, bool dedicated_memory)
{ {
_width = width; _width = width;
_height = height; _height = height;
@@ -49,8 +130,9 @@ namespace mlx
} }
_allocation = Render_Core::get().getAllocator().createImage(&imageInfo, &alloc_info, _image, name); _allocation = Render_Core::get().getAllocator().createImage(&imageInfo, &alloc_info, _image, name);
#ifdef DEBUG
_pool.init(); _name = name;
#endif
} }
void Image::createImageView(VkImageViewType type, VkImageAspectFlags aspectFlags) noexcept void Image::createImageView(VkImageViewType type, VkImageAspectFlags aspectFlags) noexcept
@@ -66,8 +148,13 @@ namespace mlx
viewInfo.subresourceRange.baseArrayLayer = 0; viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = 1; viewInfo.subresourceRange.layerCount = 1;
if(vkCreateImageView(Render_Core::get().getDevice().get(), &viewInfo, nullptr, &_image_view) != VK_SUCCESS) VkResult res = vkCreateImageView(Render_Core::get().getDevice().get(), &viewInfo, nullptr, &_image_view);
core::error::report(e_kind::fatal_error, "Vulkan : failed to create an image view"); if(res != VK_SUCCESS)
core::error::report(e_kind::fatal_error, "Vulkan : failed to create an image view, %s", RCore::verbaliseResultVk(res));
#ifdef DEBUG
else
Render_Core::get().getLayers().setDebugUtilsObjectNameEXT(VK_OBJECT_TYPE_IMAGE_VIEW, (std::uint64_t)_image_view, _name.c_str());
#endif
} }
void Image::createSampler() noexcept void Image::createSampler() noexcept
@@ -85,130 +172,99 @@ namespace mlx
info.anisotropyEnable = VK_FALSE; info.anisotropyEnable = VK_FALSE;
info.maxAnisotropy = 1.0f; info.maxAnisotropy = 1.0f;
if(vkCreateSampler(Render_Core::get().getDevice().get(), &info, nullptr, &_sampler) != VK_SUCCESS) VkResult res = vkCreateSampler(Render_Core::get().getDevice().get(), &info, nullptr, &_sampler);
core::error::report(e_kind::fatal_error, "Vulkan : failed to create an image"); if(res != VK_SUCCESS)
core::error::report(e_kind::fatal_error, "Vulkan : failed to create an image sampler, %s", RCore::verbaliseResultVk(res));
#ifdef DEBUG
else
Render_Core::get().getLayers().setDebugUtilsObjectNameEXT(VK_OBJECT_TYPE_SAMPLER, (std::uint64_t)_sampler, _name.c_str());
#endif
} }
void Image::copyFromBuffer(Buffer& buffer) void Image::copyFromBuffer(Buffer& buffer)
{ {
if(!_transfer_cmd.isInit()) CmdBuffer& cmd = Render_Core::get().getSingleTimeCmdBuffer();
_transfer_cmd.init(&_pool); cmd.beginRecord();
_transfer_cmd.reset(); VkImageLayout layout_save = _layout;
_transfer_cmd.beginRecord(); transitionLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &cmd);
VkImageMemoryBarrier copy_barrier{}; cmd.copyBufferToImage(buffer, *this);
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);
VkBufferImageCopy region{}; transitionLayout(layout_save, &cmd);
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 };
vkCmdCopyBufferToImage(_transfer_cmd.get(), buffer.get(), _image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region); cmd.endRecord();
cmd.submitIdle();
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();
} }
void Image::copyToBuffer(Buffer& buffer) void Image::copyToBuffer(Buffer& buffer)
{ {
if(!_transfer_cmd.isInit()) CmdBuffer& cmd = Render_Core::get().getSingleTimeCmdBuffer();
_transfer_cmd.init(&_pool); cmd.beginRecord();
_transfer_cmd.reset(); VkImageLayout layout_save = _layout;
_transfer_cmd.beginRecord(); transitionLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &cmd);
VkImageMemoryBarrier copy_barrier{}; cmd.copyImagetoBuffer(*this, buffer);
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);
VkBufferImageCopy region{}; transitionLayout(layout_save, &cmd);
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 };
vkCmdCopyImageToBuffer(_transfer_cmd.get(), _image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer.get(), 1, &region); cmd.endRecord();
cmd.submitIdle();
}
VkImageMemoryBarrier use_barrier{}; void Image::transitionLayout(VkImageLayout new_layout, CmdBuffer* cmd)
use_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; {
use_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; if(new_layout == _layout)
use_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; return;
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(); bool singleTime = (cmd == nullptr);
_transfer_cmd.submitIdle(); if(singleTime)
{
cmd = &Render_Core::get().getSingleTimeCmdBuffer();
cmd->beginRecord();
}
cmd->transitionImageLayout(*this, new_layout);
if(singleTime)
{
cmd->endRecord();
cmd->submitIdle();
}
_layout = new_layout;
}
void Image::destroySampler() noexcept
{
if(_sampler != VK_NULL_HANDLE)
vkDestroySampler(Render_Core::get().getDevice().get(), _sampler, nullptr);
_sampler = VK_NULL_HANDLE;
}
void Image::destroyImageView() noexcept
{
if(_image_view != VK_NULL_HANDLE)
vkDestroyImageView(Render_Core::get().getDevice().get(), _image_view, nullptr);
_image_view = VK_NULL_HANDLE;
} }
void Image::destroy() noexcept void Image::destroy() noexcept
{ {
if(_sampler != VK_NULL_HANDLE) // not creating destroyer in `create` as some image may be copied (and so `this` will be invalid)
vkDestroySampler(Render_Core::get().getDevice().get(), _sampler, nullptr); //CmdResource::setDestroyer([this]()
if(_image_view != VK_NULL_HANDLE) //{
vkDestroyImageView(Render_Core::get().getDevice().get(), _image_view, nullptr); destroySampler();
destroyImageView();
if(_image != VK_NULL_HANDLE) if(_image != VK_NULL_HANDLE)
Render_Core::get().getAllocator().destroyImage(_allocation, _image); Render_Core::get().getAllocator().destroyImage(_allocation, _image);
_image = VK_NULL_HANDLE; _image = VK_NULL_HANDLE;
if(_transfer_cmd.isInit()) //});
_transfer_cmd.destroy(); //CmdResource::requireDestroy();
_pool.destroy();
} }
uint32_t formatSize(VkFormat format) std::uint32_t formatSize(VkFormat format)
{ {
switch(format) switch(format)
{ {

View File

@@ -6,57 +6,85 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */ /* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2023/01/25 11:54:21 by maldavid #+# #+# */ /* Created: 2023/01/25 11:54:21 by maldavid #+# #+# */
/* Updated: 2023/11/14 03:15:18 by maldavid ### ########.fr */ /* Updated: 2024/01/19 06:10:15 by maldavid ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
#ifndef __VK_IMAGE__ #ifndef __MLX_VK_IMAGE__
#define __VK_IMAGE__ #define __MLX_VK_IMAGE__
#include <mlx_profile.h>
#include <volk.h> #include <volk.h>
#include <cstddef> #include <vma.h>
#include <vector> #include <renderer/core/cmd_resource.h>
#include <renderer/command/vk_cmd_buffer.h> #include <renderer/command/vk_cmd_buffer.h>
#include <renderer/command/vk_cmd_pool.h> #include <renderer/command/vk_cmd_pool.h>
#ifdef DEBUG
#include <string>
#endif
namespace mlx namespace mlx
{ {
uint32_t formatSize(VkFormat format); std::uint32_t formatSize(VkFormat format);
bool isStencilFormat(VkFormat format);
bool isDepthFormat(VkFormat format);
VkFormat bitsToFormat(std::uint32_t bits);
VkPipelineStageFlags layoutToAccessMask(VkImageLayout layout, bool isDestination);
class Image class Image : public CmdResource
{ {
friend class SwapChain;
public: public:
Image() = default; Image() = default;
void create(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, const char* name, bool decated_memory = false); inline void create(VkImage image, VkFormat format, std::uint32_t width, std::uint32_t height, VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED) noexcept
{
_image = image;
_format = format;
_width = width;
_height = height;
_layout = layout;
}
void create(std::uint32_t width, std::uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, const char* name, bool decated_memory = false);
void createImageView(VkImageViewType type, VkImageAspectFlags aspectFlags) noexcept; void createImageView(VkImageViewType type, VkImageAspectFlags aspectFlags) noexcept;
void createSampler() noexcept; void createSampler() noexcept;
void copyFromBuffer(class Buffer& buffer); void copyFromBuffer(class Buffer& buffer);
void copyToBuffer(class Buffer& buffer); void copyToBuffer(class Buffer& buffer);
void transitionLayout(VkImageLayout new_layout, CmdBuffer* cmd = nullptr);
virtual void destroy() noexcept; virtual void destroy() noexcept;
inline VkImage get() noexcept { return _image; } inline VkImage get() noexcept { return _image; }
inline VkImage operator()() noexcept { return _image; } inline VkImage operator()() noexcept { return _image; }
inline VkImageView getImageView() noexcept { return _image_view; } inline VkImageView getImageView() const noexcept { return _image_view; }
inline VkFormat getFormat() noexcept { return _format; } inline VkFormat getFormat() const noexcept { return _format; }
inline VkImageTiling getTiling() noexcept { return _tiling; } inline VkImageTiling getTiling() const noexcept { return _tiling; }
inline VkSampler getSampler() noexcept { return _sampler; } inline VkImageLayout getLayout() const noexcept { return _layout; }
inline uint32_t getWidth() const noexcept { return _width; } inline VkSampler getSampler() const noexcept { return _sampler; }
inline uint32_t getHeight() const noexcept { return _height; } inline std::uint32_t getWidth() const noexcept { return _width; }
inline std::uint32_t getHeight() const noexcept { return _height; }
inline bool isInit() const noexcept { return _image != VK_NULL_HANDLE; }
virtual ~Image() = default; virtual ~Image() = default;
private: private:
CmdBuffer _transfer_cmd; void destroySampler() noexcept;
CmdPool _pool; void destroyImageView() noexcept;
private:
VmaAllocation _allocation; VmaAllocation _allocation;
VkImage _image = VK_NULL_HANDLE; VkImage _image = VK_NULL_HANDLE;
VkImageView _image_view = VK_NULL_HANDLE; VkImageView _image_view = VK_NULL_HANDLE;
VkSampler _sampler = VK_NULL_HANDLE; VkSampler _sampler = VK_NULL_HANDLE;
#ifdef DEBUG
std::string _name;
#endif
VkFormat _format; VkFormat _format;
VkImageTiling _tiling; VkImageTiling _tiling;
uint32_t _width = 0; VkImageLayout _layout = VK_IMAGE_LAYOUT_UNDEFINED;
uint32_t _height = 0; std::uint32_t _width = 0;
std::uint32_t _height = 0;
}; };
} }

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