1 // Copyright 2021 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "Util.hpp"
16 #include "SPIRV/GlslangToSpv.h"
17 #include "glslang/Public/ResourceLimits.h"
18
19 #include <memory>
20
21 namespace Util {
22
getMemoryTypeIndex(vk::PhysicalDevice physicalDevice,uint32_t typeBits,vk::MemoryPropertyFlags properties)23 uint32_t getMemoryTypeIndex(vk::PhysicalDevice physicalDevice, uint32_t typeBits, vk::MemoryPropertyFlags properties)
24 {
25 vk::PhysicalDeviceMemoryProperties deviceMemoryProperties = physicalDevice.getMemoryProperties();
26 for(uint32_t i = 0; i < deviceMemoryProperties.memoryTypeCount; i++)
27 {
28 if((typeBits & 1) == 1)
29 {
30 if((deviceMemoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
31 {
32 return i;
33 }
34 }
35 typeBits >>= 1;
36 }
37
38 assert(false);
39 return -1;
40 }
41
beginSingleTimeCommands(vk::Device device,vk::CommandPool commandPool)42 vk::CommandBuffer beginSingleTimeCommands(vk::Device device, vk::CommandPool commandPool)
43 {
44 vk::CommandBufferAllocateInfo allocInfo{};
45 allocInfo.level = vk::CommandBufferLevel::ePrimary;
46 allocInfo.commandPool = commandPool;
47 allocInfo.commandBufferCount = 1;
48
49 auto commandBuffer = device.allocateCommandBuffers(allocInfo);
50
51 vk::CommandBufferBeginInfo beginInfo{};
52 beginInfo.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit;
53
54 commandBuffer[0].begin(beginInfo);
55
56 return commandBuffer[0];
57 }
58
endSingleTimeCommands(vk::Device device,vk::CommandPool commandPool,vk::Queue queue,vk::CommandBuffer commandBuffer)59 void endSingleTimeCommands(vk::Device device, vk::CommandPool commandPool, vk::Queue queue, vk::CommandBuffer commandBuffer)
60 {
61 commandBuffer.end();
62
63 vk::SubmitInfo submitInfo{};
64 submitInfo.commandBufferCount = 1;
65 submitInfo.pCommandBuffers = &commandBuffer;
66
67 vk::Fence fence = {}; // TODO: pass in fence?
68 queue.submit(1, &submitInfo, fence);
69 queue.waitIdle();
70
71 device.freeCommandBuffers(commandPool, 1, &commandBuffer);
72 }
73
transitionImageLayout(vk::Device device,vk::CommandPool commandPool,vk::Queue queue,vk::Image image,vk::Format format,vk::ImageLayout oldLayout,vk::ImageLayout newLayout)74 void transitionImageLayout(vk::Device device, vk::CommandPool commandPool, vk::Queue queue, vk::Image image, vk::Format format, vk::ImageLayout oldLayout, vk::ImageLayout newLayout)
75 {
76 vk::CommandBuffer commandBuffer = beginSingleTimeCommands(device, commandPool);
77
78 vk::ImageMemoryBarrier barrier{};
79 barrier.oldLayout = oldLayout;
80 barrier.newLayout = newLayout;
81 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
82 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
83 barrier.image = image;
84 barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
85 barrier.subresourceRange.baseMipLevel = 0;
86 barrier.subresourceRange.levelCount = 1;
87 barrier.subresourceRange.baseArrayLayer = 0;
88 barrier.subresourceRange.layerCount = 1;
89
90 vk::PipelineStageFlags sourceStage;
91 vk::PipelineStageFlags destinationStage;
92
93 if(oldLayout == vk::ImageLayout::eUndefined && newLayout == vk::ImageLayout::eTransferDstOptimal)
94 {
95 barrier.srcAccessMask = {};
96 barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite;
97
98 sourceStage = vk::PipelineStageFlagBits::eTopOfPipe;
99 destinationStage = vk::PipelineStageFlagBits::eTransfer;
100 }
101 else if(oldLayout == vk::ImageLayout::eTransferDstOptimal && newLayout == vk::ImageLayout::eShaderReadOnlyOptimal)
102 {
103 barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
104 barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead;
105
106 sourceStage = vk::PipelineStageFlagBits::eTransfer;
107 destinationStage = vk::PipelineStageFlagBits::eFragmentShader;
108 }
109 else
110 {
111 assert(false && "unsupported layout transition!");
112 }
113
114 commandBuffer.pipelineBarrier(sourceStage, destinationStage, vk::DependencyFlags{}, 0, nullptr, 0, nullptr, 1, &barrier);
115
116 endSingleTimeCommands(device, commandPool, queue, commandBuffer);
117 }
118
copyBufferToImage(vk::Device device,vk::CommandPool commandPool,vk::Queue queue,vk::Buffer buffer,vk::Image image,uint32_t width,uint32_t height)119 void copyBufferToImage(vk::Device device, vk::CommandPool commandPool, vk::Queue queue, vk::Buffer buffer, vk::Image image, uint32_t width, uint32_t height)
120 {
121 vk::CommandBuffer commandBuffer = beginSingleTimeCommands(device, commandPool);
122
123 vk::BufferImageCopy region{};
124 region.bufferOffset = 0;
125 region.bufferRowLength = 0;
126 region.bufferImageHeight = 0;
127 region.imageSubresource.aspectMask = vk::ImageAspectFlagBits::eColor;
128 region.imageSubresource.mipLevel = 0;
129 region.imageSubresource.baseArrayLayer = 0;
130 region.imageSubresource.layerCount = 1;
131 region.imageOffset = vk::Offset3D{ 0, 0, 0 };
132 region.imageExtent = vk::Extent3D{ width, height, 1 };
133
134 commandBuffer.copyBufferToImage(buffer, image, vk::ImageLayout::eTransferDstOptimal, 1, ®ion);
135
136 endSingleTimeCommands(device, commandPool, queue, commandBuffer);
137 }
138
compileGLSLtoSPIRV(const char * glslSource,EShLanguage glslLanguage)139 std::vector<uint32_t> compileGLSLtoSPIRV(const char *glslSource, EShLanguage glslLanguage)
140 {
141 // glslang requires one-time initialization.
142 const struct GlslangProcessInitialiser
143 {
144 GlslangProcessInitialiser() { glslang::InitializeProcess(); }
145 ~GlslangProcessInitialiser() { glslang::FinalizeProcess(); }
146 } glslangInitialiser;
147
148 std::unique_ptr<glslang::TShader> glslangShader = std::make_unique<glslang::TShader>(glslLanguage);
149
150 glslangShader->setStrings(&glslSource, 1);
151 glslangShader->setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_1);
152 glslangShader->setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_3);
153
154 const int defaultVersion = 100;
155 EShMessages messages = static_cast<EShMessages>(EShMessages::EShMsgDefault | EShMessages::EShMsgSpvRules | EShMessages::EShMsgVulkanRules);
156 bool parseResult = glslangShader->parse(GetDefaultResources(), defaultVersion, false, messages);
157
158 if(!parseResult)
159 {
160 std::string debugLog = glslangShader->getInfoDebugLog();
161 std::string infoLog = glslangShader->getInfoLog();
162 assert(false && "Failed to parse shader");
163 }
164
165 glslang::TIntermediate *intermediateRepresentation = glslangShader->getIntermediate();
166 assert(intermediateRepresentation);
167
168 std::vector<uint32_t> spirv;
169 glslang::SpvOptions options;
170 glslang::GlslangToSpv(*intermediateRepresentation, spirv, &options);
171 assert(spirv.size() != 0);
172
173 return spirv;
174 }
175
176 } // namespace Util
177