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 Namespace Reference

Utilities for loading and saving PNG images. More...

Namespaces

namespace  anonymous_namespace{mxvk.cpp}
namespace  anonymous_namespace{mxvk_abstract_model.cpp}
namespace  anonymous_namespace{mxvk_ff_capture.cpp}
namespace  anonymous_namespace{mxvk_model.cpp}
namespace  anonymous_namespace{mxvk_resource.cpp}
namespace  detail

Classes

struct  BufferResource
 Owned Vulkan buffer allocation with optional persistent host mapping. More...
struct  CachedTexture
 GPU texture resources cached for a rendered text string. More...
struct  CacheKey
 Cache key combining text content and colour. More...
struct  CacheKeyHash
 Hash functor for CacheKey. More...
class  Camera
 Camera and projection data for the simple software 3D pipeline. More...
struct  CyType
 Cylindrical coordinate. More...
class  Exception
class  Font
 Small RAII wrapper for an SDL_ttf font handle. More...
class  Mat1D
 Two-element column-vector storage used by 2x2 linear solves. More...
class  Mat1x3D
 Three-element column-vector storage used by 3x3 linear solves. More...
class  Mat1x4D
 Four-element column-vector storage. More...
class  Mat2D
 Two-by-two matrix with arithmetic, determinant, inverse, and solve helpers. More...
class  Mat3D
 Three-by-three matrix with multiplication, vector transform, inverse, and solve helpers. More...
class  Mat4D
 Four-by-four homogeneous transform matrix. More...
class  Mat4x3D
 Four-by-three matrix storage. More...
struct  ModelFragmentPushConstants
 Sprite-compatible fragment parameters for UV-based model effects. More...
struct  ModelFragmentUniforms
 Extended shader-viewer uniforms available to fragment shaders at binding 1. More...
struct  MXMaterial
 Parsed subset of Wavefront MTL material fields. More...
class  MXModel
 Loads OBJ/MXMOD meshes and uploads them to Vulkan buffers. More...
class  mxObject
 Simple mesh object loaded from PLG-style indexed triangle data. More...
struct  OBJMaterial
 Wavefront material data used by the software rasterizer. More...
struct  paramLine2D
 Parametric 2D line segment represented by a start point, end point, and direction. More...
struct  paramLine3D
 Parametric 3D line segment represented by a start point, end point, and direction. More...
class  PipeLine
 Clipped software rasterization pipeline for lines and filled triangles. More...
struct  Plane3D
 Plane represented by a point and a normal vector. More...
struct  PointSpriteVertex
 Vertex layout consumed by VK_PointSpriteBatch. More...
struct  Polar
 2D polar coordinate. More...
class  QuatType
 Quaternion used for 3D rotations. More...
class  RenderList
 Flat list of triangles prepared for transformation and rasterization. More...
struct  SDLRendererPixelPlotter
 Pixel plotter adapter that writes packed MXVK colors to an SDL renderer. More...
struct  SpType
 Spherical coordinate. More...
struct  SubMesh
 One indexed sub-range that can reference a dedicated texture slot. More...
struct  TextureResource
 Owned sampled 2D texture resources. More...
struct  Triangle
 Triangle primitive used by the simple software rendering pipeline. More...
struct  UniformBufferObject
 Default transform UBO payload for model shaders. More...
class  vec2D
 Two-dimensional float vector with common arithmetic helpers. More...
class  vec3D
 Three-dimensional float vector with arithmetic, dot, and cross-product helpers. More...
class  vec4D
 Four-dimensional float vector used for homogeneous 3D coordinates. More...
class  VK_Capture
 Vulkan OpenCV video capture source. More...
class  VK_Config
 Parses and manages an INI-style configuration file. More...
class  VK_ConfigItem
 A single key/value pair read from a configuration file. More...
class  VK_Console
 Lightweight command console renderer for mxvk::VK_Window. More...
class  VK_Controller
 RAII wrapper for SDL_Gamepad (standard layout mapping). More...
class  VK_FF_Capture
 FFmpeg-backed video-file capture source. More...
class  VK_IOWindow
class  VK_Joystick
 RAII wrapper for a raw SDL_Joystick device. More...
class  VK_Mixer
 SDL3_mixer-based audio manager. More...
class  VK_PointSpriteBatch
 Reusable Vulkan point-list renderer for textured particle effects. More...
class  VK_Sprite
class  VK_Sprite3D
 Depth-tested 3D billboard sprite batch. More...
class  VK_Stencil
 Owns a stencil attachment and two fullscreen pipelines for stencil-masked rendering. More...
class  VK_Text
class  VK_Window
 Main Vulkan window wrapper for MXVK. More...
class  VKAbstractModel
 Convenience wrapper that owns mesh, textures, descriptors, and pipeline state. More...
struct  VKSpritePixelPlotter
 Pixel plotter adapter that draws square pixels into a VK_Sprite. More...
struct  VKVertex
 Vertex payload consumed by MXVK model shaders. More...
struct  VKVertexHash
 Hash functor for VKVertex. More...
struct  VulkanContext
 Minimal Vulkan handles required by MXVK resource helpers. More...
class  Wrapper
 A nullable smart wrapper around a raw pointer. More...

Concepts

concept  WrapType
 Constrains Wrapper<T> to pointer types only.

Typedefs

using ConfigFile = VK_Config
using Console = VK_Console
using Controller = VK_Controller
using Item = VK_ConfigItem
using Joystick = VK_Joystick
using Mixer = VK_Mixer
using MXCOLOR = std::uint32_t
 Packed 32-bit color in ARGB byte order.
using VK_AbstractModel = VKAbstractModel

Enumerations

enum  { MX_ACTIVE = 0x1 , MX_VISIBLE = 0x2 , MX_BACKFACE = 0x4 , MX_CULLED = 0x8 }
 Object and polygon state bit flags. More...
enum  { MX_ACTIVE = 0x1 , MX_VISIBLE = 0x2 , MX_BACKFACE = 0x4 , MX_CULLED = 0x8 }
 Object and polygon state bit flags. More...

Functions

VkCommandBuffer begin_one_time_commands (const VulkanContext &context)
 Allocate and begin a primary one-time command buffer.
std::array< float, 361 > build_cos_table ()
std::array< float, 361 > build_sin_table ()
void BuildTables ()
 Rebuild the sine and cosine lookup tables.
constexpr std::uint8_t color_a (MXCOLOR color)
 Extract the alpha component from a packed ARGB color.
constexpr std::uint8_t color_b (MXCOLOR color)
 Extract the blue component from a packed ARGB color.
constexpr std::uint8_t color_g (MXCOLOR color)
 Extract the green component from a packed ARGB color.
constexpr std::uint8_t color_r (MXCOLOR color)
 Extract the red component from a packed ARGB color.
void copy_buffer (const VulkanContext &context, VkBuffer source, VkBuffer destination, VkDeviceSize size)
 Copy one buffer into another with a one-shot Vulkan 1.3 copy command.
void copy_buffer_to_image (VkCommandBuffer command_buffer, VkBuffer buffer, VkImage image, uint32_t width, uint32_t height)
 Record a Vulkan 1.3 vkCmdCopyBufferToImage2 copy for a full 2D image.
void create_buffer (const VulkanContext &context, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, BufferResource &buffer)
 Create and bind a Vulkan buffer allocation.
void create_image (const VulkanContext &context, uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage &image, VkDeviceMemory &memory)
 Create a 2D VkImage and allocate/bind its memory.
VkImageView create_image_view (VkDevice device, VkImage image, VkFormat format, VkImageAspectFlags aspect)
 Create a 2D image view for an image.
VkShaderModule create_shader_module (VkDevice device, const std::vector< char > &spv_bytes)
 Create a shader module from SPIR-V bytecode.
void create_texture_from_png (const VulkanContext &context, const std::string &path, TextureResource &texture, VkFormat format=VK_FORMAT_R8G8B8A8_UNORM)
 Load a PNG and upload it into a sampled 2D texture.
void create_texture_from_surface (const VulkanContext &context, SDL_Surface *surface, TextureResource &texture, VkFormat format=VK_FORMAT_R8G8B8A8_UNORM)
 Upload an SDL surface into a sampled 2D texture.
bool defaultEnableScreenshot ()
bool & defaultEnableScreenshotStorage ()
const std::string & defaultExecutableName ()
std::string & defaultExecutableNameStorage ()
float deg2rad (float ang)
 Convert degrees to radians.
void destroy_buffer (VkDevice device, BufferResource &buffer)
 Unmap and destroy a BufferResource.
void destroy_texture (VkDevice device, TextureResource &texture)
 Destroy every Vulkan handle owned by a TextureResource.
template<typename PlotPixel>
void draw_filled_triangle (const vec2D &p0, const vec2D &p1, const vec2D &p2, MXCOLOR color, PlotPixel &&plot_pixel)
 Rasterize a filled triangle by testing pixels against edge functions.
void draw_filled_triangle (SDL_Renderer *renderer, const vec2D &p0, const vec2D &p1, const vec2D &p2, MXCOLOR color)
 Draw a filled triangle directly to an SDL renderer.
void draw_filled_triangle (VK_Sprite &sprite, const vec2D &p0, const vec2D &p1, const vec2D &p2, MXCOLOR color, int pixel_size=1)
 Draw a filled triangle directly to a VK_Sprite with optional square pixel size.
template<typename DrawSpan>
void draw_filled_triangle_spans (vec2D p0, vec2D p1, vec2D p2, MXCOLOR color, DrawSpan &&draw_span)
template<typename DrawSpan>
void draw_filled_triangle_spans_clipped (vec2D p0, vec2D p1, vec2D p2, int clip_min_y, int clip_max_y, MXCOLOR color, DrawSpan &&draw_span)
 Rasterize a filled triangle as horizontal spans.
template<typename PlotPixel>
void draw_line (int x0, int y0, int x1, int y1, MXCOLOR color, PlotPixel &&plot_pixel)
 Draw a line with Bresenham-style integer stepping.
void draw_line (SDL_Renderer *renderer, int x0, int y0, int x1, int y1, MXCOLOR color)
 Draw a line directly to an SDL renderer.
void draw_line (VK_Sprite &sprite, int x0, int y0, int x1, int y1, MXCOLOR color, int pixel_size=1)
 Draw a line directly to a VK_Sprite with optional square pixel size.
float edge_function (const vec2D &a, const vec2D &b, const vec2D &p)
 Compute the signed edge function value for point p relative to edge a-b.
void end_one_time_commands (const VulkanContext &context, VkCommandBuffer command_buffer)
 End, submit with vkQueueSubmit2, wait idle, and free a one-time command buffer.
float fast_cosf (float theta_degrees)
 Approximate cosine using the degree lookup table with linear interpolation.
float fast_sinf (float theta_degrees)
 Approximate sine using the degree lookup table with linear interpolation.
uint32_t find_memory_type (VkPhysicalDevice physical_device, uint32_t type_filter, VkMemoryPropertyFlags properties)
 Find a memory type satisfying a Vulkan memory type mask and property set.
bool HasPngExtension (const char *file)
std::vector< char > load_spv (const std::string &path)
 Load a SPIR-V file from disk.
SDL_Surface * LoadPNG (const char *file)
 Load a PNG file into an SDL_Surface.
void map_buffer (VkDevice device, BufferResource &buffer)
 Persistently map a host-visible buffer allocation.
constexpr MXCOLOR MXVK_RGB (int r, int g, int b)
 Build an opaque ARGB color from red, green, and blue components.
std::ostream & operator<< (std::ostream &out, const vec2D &v)
 Write a 2D vector to a stream using vec2D::Print().
std::ostream & operator<< (std::ostream &out, const vec3D &v)
 Write a 3D vector to a stream using vec3D::Print().
std::ostream & operator<< (std::ostream &out, const vec4D &v)
 Write a 4D vector to a stream using vec4D::Print().
std::istream & operator>> (std::istream &in, vec2D &v)
 Read a 2D vector from a stream as two scalar coordinates.
std::istream & operator>> (std::istream &in, vec3D &v)
 Read a 3D vector from a stream as three scalar coordinates.
std::istream & operator>> (std::istream &in, vec4D &v)
 Read a 4D vector from a stream as four scalar coordinates.
float rad2deg (float rad)
 Convert radians to degrees.
int rrand (int x, int y)
 Return a pseudo-random integer in the inclusive range between two bounds.
bool SavePNG (SDL_Texture *texture, SDL_Renderer *renderer, const char *filename)
 Save an SDL_Texture to a PNG file.
bool SavePNG_RGBA (const char *filename, void *buffer, int w, int h)
 Save a raw RGBA pixel buffer to a PNG file.
bool SavePNG_RGBA16 (const char *filename, const void *buffer, int w, int h)
 Save a raw 16-bit RGBA pixel buffer to a PNG file.
bool SaveRawBytes (const char *filename, const void *buffer, size_t w, size_t h, size_t bpp)
 Save raw data to a file.
void setDefaultEnableScreenshot (bool enabled)
void setDefaultExecutableName (const std::string &name)
MXCOLOR shade_color (MXCOLOR color, float intensity)
 Scale the RGB channels of a color while preserving alpha.
void transition_image_layout (VkCommandBuffer command_buffer, VkImage image, VkImageLayout old_layout, VkImageLayout new_layout, VkImageAspectFlags aspect=VK_IMAGE_ASPECT_COLOR_BIT)
 Record a Vulkan 1.3 synchronization2 image layout transition.
void unmap_buffer (VkDevice device, BufferResource &buffer)
 Unmap a BufferResource if it is currently mapped.
bool WriteRgbaPng (const char *filename, const std::uint8_t *pixels, const int width, const int height, const int pitch, const int bit_depth, const bool swap_16bit_endianness)

Variables

std::array< float, 361 > cos_look = build_cos_table()
 Cosine lookup table with one entry per degree from 0 through 360.
constexpr float EPSILON = 1.0e-5f
 Default tolerance used for floating-point singularity and zero-length checks.
constexpr float PI = 3.14159265358979323846f
 Mathematical constant pi as a single-precision value.
std::array< float, 361 > sin_look = build_sin_table()
 Sine lookup table with one entry per degree from 0 through 360.

Detailed Description

Utilities for loading and saving PNG images.

Typedef Documentation

◆ ConfigFile

Definition at line 99 of file mxvk_cfg.hpp.

◆ Console

Definition at line 183 of file mxvk_console.hpp.

◆ Controller

Definition at line 209 of file mxvk_controller.hpp.

◆ Item

Definition at line 98 of file mxvk_cfg.hpp.

◆ Joystick

Definition at line 210 of file mxvk_controller.hpp.

◆ Mixer

Definition at line 110 of file mxvk_sound.hpp.

◆ MXCOLOR

using mxvk::MXCOLOR = std::uint32_t

Packed 32-bit color in ARGB byte order.

Definition at line 40 of file mxvk_math.h.

◆ VK_AbstractModel

Enumeration Type Documentation

◆ anonymous enum

anonymous enum

Object and polygon state bit flags.

Enumerator
MX_ACTIVE 

Active object or polygon.

MX_VISIBLE 

Visible object or polygon.

MX_BACKFACE 

Polygon is marked as a backface.

MX_CULLED 

Object or polygon is culled.

Definition at line 1356 of file mxvk_math.h.

1356 {
1357 /// Active object or polygon.
1358 MX_ACTIVE = 0x1,
1359
1360 /// Visible object or polygon.
1361 MX_VISIBLE = 0x2,
1362
1363 /// Polygon is marked as a backface.
1364 MX_BACKFACE = 0x4,
1365
1366 /// Object or polygon is culled.
1367 MX_CULLED = 0x8
1368 };
@ MX_ACTIVE
Active object or polygon.
Definition mxvk_math.h:1358
@ MX_CULLED
Object or polygon is culled.
Definition mxvk_math.h:1367
@ MX_BACKFACE
Polygon is marked as a backface.
Definition mxvk_math.h:1364
@ MX_VISIBLE
Visible object or polygon.
Definition mxvk_math.h:1361

◆ anonymous enum

anonymous enum

Object and polygon state bit flags.

Enumerator
MX_ACTIVE 

Active object or polygon.

MX_VISIBLE 

Visible object or polygon.

MX_BACKFACE 

Polygon is marked as a backface.

MX_CULLED 

Object or polygon is culled.

Definition at line 1356 of file mxvk_math_eigen.hpp.

1356 {
1357 /// Active object or polygon.
1358 MX_ACTIVE = 0x1,
1359
1360 /// Visible object or polygon.
1361 MX_VISIBLE = 0x2,
1362
1363 /// Polygon is marked as a backface.
1364 MX_BACKFACE = 0x4,
1365
1366 /// Object or polygon is culled.
1367 MX_CULLED = 0x8
1368 };

Function Documentation

◆ begin_one_time_commands()

VkCommandBuffer mxvk::begin_one_time_commands ( const VulkanContext & context)
nodiscard

Allocate and begin a primary one-time command buffer.

Parameters
contextValid upload context with device, queue, and command pool.
Returns
Recording command buffer.
Exceptions
mxvk::Exceptionif allocation or begin fails.

Definition at line 229 of file mxvk_resource.cpp.

229 {
230 validate_upload_context(context);
231 VkCommandBufferAllocateInfo alloc_info{};
232 alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
233 alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
234 alloc_info.commandPool = context.command_pool;
235 alloc_info.commandBufferCount = 1;
236
237 VkCommandBuffer command_buffer = VK_NULL_HANDLE;
238 if (vkAllocateCommandBuffers(context.device, &alloc_info, &command_buffer) != VK_SUCCESS) {
239 throw mxvk::Exception("failed to allocate one-time command buffer");
240 }
241
242 VkCommandBufferBeginInfo begin_info{};
243 begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
244 begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
245 if (vkBeginCommandBuffer(command_buffer, &begin_info) != VK_SUCCESS) {
246 vkFreeCommandBuffers(context.device, context.command_pool, 1, &command_buffer);
247 throw mxvk::Exception("failed to begin one-time command buffer");
248 }
249
250 return command_buffer;
251 }
VkDevice device
Logical device used to create and destroy resources.
VkCommandPool command_pool
Command pool used for transient upload command buffers.

◆ build_cos_table()

std::array< float, 361 > mxvk::build_cos_table ( )
inline

Definition at line 98 of file mxvk_math.h.

98 {
99 std::array<float, 361> values{};
100 for (int ang = 0; ang <= 360; ++ang) {
101 values[static_cast<std::size_t>(ang)] = std::cos(static_cast<float>(ang) * PI / 180.0f);
102 }
103 return values;
104 }
constexpr float PI
Mathematical constant pi as a single-precision value.
Definition mxvk_math.h:34

◆ build_sin_table()

std::array< float, 361 > mxvk::build_sin_table ( )
inline

Definition at line 90 of file mxvk_math.h.

90 {
91 std::array<float, 361> values{};
92 for (int ang = 0; ang <= 360; ++ang) {
93 values[static_cast<std::size_t>(ang)] = std::sin(static_cast<float>(ang) * PI / 180.0f);
94 }
95 return values;
96 }

◆ BuildTables()

void mxvk::BuildTables ( )
inline

Rebuild the sine and cosine lookup tables.

Definition at line 113 of file mxvk_math.h.

113 {
114 std::cout << "mxvk_math: building trigonometric lookup tables\n";
115 for (int ang = 0; ang <= 360; ++ang) {
116 const float theta = static_cast<float>(ang) * PI / 180.0f;
117 cos_look[static_cast<std::size_t>(ang)] = std::cos(theta);
118 sin_look[static_cast<std::size_t>(ang)] = std::sin(theta);
119 }
120 std::cout << "mxvk_math: trigonometric lookup tables ready (361 entries)\n";
121 }
std::array< float, 361 > cos_look
Cosine lookup table with one entry per degree from 0 through 360.
Definition mxvk_math.h:110
std::array< float, 361 > sin_look
Sine lookup table with one entry per degree from 0 through 360.
Definition mxvk_math.h:107

◆ color_a()

std::uint8_t mxvk::color_a ( MXCOLOR color)
inlinenodiscardconstexpr

Extract the alpha component from a packed ARGB color.

Definition at line 69 of file mxvk_math.h.

69 {
70 return static_cast<std::uint8_t>((color >> 24u) & 0xFFu);
71 }

◆ color_b()

std::uint8_t mxvk::color_b ( MXCOLOR color)
inlinenodiscardconstexpr

Extract the blue component from a packed ARGB color.

Definition at line 64 of file mxvk_math.h.

64 {
65 return static_cast<std::uint8_t>(color & 0xFFu);
66 }

◆ color_g()

std::uint8_t mxvk::color_g ( MXCOLOR color)
inlinenodiscardconstexpr

Extract the green component from a packed ARGB color.

Definition at line 59 of file mxvk_math.h.

59 {
60 return static_cast<std::uint8_t>((color >> 8u) & 0xFFu);
61 }

◆ color_r()

std::uint8_t mxvk::color_r ( MXCOLOR color)
inlinenodiscardconstexpr

Extract the red component from a packed ARGB color.

Definition at line 54 of file mxvk_math.h.

54 {
55 return static_cast<std::uint8_t>((color >> 16u) & 0xFFu);
56 }

◆ copy_buffer()

void mxvk::copy_buffer ( const VulkanContext & context,
VkBuffer source,
VkBuffer destination,
VkDeviceSize size )

Copy one buffer into another with a one-shot Vulkan 1.3 copy command.

Parameters
contextValid upload context.
sourceSource buffer.
destinationDestination buffer.
sizeBytes to copy.
Exceptions
mxvk::Exceptionif command allocation, submission, or completion fails.

Definition at line 282 of file mxvk_resource.cpp.

285 {
286 if (size == 0) {
287 return;
288 }
289
290 VkCommandBuffer command_buffer = begin_one_time_commands(context);
291
292 VkBufferCopy2 copy_region{};
293 copy_region.sType = VK_STRUCTURE_TYPE_BUFFER_COPY_2;
294 copy_region.size = size;
295
296 VkCopyBufferInfo2 copy_info{};
297 copy_info.sType = VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2;
298 copy_info.srcBuffer = source;
299 copy_info.dstBuffer = destination;
300 copy_info.regionCount = 1;
301 copy_info.pRegions = &copy_region;
302 vkCmdCopyBuffer2(command_buffer, &copy_info);
303
304 end_one_time_commands(context, command_buffer);
305 }
VkCommandBuffer begin_one_time_commands(const VulkanContext &context)
Allocate and begin a primary one-time command buffer.
void end_one_time_commands(const VulkanContext &context, VkCommandBuffer command_buffer)
End, submit with vkQueueSubmit2, wait idle, and free a one-time command buffer.

◆ copy_buffer_to_image()

void mxvk::copy_buffer_to_image ( VkCommandBuffer command_buffer,
VkBuffer buffer,
VkImage image,
uint32_t width,
uint32_t height )

Record a Vulkan 1.3 vkCmdCopyBufferToImage2 copy for a full 2D image.

Parameters
command_bufferCommand buffer in recording state.
bufferSource buffer containing tightly packed RGBA pixels.
imageDestination image in VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL.
widthCopy width in pixels.
heightCopy height in pixels.

Definition at line 347 of file mxvk_resource.cpp.

351 {
352 VkBufferImageCopy2 region{};
353 region.sType = VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2;
354 region.bufferOffset = 0;
355 region.bufferRowLength = 0;
356 region.bufferImageHeight = 0;
357 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
358 region.imageSubresource.mipLevel = 0;
359 region.imageSubresource.baseArrayLayer = 0;
360 region.imageSubresource.layerCount = 1;
361 region.imageOffset = {0, 0, 0};
362 region.imageExtent = {width, height, 1};
363
364 VkCopyBufferToImageInfo2 copy_info{};
365 copy_info.sType = VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2;
366 copy_info.srcBuffer = buffer;
367 copy_info.dstImage = image;
368 copy_info.dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
369 copy_info.regionCount = 1;
370 copy_info.pRegions = &region;
371 vkCmdCopyBufferToImage2(command_buffer, &copy_info);
372 }

◆ create_buffer()

void mxvk::create_buffer ( const VulkanContext & context,
VkDeviceSize size,
VkBufferUsageFlags usage,
VkMemoryPropertyFlags properties,
BufferResource & buffer )

Create and bind a Vulkan buffer allocation.

Parameters
contextValid Vulkan device and physical device handles.
sizeBuffer size in bytes.
usageVkBufferUsageFlagBits describing intended buffer use.
propertiesRequired memory properties.
bufferOutput buffer resource; any existing contents are destroyed first.
Exceptions
mxvk::Exceptionon invalid input or Vulkan allocation failure.

Definition at line 67 of file mxvk_resource.cpp.

71 {
72 validate_context(context);
73 if (size == 0) {
74 throw mxvk::Exception("create_buffer requires a non-zero size");
75 }
76 destroy_buffer(context.device, buffer);
77
78 VkBufferCreateInfo buffer_info{};
79 buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
80 buffer_info.size = size;
81 buffer_info.usage = usage;
82 buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
83 if (vkCreateBuffer(context.device, &buffer_info, nullptr, &buffer.buffer) != VK_SUCCESS) {
84 throw mxvk::Exception("failed to create Vulkan buffer");
85 }
86
87 VkMemoryRequirements requirements{};
88 vkGetBufferMemoryRequirements(context.device, buffer.buffer, &requirements);
89
90 VkMemoryAllocateInfo allocation{};
91 allocation.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
92 allocation.allocationSize = requirements.size;
93 try {
94 allocation.memoryTypeIndex = find_memory_type(context.physical_device, requirements.memoryTypeBits, properties);
95 if (vkAllocateMemory(context.device, &allocation, nullptr, &buffer.memory) != VK_SUCCESS) {
96 throw mxvk::Exception("failed to allocate Vulkan buffer memory");
97 }
98 if (vkBindBufferMemory(context.device, buffer.buffer, buffer.memory, 0) != VK_SUCCESS) {
99 throw mxvk::Exception("failed to bind Vulkan buffer memory");
100 }
101 } catch (...) {
102 destroy_buffer(context.device, buffer);
103 throw;
104 }
105 buffer.size = size;
106 }
uint32_t find_memory_type(VkPhysicalDevice physical_device, uint32_t type_filter, VkMemoryPropertyFlags properties)
Find a memory type satisfying a Vulkan memory type mask and property set.
void destroy_buffer(VkDevice device, BufferResource &buffer)
Unmap and destroy a BufferResource.
VkDeviceMemory memory
Device memory bound to buffer.
VkBuffer buffer
Vulkan buffer handle.
VkDeviceSize size
Requested buffer size in bytes.
VkPhysicalDevice physical_device
Physical device used for memory type queries.

◆ create_image()

void mxvk::create_image ( const VulkanContext & context,
uint32_t width,
uint32_t height,
VkFormat format,
VkImageTiling tiling,
VkImageUsageFlags usage,
VkMemoryPropertyFlags properties,
VkImage & image,
VkDeviceMemory & memory )

Create a 2D VkImage and allocate/bind its memory.

Parameters
contextValid Vulkan device and physical device handles.
widthImage width in pixels.
heightImage height in pixels.
formatImage format.
tilingImage tiling mode.
usageVkImageUsageFlagBits describing intended image use.
propertiesRequired memory properties.
imageOutput image handle.
memoryOutput memory handle bound to image.
Exceptions
mxvk::Exceptionon invalid dimensions or Vulkan allocation failure.

Definition at line 142 of file mxvk_resource.cpp.

150 {
151 validate_context(context);
152 if (width == 0 || height == 0) {
153 throw mxvk::Exception("create_image requires non-zero dimensions");
154 }
155 if (image != VK_NULL_HANDLE) {
156 vkDestroyImage(context.device, image, nullptr);
157 image = VK_NULL_HANDLE;
158 }
159 if (memory != VK_NULL_HANDLE) {
160 vkFreeMemory(context.device, memory, nullptr);
161 memory = VK_NULL_HANDLE;
162 }
163
164 VkImageCreateInfo image_info{};
165 image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
166 image_info.imageType = VK_IMAGE_TYPE_2D;
167 image_info.extent = {width, height, 1};
168 image_info.mipLevels = 1;
169 image_info.arrayLayers = 1;
170 image_info.format = format;
171 image_info.tiling = tiling;
172 image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
173 image_info.usage = usage;
174 image_info.samples = VK_SAMPLE_COUNT_1_BIT;
175 image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
176 if (vkCreateImage(context.device, &image_info, nullptr, &image) != VK_SUCCESS) {
177 throw mxvk::Exception("failed to create Vulkan image");
178 }
179
180 VkMemoryRequirements requirements{};
181 vkGetImageMemoryRequirements(context.device, image, &requirements);
182
183 VkMemoryAllocateInfo allocation{};
184 allocation.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
185 allocation.allocationSize = requirements.size;
186 try {
187 allocation.memoryTypeIndex = find_memory_type(context.physical_device, requirements.memoryTypeBits, properties);
188 if (vkAllocateMemory(context.device, &allocation, nullptr, &memory) != VK_SUCCESS) {
189 throw mxvk::Exception("failed to allocate Vulkan image memory");
190 }
191 if (vkBindImageMemory(context.device, image, memory, 0) != VK_SUCCESS) {
192 throw mxvk::Exception("failed to bind Vulkan image memory");
193 }
194 } catch (...) {
195 if (memory != VK_NULL_HANDLE) {
196 vkFreeMemory(context.device, memory, nullptr);
197 memory = VK_NULL_HANDLE;
198 }
199 if (image != VK_NULL_HANDLE) {
200 vkDestroyImage(context.device, image, nullptr);
201 image = VK_NULL_HANDLE;
202 }
203 throw;
204 }
205 }

◆ create_image_view()

VkImageView mxvk::create_image_view ( VkDevice device,
VkImage image,
VkFormat format,
VkImageAspectFlags aspect )
nodiscard

Create a 2D image view for an image.

Parameters
deviceLogical device.
imageImage to view.
formatView format.
aspectImage aspect mask, usually VK_IMAGE_ASPECT_COLOR_BIT.
Returns
Created image view handle.
Exceptions
mxvk::Exceptionif view creation fails.

Definition at line 207 of file mxvk_resource.cpp.

210 {
211 VkImageViewCreateInfo view_info{};
212 view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
213 view_info.image = image;
214 view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
215 view_info.format = format;
216 view_info.subresourceRange.aspectMask = aspect;
217 view_info.subresourceRange.baseMipLevel = 0;
218 view_info.subresourceRange.levelCount = 1;
219 view_info.subresourceRange.baseArrayLayer = 0;
220 view_info.subresourceRange.layerCount = 1;
221
222 VkImageView image_view = VK_NULL_HANDLE;
223 if (vkCreateImageView(device, &view_info, nullptr, &image_view) != VK_SUCCESS) {
224 throw mxvk::Exception("failed to create Vulkan image view");
225 }
226 return image_view;
227 }

◆ create_shader_module()

VkShaderModule mxvk::create_shader_module ( VkDevice device,
const std::vector< char > & spv_bytes )
nodiscard

Create a shader module from SPIR-V bytecode.

Parameters
deviceLogical Vulkan device used to create the module.
spv_bytesSPIR-V bytecode payload.
Returns
Created shader module handle.
Exceptions
mxvk::Exceptionwhen inputs are invalid or module creation fails.

Definition at line 30 of file mxvk_shader_module.cpp.

30 {
31 if (device == VK_NULL_HANDLE) {
32 throw mxvk::Exception("Cannot create shader module with a null device");
33 }
34 if (spv_bytes.empty() || (spv_bytes.size() % 4U) != 0U) {
35 throw mxvk::Exception("Invalid SPIR-V shader data");
36 }
37
38 VkShaderModuleCreateInfo create_info{};
39 create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
40 create_info.codeSize = spv_bytes.size();
41 create_info.pCode = reinterpret_cast<const uint32_t *>(spv_bytes.data());
42
43 VkShaderModule module = VK_NULL_HANDLE;
44 if (vkCreateShaderModule(device, &create_info, nullptr, &module) != VK_SUCCESS) {
45 throw mxvk::Exception("Failed to create shader module");
46 }
47
48 return module;
49 }

◆ create_texture_from_png()

void mxvk::create_texture_from_png ( const VulkanContext & context,
const std::string & path,
TextureResource & texture,
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM )

Load a PNG and upload it into a sampled 2D texture.

Parameters
contextValid upload context.
pathPNG path.
textureOutput texture resource; any existing contents are destroyed first.
formatDestination image format. Defaults to VK_FORMAT_R8G8B8A8_UNORM.
Exceptions
mxvk::Exceptionif loading or upload fails.

Definition at line 437 of file mxvk_resource.cpp.

440 {
441 std::unique_ptr<SDL_Surface, decltype(&SDL_DestroySurface)> surface(mxvk::LoadPNG(path.c_str()), SDL_DestroySurface);
442 if (surface == nullptr) {
443 throw mxvk::Exception(std::format("failed to load texture PNG: {}", path));
444 }
445 create_texture_from_surface(context, surface.get(), texture, format);
446 }
void create_texture_from_surface(const VulkanContext &context, SDL_Surface *surface, TextureResource &texture, VkFormat format=VK_FORMAT_R8G8B8A8_UNORM)
Upload an SDL surface into a sampled 2D texture.
SDL_Surface * LoadPNG(const char *file)
Load a PNG file into an SDL_Surface.
Definition mxvk_png.cpp:103

◆ create_texture_from_surface()

void mxvk::create_texture_from_surface ( const VulkanContext & context,
SDL_Surface * surface,
TextureResource & texture,
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM )

Upload an SDL surface into a sampled 2D texture.

Parameters
contextValid upload context.
surfaceSource surface. Pixels are copied immediately.
textureOutput texture resource; any existing contents are destroyed first.
formatDestination image format. Defaults to VK_FORMAT_R8G8B8A8_UNORM.

The source surface is copied row-by-row into a tight staging buffer to tolerate SDL pitch padding. The surface is expected to contain 4 bytes per pixel, as produced by MXVK's PNG loader.

Exceptions
mxvk::Exceptionon invalid input, allocation failure, or upload failure.

Definition at line 374 of file mxvk_resource.cpp.

377 {
378 validate_upload_context(context);
379 if (surface == nullptr || surface->pixels == nullptr || surface->w <= 0 || surface->h <= 0) {
380 throw mxvk::Exception("create_texture_from_surface requires a valid SDL surface");
381 }
382 destroy_texture(context.device, texture);
383
384 const uint32_t width = static_cast<uint32_t>(surface->w);
385 const uint32_t height = static_cast<uint32_t>(surface->h);
386 const VkDeviceSize image_size = static_cast<VkDeviceSize>(width) * static_cast<VkDeviceSize>(height) * 4U;
387 std::vector<std::byte> tight_pixels(static_cast<size_t>(image_size));
388
389 // SDL surfaces may have padded rows; Vulkan buffer-image copies use tight rows here.
390 const auto *src = static_cast<const std::byte *>(surface->pixels);
391 auto *dst = tight_pixels.data();
392 const size_t tight_row_bytes = static_cast<size_t>(width) * 4U;
393 for (uint32_t y = 0; y < height; ++y) {
394 std::memcpy(dst + y * tight_row_bytes, src + static_cast<size_t>(y) * static_cast<size_t>(surface->pitch), tight_row_bytes);
395 }
396
397 BufferResource staging{};
398 try {
399 create_buffer(context,
400 image_size,
401 VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
402 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
403 staging);
404 map_buffer(context.device, staging);
405 std::memcpy(staging.mapped, tight_pixels.data(), tight_pixels.size());
406 unmap_buffer(context.device, staging);
407
408 create_image(context,
409 width,
410 height,
411 format,
412 VK_IMAGE_TILING_OPTIMAL,
413 VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
414 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
415 texture.image,
416 texture.memory);
417
418 const VkCommandBuffer cmd = begin_one_time_commands(context);
419 transition_image_layout(cmd, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
420 copy_buffer_to_image(cmd, staging.buffer, texture.image, width, height);
421 transition_image_layout(cmd, texture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
422 end_one_time_commands(context, cmd);
423
424 destroy_buffer(context.device, staging);
425
426 texture.view = create_image_view(context.device, texture.image, format, VK_IMAGE_ASPECT_COLOR_BIT);
427 create_sampler(context.device, texture);
428 texture.width = width;
429 texture.height = height;
430 } catch (...) {
431 destroy_buffer(context.device, staging);
432 destroy_texture(context.device, texture);
433 throw;
434 }
435 }
void create_sampler(VkDevice device, TextureResource &texture)
void transition_image_layout(VkCommandBuffer command_buffer, VkImage image, VkImageLayout old_layout, VkImageLayout new_layout, VkImageAspectFlags aspect=VK_IMAGE_ASPECT_COLOR_BIT)
Record a Vulkan 1.3 synchronization2 image layout transition.
void create_image(const VulkanContext &context, uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage &image, VkDeviceMemory &memory)
Create a 2D VkImage and allocate/bind its memory.
VkImageView create_image_view(VkDevice device, VkImage image, VkFormat format, VkImageAspectFlags aspect)
Create a 2D image view for an image.
void unmap_buffer(VkDevice device, BufferResource &buffer)
Unmap a BufferResource if it is currently mapped.
void map_buffer(VkDevice device, BufferResource &buffer)
Persistently map a host-visible buffer allocation.
void create_buffer(const VulkanContext &context, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, BufferResource &buffer)
Create and bind a Vulkan buffer allocation.
void copy_buffer_to_image(VkCommandBuffer command_buffer, VkBuffer buffer, VkImage image, uint32_t width, uint32_t height)
Record a Vulkan 1.3 vkCmdCopyBufferToImage2 copy for a full 2D image.
void destroy_texture(VkDevice device, TextureResource &texture)
Destroy every Vulkan handle owned by a TextureResource.
Owned Vulkan buffer allocation with optional persistent host mapping.
uint32_t width
Texture width in pixels.
VkImage image
Optimal-tiled image containing the texture pixels.
VkImageView view
2D color image view used by descriptors.
uint32_t height
Texture height in pixels.
VkDeviceMemory memory
Device-local memory bound to image.

◆ defaultEnableScreenshot()

bool mxvk::defaultEnableScreenshot ( )
inlinenodiscard

Definition at line 15 of file mxvk_runtime_options.hpp.

15 {
17 }
bool & defaultEnableScreenshotStorage()

◆ defaultEnableScreenshotStorage()

bool & mxvk::defaultEnableScreenshotStorage ( )
inlinenodiscard

Definition at line 6 of file mxvk_runtime_options.hpp.

6 {
7 static bool enabled = false;
8 return enabled;
9 }

◆ defaultExecutableName()

const std::string & mxvk::defaultExecutableName ( )
inlinenodiscard

Definition at line 28 of file mxvk_runtime_options.hpp.

28 {
30 }
std::string & defaultExecutableNameStorage()

◆ defaultExecutableNameStorage()

std::string & mxvk::defaultExecutableNameStorage ( )
inlinenodiscard

Definition at line 19 of file mxvk_runtime_options.hpp.

19 {
20 static std::string name = "mxvk";
21 return name;
22 }

◆ deg2rad()

float mxvk::deg2rad ( float ang)
inlinenodiscard

Convert degrees to radians.

Definition at line 124 of file mxvk_math.h.

124 {
125 return ang * PI / 180.0f;
126 }

◆ destroy_buffer()

void mxvk::destroy_buffer ( VkDevice device,
BufferResource & buffer )

Unmap and destroy a BufferResource.

Parameters
deviceLogical device that owns the resource.
bufferResource to release and reset.

Definition at line 108 of file mxvk_resource.cpp.

108 {
109 if (device == VK_NULL_HANDLE) {
110 buffer = {};
111 return;
112 }
113 unmap_buffer(device, buffer);
114 if (buffer.buffer != VK_NULL_HANDLE) {
115 vkDestroyBuffer(device, buffer.buffer, nullptr);
116 }
117 if (buffer.memory != VK_NULL_HANDLE) {
118 vkFreeMemory(device, buffer.memory, nullptr);
119 }
120 buffer = {};
121 }

◆ destroy_texture()

void mxvk::destroy_texture ( VkDevice device,
TextureResource & texture )

Destroy every Vulkan handle owned by a TextureResource.

Parameters
deviceLogical device that owns the texture.
textureTexture resource to release and reset.

Definition at line 448 of file mxvk_resource.cpp.

448 {
449 if (device == VK_NULL_HANDLE) {
450 texture = {};
451 return;
452 }
453 if (texture.sampler != VK_NULL_HANDLE) {
454 vkDestroySampler(device, texture.sampler, nullptr);
455 }
456 if (texture.view != VK_NULL_HANDLE) {
457 vkDestroyImageView(device, texture.view, nullptr);
458 }
459 if (texture.image != VK_NULL_HANDLE) {
460 vkDestroyImage(device, texture.image, nullptr);
461 }
462 if (texture.memory != VK_NULL_HANDLE) {
463 vkFreeMemory(device, texture.memory, nullptr);
464 }
465 texture = {};
466 }
VkSampler sampler
Sampler configured for linear filtering and clamp-to-edge addressing.

◆ draw_filled_triangle() [1/3]

template<typename PlotPixel>
void mxvk::draw_filled_triangle ( const vec2D & p0,
const vec2D & p1,
const vec2D & p2,
MXCOLOR color,
PlotPixel && plot_pixel )

Rasterize a filled triangle by testing pixels against edge functions.

Template Parameters
PlotPixelCallable accepting (x, y, MXCOLOR).
Parameters
p0First triangle vertex in screen coordinates.
p1Second triangle vertex in screen coordinates.
p2Third triangle vertex in screen coordinates.
colorPacked ARGB color.
plot_pixelPixel plotting callable.

Definition at line 2141 of file mxvk_math.h.

2141 {
2142 const float area = edge_function(p0, p1, p2);
2143 if (std::fabs(area) <= EPSILON) {
2144 return;
2145 }
2146
2147 const int min_x = static_cast<int>(std::floor(std::min({p0.x, p1.x, p2.x})));
2148 const int max_x = static_cast<int>(std::ceil(std::max({p0.x, p1.x, p2.x})));
2149 const int min_y = static_cast<int>(std::floor(std::min({p0.y, p1.y, p2.y})));
2150 const int max_y = static_cast<int>(std::ceil(std::max({p0.y, p1.y, p2.y})));
2151
2152 for (int y = min_y; y <= max_y; ++y) {
2153 for (int x = min_x; x <= max_x; ++x) {
2154 const vec2D p(static_cast<float>(x) + 0.5f, static_cast<float>(y) + 0.5f);
2155 const float w0 = edge_function(p1, p2, p);
2156 const float w1 = edge_function(p2, p0, p);
2157 const float w2 = edge_function(p0, p1, p);
2158 if ((area > 0.0f && w0 >= 0.0f && w1 >= 0.0f && w2 >= 0.0f) ||
2159 (area < 0.0f && w0 <= 0.0f && w1 <= 0.0f && w2 <= 0.0f)) {
2160 plot_pixel(x, y, color);
2161 }
2162 }
2163 }
2164 }
Two-dimensional float vector with common arithmetic helpers.
Definition mxvk_math.h:177
float x
X coordinate.
Definition mxvk_math.h:180
float y
Y coordinate.
Definition mxvk_math.h:183
float edge_function(const vec2D &a, const vec2D &b, const vec2D &p)
Compute the signed edge function value for point p relative to edge a-b.
Definition mxvk_math.h:2127
constexpr float EPSILON
Default tolerance used for floating-point singularity and zero-length checks.
Definition mxvk_math.h:37

◆ draw_filled_triangle() [2/3]

void mxvk::draw_filled_triangle ( SDL_Renderer * renderer,
const vec2D & p0,
const vec2D & p1,
const vec2D & p2,
MXCOLOR color )
inline

Draw a filled triangle directly to an SDL renderer.

Definition at line 2167 of file mxvk_math.h.

2167 {
2168 draw_filled_triangle(p0, p1, p2, color, SDLRendererPixelPlotter{renderer});
2169 }
void draw_filled_triangle(const vec2D &p0, const vec2D &p1, const vec2D &p2, MXCOLOR color, PlotPixel &&plot_pixel)
Rasterize a filled triangle by testing pixels against edge functions.
Definition mxvk_math.h:2141
Pixel plotter adapter that writes packed MXVK colors to an SDL renderer.
Definition mxvk_math.h:2051

◆ draw_filled_triangle() [3/3]

void mxvk::draw_filled_triangle ( VK_Sprite & sprite,
const vec2D & p0,
const vec2D & p1,
const vec2D & p2,
MXCOLOR color,
int pixel_size = 1 )
inline

Draw a filled triangle directly to a VK_Sprite with optional square pixel size.

Definition at line 2172 of file mxvk_math.h.

2172 {
2173 draw_filled_triangle(p0, p1, p2, color, VKSpritePixelPlotter{&sprite, pixel_size});
2174 }
Pixel plotter adapter that draws square pixels into a VK_Sprite.
Definition mxvk_math.h:2066

◆ draw_filled_triangle_spans()

template<typename DrawSpan>
void mxvk::draw_filled_triangle_spans ( vec2D p0,
vec2D p1,
vec2D p2,
MXCOLOR color,
DrawSpan && draw_span )

Definition at line 2268 of file mxvk_math.h.

2268 {
2269 draw_filled_triangle_spans_clipped(p0, p1, p2, std::numeric_limits<int>::min(), std::numeric_limits<int>::max(), color, std::forward<DrawSpan>(draw_span));
2270 }
void draw_filled_triangle_spans_clipped(vec2D p0, vec2D p1, vec2D p2, int clip_min_y, int clip_max_y, MXCOLOR color, DrawSpan &&draw_span)
Rasterize a filled triangle as horizontal spans.
Definition mxvk_math.h:2188

◆ draw_filled_triangle_spans_clipped()

template<typename DrawSpan>
void mxvk::draw_filled_triangle_spans_clipped ( vec2D p0,
vec2D p1,
vec2D p2,
int clip_min_y,
int clip_max_y,
MXCOLOR color,
DrawSpan && draw_span )

Rasterize a filled triangle as horizontal spans.

Template Parameters
DrawSpanCallable accepting (x0, x1, y, MXCOLOR).
Parameters
p0First triangle vertex in screen coordinates.
p1Second triangle vertex in screen coordinates.
p2Third triangle vertex in screen coordinates.
clip_min_yMinimum inclusive scanline to rasterize.
clip_max_yMaximum inclusive scanline to rasterize.
colorPacked ARGB color.
draw_spanSpan drawing callable.

Definition at line 2188 of file mxvk_math.h.

2188 {
2189 if (std::fabs(edge_function(p0, p1, p2)) <= EPSILON) {
2190 return;
2191 }
2192
2193 struct SpanEdge {
2194 int y0 = 0;
2195 int y1 = -1;
2196 float x0 = 0.0f;
2197 float slope = 0.0f;
2198
2199 [[nodiscard]] float x_at(int y) const {
2200 return x0 + static_cast<float>(y - y0) * slope;
2201 }
2202 };
2203
2204 const int min_y = std::max(clip_min_y, static_cast<int>(std::floor(std::min({p0.y, p1.y, p2.y}))));
2205 const int max_y = std::min(clip_max_y, static_cast<int>(std::ceil(std::max({p0.y, p1.y, p2.y}))));
2206 if (min_y > max_y) {
2207 return;
2208 }
2209
2210 std::array<SpanEdge, 3> edges{};
2211 int edge_count = 0;
2212 const auto add_edge = [&](vec2D a, vec2D b) {
2213 if (std::fabs(a.y - b.y) <= EPSILON) {
2214 return;
2215 }
2216 if (a.y > b.y) {
2217 std::swap(a, b);
2218 }
2219
2220 const int y0 = std::max(min_y, static_cast<int>(std::ceil(a.y - 0.5f)));
2221 const int y1 = std::min(max_y, static_cast<int>(std::ceil(b.y - 0.5f)) - 1);
2222 if (y0 > y1) {
2223 return;
2224 }
2225
2226 SpanEdge &edge = edges[static_cast<std::size_t>(edge_count++)];
2227 edge.y0 = y0;
2228 edge.y1 = y1;
2229 edge.slope = (b.x - a.x) / (b.y - a.y);
2230 edge.x0 = a.x + ((static_cast<float>(y0) + 0.5f) - a.y) * edge.slope;
2231 };
2232
2233 add_edge(p0, p1);
2234 add_edge(p1, p2);
2235 add_edge(p2, p0);
2236
2237 for (int y = min_y; y <= max_y; ++y) {
2238 std::array<float, 3> intersections{};
2239 int intersection_count = 0;
2240
2241 for (int edge_index = 0; edge_index < edge_count; ++edge_index) {
2242 const SpanEdge &edge = edges[static_cast<std::size_t>(edge_index)];
2243 if (y >= edge.y0 && y <= edge.y1) {
2244 intersections[static_cast<std::size_t>(intersection_count++)] = edge.x_at(y);
2245 }
2246 }
2247
2248 if (intersection_count < 2) {
2249 continue;
2250 }
2251
2252 float min_x = intersections[0];
2253 float max_x = intersections[0];
2254 for (int i = 1; i < intersection_count; ++i) {
2255 min_x = std::min(min_x, intersections[static_cast<std::size_t>(i)]);
2256 max_x = std::max(max_x, intersections[static_cast<std::size_t>(i)]);
2257 }
2258
2259 const int x0 = static_cast<int>(std::ceil(min_x - 0.5f));
2260 const int x1 = static_cast<int>(std::floor(max_x - 0.5f));
2261 if (x0 <= x1) {
2262 draw_span(x0, x1, y, color);
2263 }
2264 }
2265 }

◆ draw_line() [1/3]

template<typename PlotPixel>
void mxvk::draw_line ( int x0,
int y0,
int x1,
int y1,
MXCOLOR color,
PlotPixel && plot_pixel )

Draw a line with Bresenham-style integer stepping.

Template Parameters
PlotPixelCallable accepting (x, y, MXCOLOR).
Parameters
x0Start X coordinate.
y0Start Y coordinate.
x1End X coordinate.
y1End Y coordinate.
colorPacked ARGB color.
plot_pixelPixel plotting callable.

Definition at line 2092 of file mxvk_math.h.

2092 {
2093 const int dx = std::abs(x1 - x0);
2094 const int sx = x0 < x1 ? 1 : -1;
2095 const int dy = -std::abs(y1 - y0);
2096 const int sy = y0 < y1 ? 1 : -1;
2097 int err = dx + dy;
2098
2099 while (1) {
2100 plot_pixel(x0, y0, color);
2101 if (x0 == x1 && y0 == y1) {
2102 break;
2103 }
2104 const int e2 = 2 * err;
2105 if (e2 >= dy) {
2106 err += dy;
2107 x0 += sx;
2108 }
2109 if (e2 <= dx) {
2110 err += dx;
2111 y0 += sy;
2112 }
2113 }
2114 }

◆ draw_line() [2/3]

void mxvk::draw_line ( SDL_Renderer * renderer,
int x0,
int y0,
int x1,
int y1,
MXCOLOR color )
inline

Draw a line directly to an SDL renderer.

Definition at line 2117 of file mxvk_math.h.

2117 {
2118 draw_line(x0, y0, x1, y1, color, SDLRendererPixelPlotter{renderer});
2119 }
void draw_line(int x0, int y0, int x1, int y1, MXCOLOR color, PlotPixel &&plot_pixel)
Draw a line with Bresenham-style integer stepping.
Definition mxvk_math.h:2092

◆ draw_line() [3/3]

void mxvk::draw_line ( VK_Sprite & sprite,
int x0,
int y0,
int x1,
int y1,
MXCOLOR color,
int pixel_size = 1 )
inline

Draw a line directly to a VK_Sprite with optional square pixel size.

Definition at line 2122 of file mxvk_math.h.

2122 {
2123 draw_line(x0, y0, x1, y1, color, VKSpritePixelPlotter{&sprite, pixel_size});
2124 }

◆ edge_function()

float mxvk::edge_function ( const vec2D & a,
const vec2D & b,
const vec2D & p )
inlinenodiscard

Compute the signed edge function value for point p relative to edge a-b.

Definition at line 2127 of file mxvk_math.h.

2127 {
2128 return (p.x - a.x) * (b.y - a.y) - (p.y - a.y) * (b.x - a.x);
2129 }

◆ end_one_time_commands()

void mxvk::end_one_time_commands ( const VulkanContext & context,
VkCommandBuffer command_buffer )

End, submit with vkQueueSubmit2, wait idle, and free a one-time command buffer.

Parameters
contextValid upload context with device, queue, and command pool.
command_bufferCommand buffer returned by begin_one_time_commands().
Exceptions
mxvk::Exceptionif end, submit, or queue wait fails.

Definition at line 253 of file mxvk_resource.cpp.

253 {
254 validate_upload_context(context);
255 if (vkEndCommandBuffer(command_buffer) != VK_SUCCESS) {
256 vkFreeCommandBuffers(context.device, context.command_pool, 1, &command_buffer);
257 throw mxvk::Exception("failed to end one-time command buffer");
258 }
259
260 VkCommandBufferSubmitInfo command_buffer_info{};
261 command_buffer_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO;
262 command_buffer_info.commandBuffer = command_buffer;
263
264 VkSubmitInfo2 submit_info{};
265 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2;
266 submit_info.commandBufferInfoCount = 1;
267 submit_info.pCommandBufferInfos = &command_buffer_info;
268
269 if (vkQueueSubmit2(context.graphics_queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
270 vkFreeCommandBuffers(context.device, context.command_pool, 1, &command_buffer);
271 throw mxvk::Exception("failed to submit one-time command buffer");
272 }
273 if (vkQueueWaitIdle(context.graphics_queue) != VK_SUCCESS) {
274 vkFreeCommandBuffers(context.device, context.command_pool, 1, &command_buffer);
275 throw mxvk::Exception("failed to wait for one-time command completion");
276 }
277
278 // Upload command buffers are transient; callers only observe completion.
279 vkFreeCommandBuffers(context.device, context.command_pool, 1, &command_buffer);
280 }
VkQueue graphics_queue
Queue used for one-shot upload command submission.

◆ fast_cosf()

float mxvk::fast_cosf ( float theta_degrees)
inlinenodiscard

Approximate cosine using the degree lookup table with linear interpolation.

Parameters
theta_degreesAngle in degrees.
Returns
Approximate cosine of the angle.

Definition at line 138 of file mxvk_math.h.

138 {
139 theta_degrees = std::fmod(theta_degrees, 360.0f);
140 if (theta_degrees < 0.0f) {
141 theta_degrees += 360.0f;
142 }
143 const int theta_int = static_cast<int>(theta_degrees);
144 const float theta_frac = theta_degrees - static_cast<float>(theta_int);
145 return cos_look[static_cast<std::size_t>(theta_int)] + theta_frac * (cos_look[static_cast<std::size_t>(theta_int + 1)] - cos_look[static_cast<std::size_t>(theta_int)]);
146 }

◆ fast_sinf()

float mxvk::fast_sinf ( float theta_degrees)
inlinenodiscard

Approximate sine using the degree lookup table with linear interpolation.

Parameters
theta_degreesAngle in degrees.
Returns
Approximate sine of the angle.

Definition at line 153 of file mxvk_math.h.

153 {
154 theta_degrees = std::fmod(theta_degrees, 360.0f);
155 if (theta_degrees < 0.0f) {
156 theta_degrees += 360.0f;
157 }
158 const int theta_int = static_cast<int>(theta_degrees);
159 const float theta_frac = theta_degrees - static_cast<float>(theta_int);
160 return sin_look[static_cast<std::size_t>(theta_int)] + theta_frac * (sin_look[static_cast<std::size_t>(theta_int + 1)] - sin_look[static_cast<std::size_t>(theta_int)]);
161 }

◆ find_memory_type()

uint32_t mxvk::find_memory_type ( VkPhysicalDevice physical_device,
uint32_t type_filter,
VkMemoryPropertyFlags properties )
nodiscard

Find a memory type satisfying a Vulkan memory type mask and property set.

Parameters
physical_devicePhysical device to query.
type_filterMemory type bitmask from VkMemoryRequirements.
propertiesRequired VkMemoryPropertyFlagBits.
Returns
Matching memory type index.
Exceptions
mxvk::Exceptionif no matching memory type is available.

Definition at line 48 of file mxvk_resource.cpp.

50 {
51 if (physical_device == VK_NULL_HANDLE) {
52 throw mxvk::Exception("find_memory_type requires a valid physical device");
53 }
54
55 VkPhysicalDeviceMemoryProperties memory_properties{};
56 vkGetPhysicalDeviceMemoryProperties(physical_device, &memory_properties);
57 for (uint32_t i = 0; i < memory_properties.memoryTypeCount; ++i) {
58 if ((type_filter & (1U << i)) &&
59 (memory_properties.memoryTypes[i].propertyFlags & properties) == properties) {
60 return i;
61 }
62 }
63
64 throw mxvk::Exception("failed to find suitable Vulkan memory type");
65 }

◆ HasPngExtension()

bool mxvk::HasPngExtension ( const char * file)
nodiscard

Definition at line 22 of file mxvk_png.cpp.

22 {
23 if (file == nullptr) {
24 return false;
25 }
26
27 std::string lower(file);
28 std::ranges::transform(lower, lower.begin(),
29 [](const unsigned char ch) { return static_cast<char>(std::tolower(ch)); });
30 return lower.ends_with(".png");
31 }

◆ load_spv()

std::vector< char > mxvk::load_spv ( const std::string & path)
nodiscard

Load a SPIR-V file from disk.

Parameters
pathAbsolute or relative path to a .spv file.
Returns
Raw bytes loaded from file.
Exceptions
mxvk::Exceptionwhen the file cannot be opened, is empty, or is not 4-byte aligned.

Definition at line 9 of file mxvk_shader_module.cpp.

9 {
10 if (path.empty()) {
11 throw mxvk::Exception("SPIR-V path is empty");
12 }
13
14 std::ifstream file(path, std::ios::binary);
15 if (!file.is_open()) {
16 throw mxvk::Exception("Failed to open SPIR-V file: " + path);
17 }
18
19 const std::vector<char> bytes((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
20 if (bytes.empty()) {
21 throw mxvk::Exception("SPIR-V file is empty: " + path);
22 }
23 if ((bytes.size() % 4U) != 0U) {
24 throw mxvk::Exception("SPIR-V file size is not 4-byte aligned: " + path);
25 }
26
27 return bytes;
28 }

◆ LoadPNG()

SDL_Surface * mxvk::LoadPNG ( const char * file)

Load a PNG file into an SDL_Surface.

Parameters
filePath to the PNG file.
Returns
Newly allocated SDL_Surface, or nullptr on failure.

Definition at line 103 of file mxvk_png.cpp.

103 {
104 if (!HasPngExtension(file)) {
105 return nullptr;
106 }
107
108 FILE *fp = std::fopen(file, "rb");
109 if (fp == nullptr) {
110 std::cerr << "Failed to open PNG file: " << file << "\n";
111 return nullptr;
112 }
113
114 png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
115 if (png == nullptr) {
116 std::fclose(fp);
117 return nullptr;
118 }
119
120 png_infop info = png_create_info_struct(png);
121 if (info == nullptr) {
122 png_destroy_read_struct(&png, nullptr, nullptr);
123 std::fclose(fp);
124 return nullptr;
125 }
126
127 if (setjmp(png_jmpbuf(png))) {
128 png_destroy_read_struct(&png, &info, nullptr);
129 std::fclose(fp);
130 return nullptr;
131 }
132
133 png_init_io(png, fp);
134 png_read_info(png, info);
135
136 const int width = static_cast<int>(png_get_image_width(png, info));
137 const int height = static_cast<int>(png_get_image_height(png, info));
138 const png_byte color_type = png_get_color_type(png, info);
139 const png_byte bit_depth = png_get_bit_depth(png, info);
140
141 if (width <= 0 || height <= 0) {
142 png_destroy_read_struct(&png, &info, nullptr);
143 std::fclose(fp);
144 return nullptr;
145 }
146
147 if (bit_depth == 16) {
148 png_set_strip_16(png);
149 }
150
151 if (color_type == PNG_COLOR_TYPE_PALETTE) {
152 png_set_palette_to_rgb(png);
153 }
154
155 if (png_get_valid(png, info, PNG_INFO_tRNS) != 0) {
156 png_set_tRNS_to_alpha(png);
157 }
158
159 if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
160 png_set_gray_to_rgb(png);
161 }
162
163 if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY ||
164 color_type == PNG_COLOR_TYPE_PALETTE) {
165 png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
166 }
167
168 png_read_update_info(png, info);
169
170 SDL_Surface *surface = SDL_CreateSurface(width, height, SDL_PIXELFORMAT_RGBA32);
171 if (surface == nullptr) {
172 png_destroy_read_struct(&png, &info, nullptr);
173 std::fclose(fp);
174 return nullptr;
175 }
176
177 const png_size_t row_bytes = png_get_rowbytes(png, info);
178 if (row_bytes > static_cast<png_size_t>(surface->pitch)) {
179 std::cerr << "mx: Unexpected PNG row stride mismatch for file: " << file << "\n";
180 SDL_DestroySurface(surface);
181 png_destroy_read_struct(&png, &info, nullptr);
182 std::fclose(fp);
183 return nullptr;
184 }
185
186 auto *pixels = static_cast<std::uint8_t *>(surface->pixels);
187 std::vector<png_bytep> row_pointers(static_cast<std::size_t>(height));
188 for (int y = 0; y < height; ++y) {
189 row_pointers[static_cast<std::size_t>(y)] = pixels + (y * surface->pitch);
190 }
191
192 png_read_image(png, row_pointers.data());
193 png_read_end(png, nullptr);
194
195 png_destroy_read_struct(&png, &info, nullptr);
196 std::fclose(fp);
197 return surface;
198 }
bool HasPngExtension(const char *file)
Definition mxvk_png.cpp:22

◆ map_buffer()

void mxvk::map_buffer ( VkDevice device,
BufferResource & buffer )

Persistently map a host-visible buffer allocation.

Parameters
deviceLogical device that owns the buffer memory.
bufferBuffer resource to map.
Exceptions
mxvk::Exceptionif the buffer is invalid or mapping fails.

Definition at line 123 of file mxvk_resource.cpp.

123 {
124 if (buffer.mapped != nullptr) {
125 return;
126 }
127 if (device == VK_NULL_HANDLE || buffer.memory == VK_NULL_HANDLE || buffer.size == 0) {
128 throw mxvk::Exception("map_buffer requires a valid buffer allocation");
129 }
130 if (vkMapMemory(device, buffer.memory, 0, buffer.size, 0, &buffer.mapped) != VK_SUCCESS || buffer.mapped == nullptr) {
131 throw mxvk::Exception("failed to map Vulkan buffer memory");
132 }
133 }
void * mapped
Host pointer returned by vkMapMemory, or nullptr when unmapped.

◆ MXVK_RGB()

MXCOLOR mxvk::MXVK_RGB ( int r,
int g,
int b )
inlinenodiscardconstexpr

Build an opaque ARGB color from red, green, and blue components.

Parameters
rRed component in the low 8 bits.
gGreen component in the low 8 bits.
bBlue component in the low 8 bits.
Returns
Packed color with alpha set to 255.

Definition at line 49 of file mxvk_math.h.

49 {
50 return 0xFF000000u | ((static_cast<MXCOLOR>(r) & 0xFFu) << 16u) | ((static_cast<MXCOLOR>(g) & 0xFFu) << 8u) | (static_cast<MXCOLOR>(b) & 0xFFu);
51 }
std::uint32_t MXCOLOR
Packed 32-bit color in ARGB byte order.
Definition mxvk_math.h:40

◆ operator<<() [1/3]

std::ostream & mxvk::operator<< ( std::ostream & out,
const vec2D & v )
inline

Write a 2D vector to a stream using vec2D::Print().

Definition at line 281 of file mxvk_math.h.

281 {
282 return out << v.Print();
283 }
std::string Print(const std::string &name="v") const
Format this vector as a named angle-bracket tuple.
Definition mxvk_math.h:273

◆ operator<<() [2/3]

std::ostream & mxvk::operator<< ( std::ostream & out,
const vec3D & v )
inline

Write a 3D vector to a stream using vec3D::Print().

Definition at line 406 of file mxvk_math.h.

406 {
407 return out << v.Print();
408 }
std::string Print(const std::string &name="v") const
Format this vector as a named angle-bracket tuple.
Definition mxvk_math.h:398

◆ operator<<() [3/3]

std::ostream & mxvk::operator<< ( std::ostream & out,
const vec4D & v )
inline

Write a 4D vector to a stream using vec4D::Print().

Definition at line 562 of file mxvk_math.h.

562 {
563 return out << v.Print();
564 }
std::string Print(const std::string &name="v") const
Format this vector as a named angle-bracket tuple.
Definition mxvk_math.h:554

◆ operator>>() [1/3]

std::istream & mxvk::operator>> ( std::istream & in,
vec2D & v )
inline

Read a 2D vector from a stream as two scalar coordinates.

Definition at line 286 of file mxvk_math.h.

286 {
287 return in >> v.x >> v.y;
288 }

◆ operator>>() [2/3]

std::istream & mxvk::operator>> ( std::istream & in,
vec3D & v )
inline

Read a 3D vector from a stream as three scalar coordinates.

Definition at line 411 of file mxvk_math.h.

411 {
412 return in >> v.x >> v.y >> v.z;
413 }
float z
Z coordinate.
Definition mxvk_math.h:300
float x
X coordinate.
Definition mxvk_math.h:294
float y
Y coordinate.
Definition mxvk_math.h:297

◆ operator>>() [3/3]

std::istream & mxvk::operator>> ( std::istream & in,
vec4D & v )
inline

Read a 4D vector from a stream as four scalar coordinates.

Definition at line 567 of file mxvk_math.h.

567 {
568 return in >> v.x >> v.y >> v.z >> v.w;
569 }
float y
Y coordinate.
Definition mxvk_math.h:422
float x
X coordinate.
Definition mxvk_math.h:419
float w
Homogeneous W coordinate.
Definition mxvk_math.h:428
float z
Z coordinate.
Definition mxvk_math.h:425

◆ rad2deg()

float mxvk::rad2deg ( float rad)
inlinenodiscard

Convert radians to degrees.

Definition at line 129 of file mxvk_math.h.

129 {
130 return rad * 180.0f / PI;
131 }

◆ rrand()

int mxvk::rrand ( int x,
int y )
inlinenodiscard

Return a pseudo-random integer in the inclusive range between two bounds.

Parameters
xFirst bound.
ySecond bound.
Returns
Random integer in [min(x, y), max(x, y)].

Definition at line 169 of file mxvk_math.h.

169 {
170 if (x > y) {
171 std::swap(x, y);
172 }
173 return x + (std::rand() % (y - x + 1));
174 }

◆ SavePNG()

bool mxvk::SavePNG ( SDL_Texture * texture,
SDL_Renderer * renderer,
const char * filename )

Save an SDL_Texture to a PNG file.

Parameters
textureSource texture.
rendererRenderer used to read back the texture pixels.
filenameDestination file path.
Returns
true on success, false on failure.

Definition at line 200 of file mxvk_png.cpp.

200 {
201 if (texture == nullptr || renderer == nullptr || filename == nullptr) {
202 std::cerr << "mx: Invalid SavePNG parameters.\n";
203 return false;
204 }
205
206 float width_f = 0.0F;
207 float height_f = 0.0F;
208 if (!SDL_GetTextureSize(texture, &width_f, &height_f)) {
209 std::cerr << "mx: Failed to query texture size: " << SDL_GetError() << "\n";
210 return false;
211 }
212
213 if (!std::isfinite(width_f) || !std::isfinite(height_f) || width_f <= 0.0F || height_f <= 0.0F) {
214 std::cerr << "mx: Invalid texture size while saving PNG.\n";
215 return false;
216 }
217
218 const int width = static_cast<int>(width_f);
219 const int height = static_cast<int>(height_f);
220 if (width <= 0 || height <= 0) {
221 std::cerr << "mx: Invalid integer texture size while saving PNG.\n";
222 return false;
223 }
224
225 SDL_Texture *previous_target = SDL_GetRenderTarget(renderer);
226 if (!SDL_SetRenderTarget(renderer, texture)) {
227 std::cerr << "mx: Failed to set render target: " << SDL_GetError() << "\n";
228 return false;
229 }
230
231 SDL_Surface *captured = SDL_RenderReadPixels(renderer, nullptr);
232
233 if (!SDL_SetRenderTarget(renderer, previous_target)) {
234 std::cerr << "mx: Failed to restore render target: " << SDL_GetError() << "\n";
235 }
236
237 if (captured == nullptr) {
238 std::cerr << "mx: Failed to read pixels from renderer: " << SDL_GetError() << "\n";
239 return false;
240 }
241
242 std::unique_ptr<SDL_Surface, decltype(&SDL_DestroySurface)> captured_surface(captured, &SDL_DestroySurface);
243
244 SDL_Surface *rgba32_surface_raw = captured_surface.get();
245 std::unique_ptr<SDL_Surface, decltype(&SDL_DestroySurface)> converted_surface(nullptr, &SDL_DestroySurface);
246 if (captured_surface->format != SDL_PIXELFORMAT_RGBA32) {
247 rgba32_surface_raw = SDL_ConvertSurface(captured_surface.get(), SDL_PIXELFORMAT_RGBA32);
248 if (rgba32_surface_raw == nullptr) {
249 std::cerr << "mx: Failed to convert surface to RGBA32: " << SDL_GetError() << "\n";
250 return false;
251 }
252 converted_surface.reset(rgba32_surface_raw);
253 }
254
255 const auto *pixels = static_cast<const std::uint8_t *>(rgba32_surface_raw->pixels);
256 return WriteRgbaPng(filename,
257 pixels,
258 rgba32_surface_raw->w,
259 rgba32_surface_raw->h,
260 rgba32_surface_raw->pitch,
261 8,
262 false);
263 }
bool WriteRgbaPng(const char *filename, const std::uint8_t *pixels, const int width, const int height, const int pitch, const int bit_depth, const bool swap_16bit_endianness)
Definition mxvk_png.cpp:33

◆ SavePNG_RGBA()

bool mxvk::SavePNG_RGBA ( const char * filename,
void * buffer,
int w,
int h )

Save a raw RGBA pixel buffer to a PNG file.

Parameters
filenameDestination file path.
bufferPointer to the raw RGBA pixel data.
wImage width in pixels.
hImage height in pixels.
Returns
true on success, false on failure.

Definition at line 300 of file mxvk_png.cpp.

300 {
301 const int pitch = w * 4;
302 return WriteRgbaPng(filename,
303 static_cast<const std::uint8_t *>(buffer),
304 w,
305 h,
306 pitch,
307 8,
308 false);
309 }

◆ SavePNG_RGBA16()

bool mxvk::SavePNG_RGBA16 ( const char * filename,
const void * buffer,
int w,
int h )

Save a raw 16-bit RGBA pixel buffer to a PNG file.

Parameters
filenameDestination file path.
bufferPointer to the raw 16-bit RGBA pixel data.
wImage width in pixels.
hImage height in pixels.
Returns
true on success, false on failure.

Definition at line 311 of file mxvk_png.cpp.

311 {
312 const int pitch = w * 8;
313#if SDL_BYTEORDER == SDL_LIL_ENDIAN
314 constexpr bool swap_16bit_endianness = true;
315#else
316 constexpr bool swap_16bit_endianness = false;
317#endif
318 return WriteRgbaPng(filename,
319 static_cast<const std::uint8_t *>(buffer),
320 w,
321 h,
322 pitch,
323 16,
324 swap_16bit_endianness);
325 }

◆ SaveRawBytes()

bool mxvk::SaveRawBytes ( const char * filename,
const void * buffer,
size_t w,
size_t h,
size_t bpp )

Save raw data to a file.

Parameters
filenameOutput file path
bufferPointer to the source data (read-only)
wWidth of the image in pixels
hHeight of the image in pixels
bppBytes per pixel (e.g., 2 for YUYV, 4 for RGBA)
Returns
true on success, false on failure.

Definition at line 265 of file mxvk_png.cpp.

265 {
266 if (filename == nullptr || buffer == nullptr || bpp == 0U) {
267 std::cerr << "mx: Invalid SaveRawBytes parameters.\n";
268 return false;
269 }
270
271 if (w != 0U && h > (std::numeric_limits<size_t>::max() / w)) {
272 std::cerr << "mx: Raw byte size overflow while writing: " << filename << "\n";
273 return false;
274 }
275
276 const size_t pixels = w * h;
277 if (pixels != 0U && bpp > (std::numeric_limits<size_t>::max() / pixels)) {
278 std::cerr << "mx: Raw byte size overflow while writing: " << filename << "\n";
279 return false;
280 }
281
282 const size_t size = pixels * bpp;
283 FILE *fptr = std::fopen(filename, "wb");
284 if (fptr == nullptr) {
285 std::cerr << "mx: Failed to open output file: " << filename << "\n";
286 return false;
287 }
288
289 const size_t written = std::fwrite(buffer, sizeof(unsigned char), size, fptr);
290 if (written != size) {
291 std::cerr << "mx: Error writing frame: " << filename << "\n";
292 std::fclose(fptr);
293 return false;
294 }
295
296 std::fclose(fptr);
297 return true;
298 }

◆ setDefaultEnableScreenshot()

void mxvk::setDefaultEnableScreenshot ( bool enabled)
inline

Definition at line 11 of file mxvk_runtime_options.hpp.

11 {
13 }

◆ setDefaultExecutableName()

void mxvk::setDefaultExecutableName ( const std::string & name)
inline

Definition at line 24 of file mxvk_runtime_options.hpp.

24 {
25 defaultExecutableNameStorage() = name.empty() ? "mxvk" : name;
26 }

◆ shade_color()

MXCOLOR mxvk::shade_color ( MXCOLOR color,
float intensity )
inlinenodiscard

Scale the RGB channels of a color while preserving alpha.

Parameters
colorPacked ARGB color to shade.
intensityMultiplier clamped to the range [0, 1].
Returns
Shaded packed ARGB color.

Definition at line 79 of file mxvk_math.h.

79 {
80 intensity = std::clamp(intensity, 0.0f, 1.0f);
81 const auto scale = [intensity](std::uint8_t component) {
82 return static_cast<int>(std::clamp(static_cast<float>(component) * intensity, 0.0f, 255.0f));
83 };
84 return (static_cast<MXCOLOR>(color_a(color)) << 24u) |
85 ((static_cast<MXCOLOR>(scale(color_r(color))) & 0xFFu) << 16u) |
86 ((static_cast<MXCOLOR>(scale(color_g(color))) & 0xFFu) << 8u) |
87 (static_cast<MXCOLOR>(scale(color_b(color))) & 0xFFu);
88 }
constexpr std::uint8_t color_r(MXCOLOR color)
Extract the red component from a packed ARGB color.
Definition mxvk_math.h:54
constexpr std::uint8_t color_g(MXCOLOR color)
Extract the green component from a packed ARGB color.
Definition mxvk_math.h:59
constexpr std::uint8_t color_a(MXCOLOR color)
Extract the alpha component from a packed ARGB color.
Definition mxvk_math.h:69
constexpr std::uint8_t color_b(MXCOLOR color)
Extract the blue component from a packed ARGB color.
Definition mxvk_math.h:64

◆ transition_image_layout()

void mxvk::transition_image_layout ( VkCommandBuffer command_buffer,
VkImage image,
VkImageLayout old_layout,
VkImageLayout new_layout,
VkImageAspectFlags aspect = VK_IMAGE_ASPECT_COLOR_BIT )

Record a Vulkan 1.3 synchronization2 image layout transition.

Parameters
command_bufferCommand buffer in recording state.
imageImage to transition.
old_layoutCurrent image layout.
new_layoutDesired image layout.
aspectImage aspect mask.

Supported transitions are:

  • VK_IMAGE_LAYOUT_UNDEFINED to VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
  • VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
Exceptions
mxvk::Exceptionfor unsupported transitions.

Definition at line 307 of file mxvk_resource.cpp.

311 {
312 VkImageMemoryBarrier2 barrier{};
313 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
314 barrier.oldLayout = old_layout;
315 barrier.newLayout = new_layout;
316 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
317 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
318 barrier.image = image;
319 barrier.subresourceRange.aspectMask = aspect;
320 barrier.subresourceRange.baseMipLevel = 0;
321 barrier.subresourceRange.levelCount = 1;
322 barrier.subresourceRange.baseArrayLayer = 0;
323 barrier.subresourceRange.layerCount = 1;
324
325 // MXVK requires Vulkan 1.3 synchronization2, so uploads use stage/access2 masks.
326 if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED && new_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
327 barrier.srcStageMask = VK_PIPELINE_STAGE_2_NONE;
328 barrier.srcAccessMask = VK_ACCESS_2_NONE;
329 barrier.dstStageMask = VK_PIPELINE_STAGE_2_COPY_BIT;
330 barrier.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT;
331 } else if (old_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && new_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
332 barrier.srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT;
333 barrier.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT;
334 barrier.dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT;
335 barrier.dstAccessMask = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT;
336 } else {
337 throw mxvk::Exception("unsupported image layout transition");
338 }
339
340 VkDependencyInfo dependency{};
341 dependency.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO;
342 dependency.imageMemoryBarrierCount = 1;
343 dependency.pImageMemoryBarriers = &barrier;
344 vkCmdPipelineBarrier2(command_buffer, &dependency);
345 }

◆ unmap_buffer()

void mxvk::unmap_buffer ( VkDevice device,
BufferResource & buffer )

Unmap a BufferResource if it is currently mapped.

Parameters
deviceLogical device that owns the buffer memory.
bufferBuffer resource to unmap.

Definition at line 135 of file mxvk_resource.cpp.

135 {
136 if (device != VK_NULL_HANDLE && buffer.memory != VK_NULL_HANDLE && buffer.mapped != nullptr) {
137 vkUnmapMemory(device, buffer.memory);
138 }
139 buffer.mapped = nullptr;
140 }

◆ WriteRgbaPng()

bool mxvk::WriteRgbaPng ( const char * filename,
const std::uint8_t * pixels,
const int width,
const int height,
const int pitch,
const int bit_depth,
const bool swap_16bit_endianness )
nodiscard

Definition at line 33 of file mxvk_png.cpp.

39 {
40 if (filename == nullptr || pixels == nullptr || width <= 0 || height <= 0 || pitch <= 0) {
41 std::cerr << "mx: Invalid PNG write parameters.\n";
42 return false;
43 }
44
45 FILE *file = std::fopen(filename, "wb");
46 if (file == nullptr) {
47 std::cerr << "mx: Failed to open file for writing: " << filename << "\n";
48 return false;
49 }
50
51 png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
52 if (png == nullptr) {
53 std::cerr << "mx: Failed to create PNG write struct.\n";
54 std::fclose(file);
55 return false;
56 }
57
58 png_infop info = png_create_info_struct(png);
59 if (info == nullptr) {
60 std::cerr << "mx: Failed to create PNG info struct.\n";
61 png_destroy_write_struct(&png, nullptr);
62 std::fclose(file);
63 return false;
64 }
65
66 if (setjmp(png_jmpbuf(png))) {
67 std::cerr << "mx: Error during PNG creation.\n";
68 png_destroy_write_struct(&png, &info);
69 std::fclose(file);
70 return false;
71 }
72
73 png_init_io(png, file);
74 png_set_IHDR(png,
75 info,
76 width,
77 height,
78 bit_depth,
79 PNG_COLOR_TYPE_RGBA,
80 PNG_INTERLACE_NONE,
81 PNG_COMPRESSION_TYPE_DEFAULT,
82 PNG_FILTER_TYPE_DEFAULT);
83
84 if (bit_depth == 16 && swap_16bit_endianness) {
85 png_set_swap(png);
86 }
87
88 png_write_info(png, info);
89
90 std::vector<png_bytep> rows(static_cast<std::size_t>(height));
91 for (int y = 0; y < height; ++y) {
92 rows[static_cast<std::size_t>(y)] = const_cast<png_bytep>(pixels + (y * pitch));
93 }
94
95 png_write_image(png, rows.data());
96 png_write_end(png, nullptr);
97
98 png_destroy_write_struct(&png, &info);
99 std::fclose(file);
100 return true;
101 }

Variable Documentation

◆ cos_look

std::array< float, 361 > mxvk::cos_look = build_cos_table()
inline

Cosine lookup table with one entry per degree from 0 through 360.

Definition at line 110 of file mxvk_math.h.

◆ EPSILON

float mxvk::EPSILON = 1.0e-5f
inlineconstexpr

Default tolerance used for floating-point singularity and zero-length checks.

Definition at line 37 of file mxvk_math.h.

◆ PI

float mxvk::PI = 3.14159265358979323846f
inlineconstexpr

Mathematical constant pi as a single-precision value.

Definition at line 34 of file mxvk_math.h.

◆ sin_look

std::array< float, 361 > mxvk::sin_look = build_sin_table()
inline

Sine lookup table with one entry per degree from 0 through 360.

Definition at line 107 of file mxvk_math.h.