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 }