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 }