MXVK Vulkan Framework 0.24.0
C++20 Vulkan rendering framework for practical 2D and 3D application development with SDL3.
Loading...
Searching...
No Matches
mxvk_abstract_model.hpp
Go to the documentation of this file.
1/**
2 * @file mxvk_abstract_model.hpp
3 * @brief High-level model wrapper integrated with MXVK dynamic rendering.
4 */
5#pragma once
6
7#include <volk/volk.h>
8
9#include "mxvk.hpp"
10#include "mxvk_model.hpp"
11
12#include <glm/glm.hpp>
13
14#include <string>
15#include <vector>
16#ifdef MXVK_CUDA
17#include <cuda_runtime_api.h>
18#include <opencv2/core/cuda.hpp>
19#endif
20
21namespace mxvk {
22
23 /**
24 * @struct UniformBufferObject
25 * @brief Default transform UBO payload for model shaders.
26 */
28 glm::mat4 model{1.0f};
29 glm::mat4 view{1.0f};
30 glm::mat4 proj{1.0f};
31 glm::vec4 fx{0.0f, 0.0f, 0.0f, 0.0f};
32 };
33
34 /**
35 * @struct ModelFragmentPushConstants
36 * @brief Sprite-compatible fragment parameters for UV-based model effects.
37 */
39 float screenWidth = 1.0f;
40 float screenHeight = 1.0f;
41 float spritePosX = 0.0f;
42 float spritePosY = 0.0f;
43 float spriteSizeW = 1.0f;
44 float spriteSizeH = 1.0f;
45 float effectsOn = 1.0f;
46 float padding = 0.0f;
47 glm::vec4 params{0.0f};
48 };
49
50 /** @brief Extended shader-viewer uniforms available to fragment shaders at binding 1. */
52 glm::vec4 mouse{0.0f};
53 glm::vec4 u0{0.0f};
54 glm::vec4 u1{0.0f};
55 glm::vec4 u2{0.0f};
56 glm::vec4 u3{0.0f};
57 };
58
59 /**
60 * @class VKAbstractModel
61 * @brief Convenience wrapper that owns mesh, textures, descriptors, and pipeline state.
62 *
63 * This class is intended to be recorded from inside
64 * `VK_Window::onRecordCustomRendering()` so it participates in the same
65 * dynamic-rendering pass as sprites/text.
66 */
68 public:
69 VKAbstractModel() = default;
70 ~VKAbstractModel() = default;
71
76
77 /**
78 * @brief Load mesh/texture resources and build Vulkan state.
79 * @param window Active MXVK window.
80 * @param modelPath Path to .obj or .mxmod mesh file.
81 * @param textureManifestPath Optional texture manifest path (.tex or .mtl-like text).
82 * @param textureBasePath Optional base path for texture files in the manifest.
83 * @param scale Uniform mesh scale.
84 */
85 void load(VK_Window *window,
86 const std::string &modelPath,
87 const std::string &textureManifestPath,
88 const std::string &textureBasePath,
89 float scale = 1.0f);
90
91 /**
92 * @brief Consume pre-parsed mesh data and build Vulkan state.
93 * @param window Active MXVK window.
94 * @param model Pre-parsed CPU-side model data.
95 * @param textureManifestPath Optional texture manifest path (.tex or .mtl-like text).
96 * @param textureBasePath Optional base path for texture files in the manifest.
97 * @param scale Uniform mesh scale. Kept for API compatibility.
98 */
99 void load(VK_Window *window,
100 MXModel &&model,
101 const std::string &textureManifestPath,
102 const std::string &textureBasePath,
103 [[maybe_unused]] float scale = 1.0f);
104
105 /**
106 * @brief Configure custom shader paths and rebuild pipelines.
107 * @param window Active MXVK window.
108 * @param vertSpv Vertex shader SPIR-V path.
109 * @param fragSpv Fragment shader SPIR-V path.
110 */
111 void setShaders(VK_Window *window, const std::string &vertSpv, const std::string &fragSpv);
112
113 /**
114 * @brief Update one per-frame UBO payload.
115 * @param imageIndex Swapchain image index.
116 * @param ubo New transform values.
117 */
118 void updateUBO(uint32_t imageIndex, const UniformBufferObject &ubo);
119
120 /** @brief Use binding 1 for fragment uniforms and binding 2 for model transforms. Call before load(). */
122
123 /** @brief Update extended fragment uniforms for one swapchain image. */
124 void updateFragmentUBO(uint32_t imageIndex, const ModelFragmentUniforms &uniforms);
125
126 /** @brief Set sprite-compatible push constants used by custom fragment shaders. */
128
129 /**
130 * @brief Upload raw RGBA pixels into the primary model texture.
131 * @param pixels Pointer to RGBA8 pixel data.
132 * @param width Texture width in pixels.
133 * @param height Texture height in pixels.
134 * @param pitch Bytes per input row. When 0, defaults to width * 4.
135 * @return True when the upload succeeds, false for invalid inputs or unavailable resources.
136 */
137 [[nodiscard]] bool updatePrimaryTexture(const void *pixels, int width, int height, int pitch = 0);
138
139#ifdef MXVK_CUDA
140 /**
141 * @brief Upload RGBA8 pixels from CUDA device memory into the primary model texture.
142 *
143 * The Vulkan texture is imported into CUDA as a mipmapped array because
144 * sampled Vulkan images use opaque optimal tiling, not a linear pitched layout.
145 */
146 [[nodiscard]] bool updatePrimaryTextureCuda(const cv::cuda::GpuMat &rgba, cv::cuda::Stream &stream);
147#endif
148
149 /**
150 * @brief Record draw commands for this model.
151 * @param cmd Active command buffer, inside a dynamic rendering scope.
152 * @param imageIndex Current swapchain image index.
153 * @param wireframe Render using the optional wireframe pipeline when available.
154 */
155 void render(VkCommandBuffer cmd, uint32_t imageIndex, bool wireframe = false) const;
156
157 /**
158 * @brief Record one draw using push constants for per-draw transforms and an explicit texture slot.
159 * @param cmd Active command buffer, inside a dynamic rendering scope.
160 * @param imageIndex Current swapchain image index.
161 * @param textureIndex Texture slot to bind for all submeshes in this draw.
162 * @param ubo Transform/effect payload copied into vertex-stage push constants.
163 * @param wireframe Render using the optional wireframe pipeline when available.
164 */
165 void renderWithPushConstants(VkCommandBuffer cmd,
166 uint32_t imageIndex,
167 size_t textureIndex,
168 const UniformBufferObject &ubo,
169 bool wireframe = false);
170
171 /**
172 * @brief Rebuild swapchain-dependent resources after resize.
173 * @param window Active MXVK window.
174 */
175 void resize(VK_Window *window);
176
177 /**
178 * @brief Destroy all owned Vulkan resources.
179 * @param window Active MXVK window.
180 */
181 void cleanup(VK_Window *window);
182
183 /** @brief Access the underlying mesh object. */
184 [[nodiscard]] const MXModel &model() const { return obj; }
185 /** @brief Access the computed center offset used for normalization. */
186 [[nodiscard]] glm::vec3 modelCenterOffset() const { return modelCenterOffsetValue; }
187 /** @brief Access the computed render scale used for normalization. */
188 [[nodiscard]] float modelRenderScale() const { return modelRenderScaleValue; }
189 /** @brief Per-axis extent (max - min) of the source mesh's bounding box. */
190 [[nodiscard]] glm::vec3 modelAxisExtent() const { return modelAxisExtentValue; }
191 /** @brief True once the model has been uploaded to GPU buffers. */
192 [[nodiscard]] bool isLoaded() const { return obj.indexCount() > 0 && vertexBufferReady(); }
193
194 /**
195 * @brief Enable or disable backface culling for this model pipeline.
196 * @param enabled True to cull backfaces, false to disable culling.
197 */
198 void setBackfaceCulling(bool enabled);
199
200 /**
201 * @brief Enable or disable alpha blending for this model pipeline.
202 * @param enabled True to blend fragment alpha and avoid depth writes.
203 */
204 void setAlphaBlending(bool enabled);
205
206 private:
207 struct TextureEntry {
208 VkImage image = VK_NULL_HANDLE;
209 VkDeviceMemory memory = VK_NULL_HANDLE;
210 VkImageView view = VK_NULL_HANDLE;
211 uint32_t width = 0;
212 uint32_t height = 0;
213#ifdef MXVK_CUDA
214 VkDeviceSize cudaExportMemorySize = 0;
215 cudaExternalMemory_t cudaExternalMemory = nullptr;
216 cudaMipmappedArray_t cudaMipmappedArray = nullptr;
217 cudaArray_t cudaArray = nullptr;
218 bool cudaInteropEnabled = false;
219 bool cudaInteropUnavailableLogged = false;
220 bool cudaUploadLogged = false;
221 bool cudaWriteTransitionLogged = false;
222 bool cudaShaderTransitionLogged = false;
223 VkImageLayout cudaImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
224#endif
225 };
226
227 MXModel obj{};
228 std::vector<TextureEntry> textures{};
229
230 VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE;
231 VkDescriptorPool descriptorPool = VK_NULL_HANDLE;
232 uint32_t descriptorPoolSetCapacity = 0;
233 std::vector<VkDescriptorSet> descriptorSets{};
234
235 VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
236 VkPipeline pipelineFill = VK_NULL_HANDLE;
237 VkPipeline pipelineWireframe = VK_NULL_HANDLE;
238 VkSampler textureSampler = VK_NULL_HANDLE;
239
240 std::vector<VkBuffer> uniformBuffers{};
241 std::vector<VkDeviceMemory> uniformBufferMemory{};
242 std::vector<void *> uniformBuffersMapped{};
243 std::vector<VkBuffer> fragmentUniformBuffers{};
244 std::vector<VkDeviceMemory> fragmentUniformBufferMemory{};
245 std::vector<void *> fragmentUniformBuffersMapped{};
246
247 glm::vec3 modelCenterOffsetValue{0.0f, 0.0f, 0.0f};
248 float modelRenderScaleValue = 1.0f;
249 glm::vec3 modelAxisExtentValue{1.0f, 1.0f, 1.0f};
250
251 std::string vertexShaderPath{};
252 std::string fragmentShaderPath{};
253 bool backfaceCullingEnabled = false;
254 bool alphaBlendingEnabled = false;
255 ModelFragmentPushConstants fragmentPushConstants{};
256 bool extendedFragmentUniformsEnabled = false;
257
258 VK_Window *windowPtr = nullptr;
259
260 [[nodiscard]] bool vertexBufferReady() const { return obj.vertexBuffer() != VK_NULL_HANDLE && obj.indexBuffer() != VK_NULL_HANDLE; }
261
262 void computeBoundsAndScale();
263 void loadTextures(const std::string &textureManifestPath, const std::string &textureBasePath);
264 void loadTexturesFromMTL(const std::string &textureBasePath);
265 void createFallbackTexture();
266
267 void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage,
268 VkMemoryPropertyFlags properties, VkBuffer &buffer,
269 VkDeviceMemory &bufferMemory) const;
270 [[nodiscard]] uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) const;
271 [[nodiscard]] VkCommandBuffer beginSingleTimeCommands() const;
272 void endSingleTimeCommands(VkCommandBuffer commandBuffer) const;
273 void createImage(uint32_t width, uint32_t height, VkFormat format,
274 VkImageTiling tiling, VkImageUsageFlags usage,
275 VkMemoryPropertyFlags properties, VkImage &image,
276 VkDeviceMemory &memory) const;
277 void createTextureImage(uint32_t width, uint32_t height, TextureEntry &texture) const;
278#ifdef MXVK_CUDA
279 void createCudaExportableImage(uint32_t width, uint32_t height, TextureEntry &texture) const;
280 void destroyTextureCudaInterop(TextureEntry &texture) const;
281 [[nodiscard]] bool ensureTextureCudaInterop(TextureEntry &texture) const;
282 [[nodiscard]] bool transitionTextureForCudaWrite(TextureEntry &texture) const;
283 [[nodiscard]] bool transitionTextureForShaderRead(TextureEntry &texture) const;
284 [[nodiscard]] bool updatePrimaryTextureCudaHost(TextureEntry &texture, const void *pixels,
285 uint32_t width, uint32_t height, uint32_t pitch) const;
286 void recreatePrimaryTextureForCuda(TextureEntry &texture, uint32_t width, uint32_t height);
287#endif
288 [[nodiscard]] VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags) const;
289 void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout) const;
290 void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height) const;
291
292 void createTextureSampler();
293 void createDescriptorSetLayout();
294 void createUniformBuffers();
295 void destroyUniformBuffers();
296 void createDescriptorPool();
297 void createDescriptorSets();
298 void createPipelines();
299
300 void destroyPipelines();
301 void destroyDescriptors();
302 void destroyTextures();
303 };
304
306
307} // namespace mxvk
Loads OBJ/MXMOD meshes and uploads them to Vulkan buffers.
Convenience wrapper that owns mesh, textures, descriptors, and pipeline state.
void setAlphaBlending(bool enabled)
Enable or disable alpha blending for this model pipeline.
void setBackfaceCulling(bool enabled)
Enable or disable backface culling for this model pipeline.
void updateFragmentUBO(uint32_t imageIndex, const ModelFragmentUniforms &uniforms)
Update extended fragment uniforms for one swapchain image.
void updateUBO(uint32_t imageIndex, const UniformBufferObject &ubo)
Update one per-frame UBO payload.
float modelRenderScale() const
Access the computed render scale used for normalization.
void load(VK_Window *window, const std::string &modelPath, const std::string &textureManifestPath, const std::string &textureBasePath, float scale=1.0f)
Load mesh/texture resources and build Vulkan state.
~VKAbstractModel()=default
VKAbstractModel & operator=(const VKAbstractModel &)=delete
void setShaders(VK_Window *window, const std::string &vertSpv, const std::string &fragSpv)
Configure custom shader paths and rebuild pipelines.
bool isLoaded() const
True once the model has been uploaded to GPU buffers.
VKAbstractModel(VKAbstractModel &&)=delete
void cleanup(VK_Window *window)
Destroy all owned Vulkan resources.
VKAbstractModel & operator=(VKAbstractModel &&)=delete
glm::vec3 modelCenterOffset() const
Access the computed center offset used for normalization.
glm::vec3 modelAxisExtent() const
Per-axis extent (max - min) of the source mesh's bounding box.
const MXModel & model() const
Access the underlying mesh object.
void resize(VK_Window *window)
Rebuild swapchain-dependent resources after resize.
void renderWithPushConstants(VkCommandBuffer cmd, uint32_t imageIndex, size_t textureIndex, const UniformBufferObject &ubo, bool wireframe=false)
Record one draw using push constants for per-draw transforms and an explicit texture slot.
void render(VkCommandBuffer cmd, uint32_t imageIndex, bool wireframe=false) const
Record draw commands for this model.
void enableExtendedFragmentUniforms()
Use binding 1 for fragment uniforms and binding 2 for model transforms.
bool updatePrimaryTexture(const void *pixels, int width, int height, int pitch=0)
Upload raw RGBA pixels into the primary model texture.
VKAbstractModel(const VKAbstractModel &)=delete
void setFragmentPushConstants(const ModelFragmentPushConstants &constants)
Set sprite-compatible push constants used by custom fragment shaders.
Main Vulkan window wrapper for MXVK.
Definition mxvk.hpp:37
Vulkan mesh loader and GPU buffer manager for MXVK.
Utilities for loading and saving PNG images.
Definition mxvk.hpp:30
VKAbstractModel VK_AbstractModel
Sprite-compatible fragment parameters for UV-based model effects.
Extended shader-viewer uniforms available to fragment shaders at binding 1.
Default transform UBO payload for model shaders.