1 module gfx.gl3.device;
2 
3 package:
4 
5 import gfx.graal.cmd : CommandPool;
6 import gfx.graal.device : Device;
7 import gfx.graal.sync : Fence, Semaphore;
8 
9 class GlDevice : Device
10 {
11     import core.time :              Duration;
12     import gfx.core.rc :            atomicRcCode, Rc;
13     import gfx.gl3 :                GlInstance, GlPhysicalDevice, GlShare;
14     import gfx.gl3.queue :          GlQueue;
15     import gfx.graal :              Instance;
16     import gfx.graal.buffer :       Buffer, BufferUsage;
17     import gfx.graal.device :       MappedMemorySet;
18     import gfx.graal.format :       Format;
19     import gfx.graal.image :        Image, ImageInfo, ImageUsage, ImageView,
20                                     Sampler, SamplerInfo;
21     import gfx.graal.memory :       DeviceMemory, MemoryProperties;
22     import gfx.graal.presentation : CompositeAlpha, PresentMode, Surface,
23                                     Swapchain;
24     import gfx.graal.queue :        Queue;
25     import gfx.graal.renderpass :   AttachmentDescription, Framebuffer,
26                                     RenderPass, SubpassDependency,
27                                     SubpassDescription;
28     import gfx.graal.pipeline :     CopyDescritporSet, DescriptorSet,
29                                     DescriptorSetLayout, DescriptorPool,
30                                     DescriptorPoolSize, Pipeline, PipelineInfo,
31                                     PipelineLayout, PipelineLayoutBinding,
32                                     PushConstantRange, ShaderModule,
33                                     WriteDescriptorSet;
34     import std.typecons : Flag;
35 
36     mixin(atomicRcCode);
37 
38     private GlPhysicalDevice _phd;
39     private Rc!Instance _inst;
40     private Rc!GlShare _share;
41     private MemoryProperties _memProps;
42     private GlQueue _queue;
43 
44 
45     this (GlPhysicalDevice phd, GlInstance inst) {
46         _phd = phd;
47         _inst = inst;
48         _share = inst.share;
49         _memProps = phd.memoryProperties;
50         _queue = new GlQueue(_share, this, 0);
51     }
52 
53     override void dispose() {
54         _queue.dispose();
55         _share.unload();
56         _inst.unload();
57     }
58 
59     override GlPhysicalDevice physicalDevice() {
60         return _phd;
61     }
62 
63     override Instance instance() {
64         return _inst;
65     }
66 
67     override void waitIdle() {}
68 
69     override Queue getQueue(uint queueFamilyIndex, uint queueIndex) {
70         return _queue;
71     }
72 
73     CommandPool createCommandPool(uint queueFamilyIndex) {
74         import gfx.gl3.queue : GlCommandPool;
75         return new GlCommandPool(_queue);
76     }
77 
78     DeviceMemory allocateMemory(uint memPropIndex, size_t size) {
79         import gfx.gl3.resource : GlDeviceMemory;
80         return new GlDeviceMemory(this, memPropIndex, _memProps.types[memPropIndex].props, size);
81     }
82 
83     void flushMappedMemory(MappedMemorySet set) {}
84     void invalidateMappedMemory(MappedMemorySet set) {}
85 
86     Buffer createBuffer(BufferUsage usage, size_t size) {
87         import gfx.gl3.resource : GlBuffer;
88         return new GlBuffer(this, _share, usage, size);
89     }
90 
91     Image createImage(in ImageInfo info) {
92         import gfx.gl3.resource : GlImage;
93         return new GlImage(this, _share, info);
94     }
95 
96     Sampler createSampler(in SamplerInfo info) {
97         import gfx.gl3.resource : GlSampler;
98         return new GlSampler(this, _share, info);
99     }
100 
101     Semaphore createSemaphore() {
102         return new GlSemaphore(this);
103     }
104 
105     Fence createFence(Flag!"signaled" signaled) {
106         return new GlFence(this, signaled);
107     }
108 
109     void resetFences(Fence[] fences) {}
110     void waitForFences(Fence[] fences, Flag!"waitAll" waitAll, Duration timeout) {}
111 
112     Swapchain createSwapchain(Surface surface, PresentMode pm, uint numImages,
113                               Format format, uint[2] size, ImageUsage usage,
114                               CompositeAlpha alpha, Swapchain former=null) {
115         import gfx.gl3.swapchain : GlSwapchain;
116         return new GlSwapchain(this, _share, surface, pm, numImages, format, size, usage, alpha, former);
117     }
118 
119     RenderPass createRenderPass(in AttachmentDescription[] attachments,
120                                 in SubpassDescription[] subpasses,
121                                 in SubpassDependency[] dependencies) {
122         import gfx.gl3.pipeline : GlRenderPass;
123         return new GlRenderPass(this, attachments, subpasses, dependencies);
124     }
125 
126     Framebuffer createFramebuffer(RenderPass rp, ImageView[] attachments,
127                                   uint width, uint height, uint layers) {
128         import gfx.gl3.pipeline : GlFramebuffer, GlRenderPass;
129         import gfx.gl3.resource : GlImageView;
130         import std.algorithm : map;
131         import std.array : array;
132 
133         return new GlFramebuffer(_share, cast(GlRenderPass)rp,
134             attachments.map!(iv => cast(GlImageView)iv).array,
135             width, height, layers);
136     }
137 
138     ShaderModule createShaderModule(const(uint)[] code, string entryPoint) {
139         import gfx.gl3.pipeline : GlShaderModule;
140         import std.exception : enforce;
141 
142         enforce(entryPoint == "main");
143         return new GlShaderModule(this, _share, code);
144     }
145 
146     DescriptorSetLayout createDescriptorSetLayout(in PipelineLayoutBinding[] bindings) {
147         import gfx.gl3.pipeline : GlDescriptorSetLayout;
148         return new GlDescriptorSetLayout(this, bindings);
149     }
150 
151     PipelineLayout createPipelineLayout(DescriptorSetLayout[] layouts, in PushConstantRange[] ranges) {
152         import gfx.gl3.pipeline : GlPipelineLayout;
153         return new GlPipelineLayout(this, layouts, ranges);
154     }
155 
156     DescriptorPool createDescriptorPool(in uint maxSets, in DescriptorPoolSize[] sizes) {
157         import gfx.gl3.pipeline : GlDescriptorPool;
158         return new GlDescriptorPool(this, maxSets, sizes);
159     }
160 
161     void updateDescriptorSets(WriteDescriptorSet[] writeOps, CopyDescritporSet[] copyOps) {
162         import gfx.gl3.pipeline : GlDescriptorSet;
163         foreach (wo; writeOps) {
164             auto glSet = cast(GlDescriptorSet)wo.dstSet;
165             glSet.write(wo.dstBinding, wo.dstArrayElem, wo.write);
166         }
167     }
168 
169     Pipeline[] createPipelines(PipelineInfo[] infos) {
170         import gfx.gl3.pipeline : GlPipeline;
171         import std.algorithm : map;
172         import std.array : array;
173         return infos.map!(pi => cast(Pipeline)new GlPipeline(this, _share, pi)).array;
174     }
175 }
176 
177 private final class GlSemaphore : Semaphore {
178     import gfx.core.rc : atomicRcCode, Rc;
179     mixin(atomicRcCode);
180 
181     private Rc!GlDevice _dev;
182 
183     this(GlDevice dev) {
184         _dev = dev;
185     }
186     override void dispose() {
187         _dev.unload();
188     }
189     override @property GlDevice device() {
190         return _dev;
191     }
192 }
193 
194 private final class GlFence : Fence {
195     import core.time : Duration;
196     import gfx.core.rc : atomicRcCode, Rc;
197     mixin(atomicRcCode);
198 
199     private Rc!GlDevice _dev;
200     private bool _signaled;
201 
202     this(GlDevice dev, bool signaled) {
203         _dev = dev;
204         _signaled = signaled;
205     }
206     override void dispose() {
207         _dev.unload();
208     }
209     override @property GlDevice device() {
210         return _dev;
211     }
212     override @property bool signaled() { return _signaled; }
213     override void reset() {}
214     override void wait(Duration timeout) {}
215 }
216