1 module sbylib.graphics.util.filetexture;
2 
3 import std;
4 import erupted;
5 import sbylib.wrapper.vulkan;
6 import sbylib.wrapper.freeimage : FIImage = Image;
7 import sbylib.graphics.wrapper.device;
8 import sbylib.graphics.util.own;
9 import sbylib.graphics.wrapper;
10 
11 class FileTexture : Texture {
12 
13     private {
14         @own {
15             VImage image;
16             ImageView _imageView;
17             Sampler _sampler;
18         }
19         uint _width, _height;
20     }
21 
22     mixin ImplReleaseOwn;
23 
24     this(string fileName) {
25         auto texture = FIImage.load(fileName).to32bit();
26         scope (exit) texture.destroy();
27 
28         this._width = texture.width;
29         this._height = texture.height;
30 
31         auto stagingBuffer = new VBuffer!ubyte(texture.dataArray, BufferUsage.TransferSrc);
32         scope (exit) stagingBuffer.destroy();
33 
34         this.image = new VImage(createImage(texture.width, texture.height), MemoryProperties.MemoryType.Flags.DeviceLocal);
35         this._imageView = createImageView(image.image);
36 
37         this._sampler = createSampler();
38 
39         transferData(stagingBuffer.buffer, image.image);
40     }
41 
42     private Buffer createStageBuffer(size_t size) {
43         Buffer.CreateInfo bufferInfo = {
44             usage: BufferUsage.TransferSrc,
45             size: size,
46             sharingMode: SharingMode.Exclusive,
47         };
48         return new Buffer(VDevice(), bufferInfo);
49     }
50 
51     private Image createImage(int width, int height) {
52         Image.CreateInfo imageInfo = {
53             imageType: ImageType.Type2D,
54             extent: {
55                 width: width,
56                 height: height,
57                 depth: 1
58             },
59             mipLevels: 1,
60             arrayLayers: 1,
61             format: VK_FORMAT_R8G8B8A8_UNORM,
62             tiling: ImageTiling.Optimal,
63             initialLayout: ImageLayout.Undefined,
64             usage: ImageUsage.TransferDst | ImageUsage.Sampled,
65             sharingMode: SharingMode.Exclusive,
66             samples: SampleCount.Count1
67         };
68         return new Image(VDevice(), imageInfo);
69     }
70 
71     private ImageView createImageView(Image image) {
72         ImageView.CreateInfo imageViewInfo = {
73             image: image,
74             viewType: ImageViewType.Type2D,
75             format: VK_FORMAT_R8G8B8A8_UNORM,
76             subresourceRange: {
77                 aspectMask: ImageAspect.Color,
78                 baseMipLevel: 0,
79                 levelCount: 1,
80                 baseArrayLayer: 0,
81                 layerCount: 1
82             },
83             components: {
84                 r: ComponentSwizzle.B,
85                 g: ComponentSwizzle.G,
86                 b: ComponentSwizzle.R,
87                 a: ComponentSwizzle.A,
88             }
89         };
90         return new ImageView(VDevice(), imageViewInfo);
91     }
92 
93     private Sampler createSampler() {
94         Sampler.CreateInfo samplerInfo = {
95             magFilter: SamplerFilter.Linear,
96             minFilter: SamplerFilter.Linear,
97             addressModeU: SamplerAddressMode.Repeat,
98             addressModeV: SamplerAddressMode.Repeat,
99             addressModeW: SamplerAddressMode.Repeat,
100             anisotropyEnable: false,
101             maxAnisotropy: 1,
102             borderColor: BorderColor.IntOpaqueBlack,
103             unnormalizedCoordinates: false,
104             compareEnable: false,
105             compareOp: CompareOp.Always,
106             mipmapMode: SamplerMipmapMode.Linear,
107             mipLodBias: 0.0f,
108             minLod: 0.0f,
109             maxLod: 0.0f
110         };
111         return new Sampler(VDevice(), samplerInfo);
112     }
113 
114     private void transferData(Buffer src, Image dst) {
115         auto commandBuffer = VCommandBuffer.allocate(VCommandBuffer.Type.Graphics);
116         scope (exit)
117             commandBuffer.destroy();
118 
119         with (commandBuffer(CommandBuffer.BeginInfo.Flags.OneTimeSubmit)) {
120             VkImageMemoryBarrier barrier = {
121                 dstAccessMask: AccessFlags.TransferWrite,
122                 oldLayout: ImageLayout.Undefined,
123                 newLayout: ImageLayout.TransferDstOptimal,
124                 image: dst.image,
125                 subresourceRange: {
126                     aspectMask: ImageAspect.Color,
127                     baseMipLevel: 0,
128                     levelCount: 1,
129                     baseArrayLayer: 0,
130                     layerCount: 1
131                 }
132             };
133             cmdPipelineBarrier(PipelineStage.TopOfPipe, PipelineStage.Transfer, 0, null, null, [barrier]);
134 
135             VkBufferImageCopy bufferImageCopy = {
136                 bufferOffset: 0,
137                 bufferRowLength: 0,
138                 bufferImageHeight: 0,
139                 imageSubresource: {
140                     aspectMask: ImageAspect.Color,
141                     mipLevel: 0,
142                     baseArrayLayer: 0,
143                     layerCount: 1,
144                 },
145                 imageOffset: {
146                     x: 0,
147                     y: 0,
148                     z: 0,
149                 },
150                 imageExtent: {
151                     width: width,
152                     height: height,
153                     depth: 1
154                 }
155             };
156             cmdCopyBufferToImage(src, dst, ImageLayout.TransferDstOptimal, [bufferImageCopy]);
157 
158             VkImageMemoryBarrier barrier2 = {
159                 oldLayout: ImageLayout.TransferDstOptimal,
160                 newLayout: ImageLayout.ShaderReadOnlyOptimal,
161                 image: dst.image,
162                 subresourceRange: {
163                     aspectMask: ImageAspect.Color,
164                     baseMipLevel: 0,
165                     levelCount: 1,
166                     baseArrayLayer: 0,
167                     layerCount: 1
168                 }
169             };
170             cmdPipelineBarrier(PipelineStage.Transfer, PipelineStage.FragmentShader, 0, null, null, [barrier2]);
171         
172         }
173 
174         auto fence = VQueue(VQueue.Type.Graphics).submitWithFence(commandBuffer, "FileTexture.transferData");
175         fence.wait();
176         fence.destroy();
177     }
178 
179     uint width() const {
180         return _width;
181     }
182 
183     uint height() const {
184         return _height;
185     }
186 
187     override ImageView imageView() {
188         return _imageView;
189     }
190 
191     override Sampler sampler() {
192         return _sampler;
193     }
194 }