VisuTwin Canvas
C++ 3D Engine — Metal Backend
Loading...
Searching...
No Matches
metalBuffer.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2025-2026 Arnis Lektauers
3//
4// Created by Arnis Lektauers on 19.07.2025.
5//
6#include "metalBuffer.h"
7
8#include <spdlog/spdlog.h>
9
11{
13 {
14 if (_buffer)
15 {
16 _buffer->release();
17 }
18 }
19
20 void MetalBuffer::allocate(MTL::Device* device, size_t size)
21 {
22 assert(!_buffer && "Buffer already allocated");
23
24 auto options = MTL::StorageModeShared;
25 _buffer = device->newBuffer(size, options);
26
27 auto label = "";
28 if (_usageFlags & VERTEX) {
29 label = "VertexBuffer";
30 } else if (_usageFlags & INDEX) {
31 label = "IndexBuffer";
32 } else if (_usageFlags & UNIFORM) {
33 label = "UniformBuffer";
34 } else if (_usageFlags & STORAGE) {
35 label = "StorageBuffer";
36 }
37 _buffer->addDebugMarker(NS::String::string(label, NS::UTF8StringEncoding), NS::Range(0, size - 1));
38 }
39
40 void MetalBuffer::write(size_t bufferOffset, const void* data, size_t dataSize) const
41 {
42 assert(bufferOffset + dataSize <= size());
43
44 memcpy(static_cast<uint8_t*>(_buffer->contents()) + bufferOffset, data, dataSize);
45 }
46
47 void MetalBuffer::unlock(MetalGraphicsDevice* device, const std::vector<uint8_t>& storage)
48 {
49 assert(device != nullptr && "Cannot unlock buffer without valid device");
50
51 if (!_buffer) {
52 // Size needs to be a multiple of 4 for WebGPU
53 size_t size = (storage.size() + 3) & ~3;
54
55 // Add COPY_DST usage flag for data uploads
56 _usageFlags = static_cast<BufferUsage>(_usageFlags | BufferUsage::COPY_DST);
57
58 allocate(device, size);
59 }
60
61 if (storage.empty()) {
62 return;
63 }
64
65 // Prepare data for upload - WebGPU requires proper alignment
66 size_t totalSize = _buffer->length();
67
68 write(0, storage.data(), totalSize);
69
70 spdlog::debug("WriteBuffer: {} (size: {} bytes)", _buffer->label()->utf8String(), totalSize);
71 }
72
74 {
75 assert(!_buffer && "Buffer already allocated");
76
77 if (!device) {
78 spdlog::error("Cannot allocate buffer without valid device");
79 return;
80 }
81
82 MTL::ResourceOptions options = MTL::ResourceStorageModeShared;
83 // Cache mode adjustments for uniform buffers
84 if (_usageFlags & UNIFORM) {
85 options |= MTL::ResourceCPUCacheModeDefaultCache;
86 } else {
87 options |= MTL::ResourceCPUCacheModeWriteCombined;
88 }
89
90 _buffer = device->raw()->newBuffer(size, options);
91
92 // Set the debug label based on usage
93 const char* label = "";
94 if (_usageFlags & VERTEX) {
95 label = "VertexBuffer";
96 } else if (_usageFlags & INDEX) {
97 label = "IndexBuffer";
98 } else if (_usageFlags & UNIFORM) {
99 label = "UniformBuffer";
100 } else if (_usageFlags & STORAGE) {
101 label = "StorageBuffer";
102 }
103 _buffer->setLabel(NS::String::string(label, NS::UTF8StringEncoding));
104
105 spdlog::debug("Allocated Metal buffer: {} (size: {} bytes)", label, size);
106 }
107
108 void MetalBuffer::upload(GraphicsDevice* device, const void* data, size_t dataSize)
109 {
110 auto* metalDevice = static_cast<MetalGraphicsDevice*>(device);
111 if (!_buffer) {
112 allocate(metalDevice, dataSize);
113 }
114 if (data && dataSize > 0) {
115 write(0, data, dataSize);
116 }
117 }
118
119 void MetalBuffer::adoptBuffer(MTL::Buffer* buffer)
120 {
121 if (_buffer) {
122 _buffer->release();
123 }
124 _buffer = buffer;
125 if (_buffer) {
126 _buffer->retain(); // We now own a reference
127 }
128 }
129}
Abstract GPU interface for resource creation, state management, and draw submission.
void upload(GraphicsDevice *device, const void *data, size_t size) override
Upload data to the GPU buffer.
void unlock(MetalGraphicsDevice *device, const std::vector< uint8_t > &storage)
void adoptBuffer(MTL::Buffer *buffer)
void allocate(MTL::Device *device, size_t size)
void write(size_t bufferOffset, const void *data, size_t dataSize) const