1 module sbylib.graphics.wrapper.buffer;
2 
3 import std;
4 import sbylib.wrapper.vulkan;
5 import sbylib.graphics.wrapper.device;
6 import sbylib.graphics.util.own;
7 
8 class VBuffer(T) {
9 
10     alias Type = T;
11 
12     private {
13         @own {
14             Buffer _buffer;
15             DeviceMemory _memory;
16         }
17         size_t size;
18     }
19 
20     mixin ImplReleaseOwn;
21 
22     this(const T[] data, BufferUsage usage) {
23         this(T.sizeof * data.length, usage, MemoryProperties.MemoryType.Flags.HostVisible);
24         this.write(data);
25     }
26 
27     this(size_t size, BufferUsage usage, MemoryProperties.MemoryType.Flags flag) {
28         this.size = size;
29 
30         with (VDevice()) {
31             Buffer.CreateInfo bufferInfo = {
32                 usage: usage,
33                 size: size,
34                 sharingMode: SharingMode.Exclusive,
35             };
36             this._buffer = new Buffer(device, bufferInfo);
37             this._memory = _buffer.allocateMemory(gpu, flag);
38     
39             _memory.bindBuffer(_buffer, 0);
40         }
41     }
42 
43     Buffer buffer() {
44         return _buffer;
45     }
46 
47     DeviceMemory memory() {
48         return _memory;
49     }
50 
51     auto map() {
52         struct HostMemory {
53             private DeviceMemory deviceMemory;
54             T[] hostMemory;
55 
56             ~this() {
57                 deviceMemory.unmap();
58             }
59 
60             static if (isAggregateType!(T)) {
61                 static foreach (mem; __traits(allMembers, T)) {
62                     static if (!isCallable!(__traits(getMember, T, mem))) {
63                         mixin(q{
64                             auto ref ${mem} () {
65                                 return hostMemory[0].${mem};
66                             }
67                         }.replace("${mem}", mem));
68                     }
69                 }
70             }
71         }
72 
73         return HostMemory(this.memory, cast(T[])this.memory.map(0, this.size, 0));
74     }
75 
76     void write(const T[] data) {
77         auto hostMemory = memory.map(0, T.sizeof * data.length, 0);
78         hostMemory[] = (cast(const ubyte[])data)[];
79         memory.unmap();
80     }
81 }