void prepareUniformBuffers() { // Prepare and initialize uniform buffer containing shader uniforms VkMemoryRequirements memReqs; // Vertex shader uniform buffer block VkBufferCreateInfo bufferInfo = {}; VkMemoryAllocateInfo allocInfo = vkTools::initializers::memoryAllocateInfo(); VkResult err; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = sizeof(computeUbo); bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; err = vkCreateBuffer(device, &bufferInfo, nullptr, &uniformDataCompute.buffer); assert(!err); vkGetBufferMemoryRequirements(device, uniformDataCompute.buffer, &memReqs); allocInfo.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &allocInfo.memoryTypeIndex); err = vkAllocateMemory(device, &allocInfo, nullptr, &(uniformDataCompute.memory)); assert(!err); err = vkBindBufferMemory(device, uniformDataCompute.buffer, uniformDataCompute.memory, 0); assert(!err); uniformDataCompute.descriptor.buffer = uniformDataCompute.buffer; uniformDataCompute.descriptor.offset = 0; uniformDataCompute.descriptor.range = sizeof(computeUbo); updateUniformBuffers(); }
static uint32_t getMemoryType(vk::PhysicalDevice& device, uint32_t typeBits, const vk::MemoryPropertyFlags& properties) { uint32_t result = 0; if (!getMemoryType(device, typeBits, properties, &result)) { // todo : throw error } return result; }
// Create a buffer for storing the query result // Setup a query pool void setupQueryResultBuffer() { uint32_t bufSize = 2 * sizeof(uint64_t); VkMemoryRequirements memReqs; VkMemoryAllocateInfo memAlloc = vkTools::initializers::memoryAllocateInfo(); VkBufferCreateInfo bufferCreateInfo = vkTools::initializers::bufferCreateInfo( VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, bufSize); VkResult err = vkCreateBuffer(device, &bufferCreateInfo, nullptr, &queryResult.buffer); assert(!err); vkGetBufferMemoryRequirements(device, queryResult.buffer, &memReqs); memAlloc.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAlloc.memoryTypeIndex); err = vkAllocateMemory(device, &memAlloc, nullptr, &queryResult.memory); assert(!err); err = vkBindBufferMemory(device, queryResult.buffer, queryResult.memory, 0); assert(!err); // Create query pool VkQueryPoolCreateInfo queryPoolInfo = {}; queryPoolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; queryPoolInfo.queryType = VK_QUERY_TYPE_OCCLUSION; queryPoolInfo.queryCount = 2; err = vkCreateQueryPool(device, &queryPoolInfo, NULL, &queryPool); assert(!err); }
VkBool32 VulkanExampleBase::createBuffer( VkBufferUsageFlags usage, VkDeviceSize size, void * data, VkBuffer *buffer, VkDeviceMemory *memory) { VkMemoryRequirements memReqs; VkMemoryAllocateInfo memAlloc = vkTools::initializers::memoryAllocateInfo(); VkBufferCreateInfo bufferCreateInfo = vkTools::initializers::bufferCreateInfo(usage, size); VkResult err = vkCreateBuffer(device, &bufferCreateInfo, nullptr, buffer); assert(!err); vkGetBufferMemoryRequirements(device, *buffer, &memReqs); memAlloc.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAlloc.memoryTypeIndex); err = vkAllocateMemory(device, &memAlloc, nullptr, memory); assert(!err); if (data != nullptr) { void *mapped; err = vkMapMemory(device, *memory, 0, size, 0, &mapped); assert(!err); memcpy(mapped, data, size); vkUnmapMemory(device, *memory); } err = vkBindBufferMemory(device, *buffer, *memory, 0); assert(!err); return true; }
/** * Create a buffer on the device * * @param usageFlags Usage flag bitmask for the buffer (i.e. index, vertex, uniform buffer) * @param memoryPropertyFlags Memory properties for this buffer (i.e. device local, host visible, coherent) * @param size Size of the buffer in byes * @param buffer Pointer to the buffer handle acquired by the function * @param memory Pointer to the memory handle acquired by the function * @param data Pointer to the data that should be copied to the buffer after creation (optional, if not set, no data is copied over) * * @return VK_SUCCESS if buffer handle and memory have been created and (optionally passed) data has been copied */ VkResult createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, VkBuffer *buffer, VkDeviceMemory *memory, void *data = nullptr) { // Create the buffer handle VkBufferCreateInfo bufferCreateInfo = vkTools::initializers::bufferCreateInfo(usageFlags, size); bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; VK_CHECK_RESULT(vkCreateBuffer(logicalDevice, &bufferCreateInfo, nullptr, buffer)); // Create the memory backing up the buffer handle VkMemoryRequirements memReqs; VkMemoryAllocateInfo memAlloc = vkTools::initializers::memoryAllocateInfo(); vkGetBufferMemoryRequirements(logicalDevice, *buffer, &memReqs); memAlloc.allocationSize = memReqs.size; // Find a memory type index that fits the properties of the buffer memAlloc.memoryTypeIndex = getMemoryType(memReqs.memoryTypeBits, memoryPropertyFlags); VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAlloc, nullptr, memory)); // If a pointer to the buffer data has been passed, map the buffer and copy over the data if (data != nullptr) { void *mapped; VK_CHECK_RESULT(vkMapMemory(logicalDevice, *memory, 0, size, 0, &mapped)); memcpy(mapped, data, size); vkUnmapMemory(logicalDevice, *memory); } // Attach the memory to the buffer object VK_CHECK_RESULT(vkBindBufferMemory(logicalDevice, *buffer, *memory, 0)); return VK_SUCCESS; }
void VulkanExampleBase::setupDepthStencil() { VkImageCreateInfo image = {}; image.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image.pNext = NULL; image.imageType = VK_IMAGE_TYPE_2D; image.format = depthFormat; image.extent = { width, height, 1 }; image.mipLevels = 1; image.arrayLayers = 1; image.samples = VK_SAMPLE_COUNT_1_BIT; image.tiling = VK_IMAGE_TILING_OPTIMAL; image.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; image.flags = 0; VkMemoryAllocateInfo mem_alloc = {}; mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; mem_alloc.pNext = NULL; mem_alloc.allocationSize = 0; mem_alloc.memoryTypeIndex = 0; VkImageViewCreateInfo depthStencilView = {}; depthStencilView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; depthStencilView.pNext = NULL; depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; depthStencilView.format = depthFormat; depthStencilView.flags = 0; depthStencilView.subresourceRange = {}; depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; depthStencilView.subresourceRange.baseMipLevel = 0; depthStencilView.subresourceRange.levelCount = 1; depthStencilView.subresourceRange.baseArrayLayer = 0; depthStencilView.subresourceRange.layerCount = 1; VkMemoryRequirements memReqs; VkResult err; err = vkCreateImage(device, &image, nullptr, &depthStencil.image); assert(!err); vkGetImageMemoryRequirements(device, depthStencil.image, &memReqs); mem_alloc.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &mem_alloc.memoryTypeIndex); err = vkAllocateMemory(device, &mem_alloc, nullptr, &depthStencil.mem); assert(!err); err = vkBindImageMemory(device, depthStencil.image, depthStencil.mem, 0); assert(!err); vkTools::setImageLayout( setupCmdBuffer, depthStencil.image, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); depthStencilView.image = depthStencil.image; err = vkCreateImageView(device, &depthStencilView, nullptr, &depthStencil.view); assert(!err); }
void prepareUniformBuffers() { // Prepare and initialize uniform buffer containing shader uniforms VkMemoryRequirements memReqs; // Vertex shader uniform buffer block VkBufferCreateInfo bufferInfo = {}; VkMemoryAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocInfo.pNext = NULL; allocInfo.allocationSize = 0; allocInfo.memoryTypeIndex = 0; VkResult err; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = sizeof(uboVS); bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; // Create a new buffer err = vkCreateBuffer(device, &bufferInfo, nullptr, &uniformDataVS.buffer); assert(!err); // Get memory requirements including size, alignment and memory type vkGetBufferMemoryRequirements(device, uniformDataVS.buffer, &memReqs); allocInfo.allocationSize = memReqs.size; // Gets the appropriate memory type for this type of buffer allocation // Only memory types that are visible to the host getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &allocInfo.memoryTypeIndex); // Allocate memory for the uniform buffer err = vkAllocateMemory(device, &allocInfo, nullptr, &(uniformDataVS.memory)); assert(!err); // Bind memory to buffer err = vkBindBufferMemory(device, uniformDataVS.buffer, uniformDataVS.memory, 0); assert(!err); // Store information in the uniform's descriptor uniformDataVS.descriptor.buffer = uniformDataVS.buffer; uniformDataVS.descriptor.offset = 0; uniformDataVS.descriptor.range = sizeof(uboVS); updateUniformBuffers(); }
VkBool32 VulkanExampleBase::createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, void * data, VkBuffer * buffer, VkDeviceMemory * memory) { VkMemoryRequirements memReqs; VkMemoryAllocateInfo memAlloc = vkTools::initializers::memoryAllocateInfo(); VkBufferCreateInfo bufferCreateInfo = vkTools::initializers::bufferCreateInfo(usageFlags, size); vkTools::checkResult(vkCreateBuffer(device, &bufferCreateInfo, nullptr, buffer)); vkGetBufferMemoryRequirements(device, *buffer, &memReqs); memAlloc.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, memoryPropertyFlags, &memAlloc.memoryTypeIndex); vkTools::checkResult(vkAllocateMemory(device, &memAlloc, nullptr, memory)); if (data != nullptr) { void *mapped; vkTools::checkResult(vkMapMemory(device, *memory, 0, size, 0, &mapped)); memcpy(mapped, data, size); vkUnmapMemory(device, *memory); } vkTools::checkResult(vkBindBufferMemory(device, *buffer, *memory, 0)); return true; }
/** * Create a buffer on the device * * @param usageFlags Usage flag bitmask for the buffer (i.e. index, vertex, uniform buffer) * @param memoryPropertyFlags Memory properties for this buffer (i.e. device local, host visible, coherent) * @param buffer Pointer to a vk::Vulkan buffer object * @param size Size of the buffer in byes * @param data Pointer to the data that should be copied to the buffer after creation (optional, if not set, no data is copied over) * * @return VK_SUCCESS if buffer handle and memory have been created and (optionally passed) data has been copied */ VkResult createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, vk::Buffer *buffer, VkDeviceSize size, void *data = nullptr) { buffer->device = logicalDevice; // Create the buffer handle VkBufferCreateInfo bufferCreateInfo = vkTools::initializers::bufferCreateInfo(usageFlags, size); VK_CHECK_RESULT(vkCreateBuffer(logicalDevice, &bufferCreateInfo, nullptr, &buffer->buffer)); // Create the memory backing up the buffer handle VkMemoryRequirements memReqs; VkMemoryAllocateInfo memAlloc = vkTools::initializers::memoryAllocateInfo(); vkGetBufferMemoryRequirements(logicalDevice, buffer->buffer, &memReqs); memAlloc.allocationSize = memReqs.size; // Find a memory type index that fits the properties of the buffer memAlloc.memoryTypeIndex = getMemoryType(memReqs.memoryTypeBits, memoryPropertyFlags); VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAlloc, nullptr, &buffer->memory)); buffer->alignment = memReqs.alignment; buffer->size = memAlloc.allocationSize; buffer->usageFlags = usageFlags; buffer->memoryPropertyFlags = memoryPropertyFlags; // If a pointer to the buffer data has been passed, map the buffer and copy over the data if (data != nullptr) { VK_CHECK_RESULT(buffer->map()); memcpy(buffer->mapped, data, size); buffer->unmap(); } // Initialize a default descriptor that covers the whole buffer size buffer->setupDescriptor(); // Attach the memory to the buffer object return buffer->bind(); }
// Creates a multi sample render target (image and view) that is used to resolve // into the visible frame buffer target in the render pass void setupMultisampleTarget() { // Check if device supports requested sample count for color and depth frame buffer assert((deviceProperties.limits.framebufferColorSampleCounts >= SAMPLE_COUNT) && (deviceProperties.limits.framebufferDepthSampleCounts >= SAMPLE_COUNT)); // Color target VkImageCreateInfo info = vkTools::initializers::imageCreateInfo(); info.imageType = VK_IMAGE_TYPE_2D; info.format = colorformat; info.extent.width = width; info.extent.height = height; info.extent.depth = 1; info.mipLevels = 1; info.arrayLayers = 1; info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; info.tiling = VK_IMAGE_TILING_OPTIMAL; info.samples = SAMPLE_COUNT; // Image will only be used as a transient target info.usage = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; vkTools::checkResult(vkCreateImage(device, &info, nullptr, &multisampleTarget.color.image)); VkMemoryRequirements memReqs; vkGetImageMemoryRequirements(device, multisampleTarget.color.image, &memReqs); VkMemoryAllocateInfo memAlloc = vkTools::initializers::memoryAllocateInfo(); memAlloc.allocationSize = memReqs.size; // We prefer a lazily allocated memory type // This means that the memory get allocated when the implementation sees fit, e.g. when first using the images VkBool32 lazyMemType = getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT, &memAlloc.memoryTypeIndex); if (!lazyMemType) { // If this is not available, fall back to device local memory getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAlloc.memoryTypeIndex); } vkTools::checkResult(vkAllocateMemory(device, &memAlloc, nullptr, &multisampleTarget.color.memory)); vkBindImageMemory(device, multisampleTarget.color.image, multisampleTarget.color.memory, 0); // Create image view for the MSAA target VkImageViewCreateInfo viewInfo = vkTools::initializers::imageViewCreateInfo(); viewInfo.image = multisampleTarget.color.image; viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; viewInfo.format = colorformat; viewInfo.components.r = VK_COMPONENT_SWIZZLE_R; viewInfo.components.g = VK_COMPONENT_SWIZZLE_G; viewInfo.components.b = VK_COMPONENT_SWIZZLE_B; viewInfo.components.a = VK_COMPONENT_SWIZZLE_A; viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; viewInfo.subresourceRange.levelCount = 1; viewInfo.subresourceRange.layerCount = 1; vkTools::checkResult(vkCreateImageView(device, &viewInfo, nullptr, &multisampleTarget.color.view)); // Depth target info.imageType = VK_IMAGE_TYPE_2D; info.format = depthFormat; info.extent.width = width; info.extent.height = height; info.extent.depth = 1; info.mipLevels = 1; info.arrayLayers = 1; info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; info.tiling = VK_IMAGE_TILING_OPTIMAL; info.samples = SAMPLE_COUNT; // Image will only be used as a transient target info.usage = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; vkTools::checkResult(vkCreateImage(device, &info, nullptr, &multisampleTarget.depth.image)); vkGetImageMemoryRequirements(device, multisampleTarget.depth.image, &memReqs); memAlloc = vkTools::initializers::memoryAllocateInfo(); memAlloc.allocationSize = memReqs.size; lazyMemType = getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT, &memAlloc.memoryTypeIndex); if (!lazyMemType) { getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAlloc.memoryTypeIndex); } vkTools::checkResult(vkAllocateMemory(device, &memAlloc, nullptr, &multisampleTarget.depth.memory)); vkBindImageMemory(device, multisampleTarget.depth.image, multisampleTarget.depth.memory, 0); // Create image view for the MSAA target viewInfo.image = multisampleTarget.depth.image; viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; viewInfo.format = depthFormat; viewInfo.components.r = VK_COMPONENT_SWIZZLE_R; viewInfo.components.g = VK_COMPONENT_SWIZZLE_G; viewInfo.components.b = VK_COMPONENT_SWIZZLE_B; viewInfo.components.a = VK_COMPONENT_SWIZZLE_A; viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; viewInfo.subresourceRange.levelCount = 1; viewInfo.subresourceRange.layerCount = 1; vkTools::checkResult(vkCreateImageView(device, &viewInfo, nullptr, &multisampleTarget.depth.view)); }
// Preapre an empty texture as the blit target from // the offscreen framebuffer void prepareTextureTarget(uint32_t width, uint32_t height, VkFormat format) { createSetupCommandBuffer(); VkResult err; // Get device properites for the requested texture format VkFormatProperties formatProperties; vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProperties); // Check if format is supported for optimal tiling assert(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT); // Prepare blit target texture offScreenFrameBuf.textureTarget.width = width; offScreenFrameBuf.textureTarget.height = height; VkImageCreateInfo imageCreateInfo = vkTools::initializers::imageCreateInfo(); imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; imageCreateInfo.format = format; imageCreateInfo.extent = { width, height, 1 }; imageCreateInfo.mipLevels = 1; imageCreateInfo.arrayLayers = 1; imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; imageCreateInfo.flags = 0; imageCreateInfo.pQueueFamilyIndices = 0; imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; VkMemoryAllocateInfo memAllocInfo = vkTools::initializers::memoryAllocateInfo(); VkMemoryRequirements memReqs; err = vkCreateImage(device, &imageCreateInfo, nullptr, &offScreenFrameBuf.textureTarget.image); assert(!err); vkGetImageMemoryRequirements(device, offScreenFrameBuf.textureTarget.image, &memReqs); memAllocInfo.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAllocInfo.memoryTypeIndex); err = vkAllocateMemory(device, &memAllocInfo, nullptr, &offScreenFrameBuf.textureTarget.deviceMemory); assert(!err); err = vkBindImageMemory(device, offScreenFrameBuf.textureTarget.image, offScreenFrameBuf.textureTarget.deviceMemory, 0); assert(!err); offScreenFrameBuf.textureTarget.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; vkTools::setImageLayout( setupCmdBuffer, offScreenFrameBuf.textureTarget.image, VK_IMAGE_ASPECT_DEPTH_BIT, VK_IMAGE_LAYOUT_UNDEFINED, offScreenFrameBuf.textureTarget.imageLayout); // Create sampler VkSamplerCreateInfo sampler = vkTools::initializers::samplerCreateInfo(); sampler.magFilter = TEX_FILTER; sampler.minFilter = TEX_FILTER; sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; sampler.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler.addressModeV = sampler.addressModeU; sampler.addressModeW = sampler.addressModeU; sampler.mipLodBias = 0.0f; sampler.maxAnisotropy = 0; sampler.minLod = 0.0f; sampler.maxLod = 0.0f; sampler.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; err = vkCreateSampler(device, &sampler, nullptr, &offScreenFrameBuf.textureTarget.sampler); assert(!err); // Create image view VkImageViewCreateInfo view = {}; view.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; view.pNext = NULL; view.viewType = VK_IMAGE_VIEW_TYPE_2D; view.format = format; view.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; view.subresourceRange = { VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1 }; view.image = offScreenFrameBuf.textureTarget.image; err = vkCreateImageView(device, &view, nullptr, &offScreenFrameBuf.textureTarget.view); assert(!err); flushSetupCommandBuffer(); }
bool PublisherExtractor::start() { auto thread_function = [this]() { MemoryExtractor* extractor = nullptr; DeviceBase* device = source_publisher_->getDevice(); if (device) { device->threadInit(); } while(true) { DataBuffer* source_buffer = nullptr; if (queued_buffer_) { source_buffer = queued_buffer_; queued_buffer_ = nullptr; } else { source_buffer = source_subscription_->pull(); } if (nullptr == source_buffer) { break; } if (source_buffer->simulation_step < start_step_) { source_buffer->release(); } else { queued_buffer_ = source_buffer; break; } } while(true) { Mailbox mailbox; DataBuffer* source_buffer = nullptr; if (queued_buffer_) { source_buffer = queued_buffer_; queued_buffer_ = nullptr; } else { source_subscription_->pull(&source_buffer, &mailbox); } ReportDataBuffer* destination_buffer = nullptr; destination_subscription_->pull(&destination_buffer, &mailbox); if (!mailbox.wait(&source_buffer, &destination_buffer)) { source_subscription_->cancel(); destination_subscription_->cancel(); if (source_buffer) { source_buffer->release(); } if (destination_buffer) { destination_buffer->release(); } delete source_subscription_; source_subscription_ = nullptr; delete destination_subscription_; destination_subscription_ = nullptr; break; } if (source_buffer->simulation_step > end_step_) { source_buffer->release(); destination_buffer->release(); break; } auto signal = this->getBlank(); auto pin = source_buffer->getPin(pin_name_); if (nullptr == extractor) { switch(pin.getMemoryType()) { case DeviceType::CPU: switch(datatype_) { case DataType::Float: extractor = new CPUExtractor<float>(indices_); break; case DataType::Integer: extractor = new CPUExtractor<int>(indices_); break; case DataType::Bit: extractor = new CPUExtractor<Bit>(indices_); break; } break; #ifdef NCS_CUDA case DeviceType::CUDA: switch(datatype_) { case DataType::Float: extractor = new CUDAExtractor<float>(indices_); break; case DataType::Integer: extractor = new CUDAExtractor<int>(indices_); break; case DataType::Bit: extractor = new CUDAExtractor<Bit>(indices_); break; } break; #endif // NCS_CUDA default: break; } } char* dest = static_cast<char*>(destination_buffer->getData()) + output_offset_; extractor->extract(pin.getData(), dest); source_buffer->release(); destination_buffer->release(); auto num_subscribers = this->publish(signal); if (0 == num_subscribers) { break; } } if (device) { device->threadDestroy(); } delete source_subscription_; source_subscription_ = nullptr; delete destination_subscription_; destination_subscription_ = nullptr; this->clearSubscriptions(); if (extractor) { delete extractor; } }; thread_ = std::thread(thread_function); return true; }
// Setup and fill the compute shader storage buffers for // vertex positions and velocities void prepareStorageBuffers() { float destPosX = 0.0f; float destPosY = 0.0f; // Initial particle positions std::vector<Particle> particleBuffer; for (int i = 0; i < PARTICLE_COUNT; ++i) { // Position float aspectRatio = (float)height / (float)width; float rndVal = (float)rand() / (float)(RAND_MAX / (360.0f * 3.14f * 2.0f)); float rndRad = (float)rand() / (float)(RAND_MAX) * 0.5f; Particle p; p.pos = glm::vec4( destPosX + cos(rndVal) * rndRad * aspectRatio, destPosY + sin(rndVal) * rndRad, 0.0f, 1.0f); p.col = glm::vec4( (float)(rand() % 255) / 255.0f, (float)(rand() % 255) / 255.0f, (float)(rand() % 255) / 255.0f, 1.0f); p.vel = glm::vec4(0.0f); particleBuffer.push_back(p); } // Buffer size is the same for all storage buffers uint32_t storageBufferSize = particleBuffer.size() * sizeof(Particle); VkMemoryAllocateInfo memAlloc = vkTools::initializers::memoryAllocateInfo(); VkMemoryRequirements memReqs; VkResult err; void *data; struct StagingBuffer { VkDeviceMemory memory; VkBuffer buffer; } stagingBuffer; // Allocate and fill host-visible staging storage buffer object // Allocate and fill storage buffer object VkBufferCreateInfo vBufferInfo = vkTools::initializers::bufferCreateInfo( VK_BUFFER_USAGE_TRANSFER_SRC_BIT, storageBufferSize); vkTools::checkResult(vkCreateBuffer(device, &vBufferInfo, nullptr, &stagingBuffer.buffer)); vkGetBufferMemoryRequirements(device, stagingBuffer.buffer, &memReqs); memAlloc.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAlloc.memoryTypeIndex); vkTools::checkResult(vkAllocateMemory(device, &memAlloc, nullptr, &stagingBuffer.memory)); vkTools::checkResult(vkMapMemory(device, stagingBuffer.memory, 0, storageBufferSize, 0, &data)); memcpy(data, particleBuffer.data(), storageBufferSize); vkUnmapMemory(device, stagingBuffer.memory); vkTools::checkResult(vkBindBufferMemory(device, stagingBuffer.buffer, stagingBuffer.memory, 0)); // Allocate device local storage buffer ojbect vBufferInfo.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; vkTools::checkResult(vkCreateBuffer(device, &vBufferInfo, nullptr, &computeStorageBuffer.buffer)); vkGetBufferMemoryRequirements(device, computeStorageBuffer.buffer, &memReqs); memAlloc.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAlloc.memoryTypeIndex); vkTools::checkResult(vkAllocateMemory(device, &memAlloc, nullptr, &computeStorageBuffer.memory)); vkTools::checkResult(vkBindBufferMemory(device, computeStorageBuffer.buffer, computeStorageBuffer.memory, 0)); // Copy from host to device createSetupCommandBuffer(); VkBufferCopy copyRegion = {}; copyRegion.size = storageBufferSize; vkCmdCopyBuffer( setupCmdBuffer, stagingBuffer.buffer, computeStorageBuffer.buffer, 1, ©Region); flushSetupCommandBuffer(); // Destroy staging buffer vkDestroyBuffer(device, stagingBuffer.buffer, nullptr); vkFreeMemory(device, stagingBuffer.memory, nullptr); computeStorageBuffer.descriptor.buffer = computeStorageBuffer.buffer; computeStorageBuffer.descriptor.offset = 0; computeStorageBuffer.descriptor.range = storageBufferSize; // Binding description vertices.bindingDescriptions.resize(1); vertices.bindingDescriptions[0] = vkTools::initializers::vertexInputBindingDescription( VERTEX_BUFFER_BIND_ID, sizeof(Particle), VK_VERTEX_INPUT_RATE_VERTEX); // Attribute descriptions // Describes memory layout and shader positions vertices.attributeDescriptions.resize(2); // Location 0 : Position vertices.attributeDescriptions[0] = vkTools::initializers::vertexInputAttributeDescription( VERTEX_BUFFER_BIND_ID, 0, VK_FORMAT_R32G32B32A32_SFLOAT, 0); // Location 1 : Color vertices.attributeDescriptions[1] = vkTools::initializers::vertexInputAttributeDescription( VERTEX_BUFFER_BIND_ID, 1, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(float) * 4); // Assign to vertex buffer vertices.inputState = vkTools::initializers::pipelineVertexInputStateCreateInfo(); vertices.inputState.vertexBindingDescriptionCount = vertices.bindingDescriptions.size(); vertices.inputState.pVertexBindingDescriptions = vertices.bindingDescriptions.data(); vertices.inputState.vertexAttributeDescriptionCount = vertices.attributeDescriptions.size(); vertices.inputState.pVertexAttributeDescriptions = vertices.attributeDescriptions.data(); }
void loadTextureArray(std::string filename, VkFormat format) { #if defined(__ANDROID__) // Textures are stored inside the apk on Android (compressed) // So they need to be loaded via the asset manager AAsset* asset = AAssetManager_open(androidApp->activity->assetManager, filename.c_str(), AASSET_MODE_STREAMING); assert(asset); size_t size = AAsset_getLength(asset); assert(size > 0); void *textureData = malloc(size); AAsset_read(asset, textureData, size); AAsset_close(asset); gli::texture2DArray tex2DArray(gli::load((const char*)textureData, size)); #else gli::texture2DArray tex2DArray(gli::load(filename)); #endif assert(!tex2DArray.empty()); textureArray.width = tex2DArray.dimensions().x; textureArray.height = tex2DArray.dimensions().y; layerCount = tex2DArray.layers(); // Get device properites for the requested texture format VkFormatProperties formatProperties; vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProperties); VkImageCreateInfo imageCreateInfo = vkTools::initializers::imageCreateInfo(); imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; imageCreateInfo.format = format; imageCreateInfo.extent = { textureArray.width, textureArray.height, 1 }; imageCreateInfo.mipLevels = 1; imageCreateInfo.arrayLayers = 1; imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageCreateInfo.tiling = VK_IMAGE_TILING_LINEAR; imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; imageCreateInfo.flags = 0; VkMemoryAllocateInfo memAllocInfo = vkTools::initializers::memoryAllocateInfo(); VkMemoryRequirements memReqs; struct Layer { VkImage image; VkDeviceMemory memory; }; std::vector<Layer> arrayLayer; arrayLayer.resize(layerCount); // Allocate command buffer for image copies and layouts VkCommandBuffer cmdBuffer; VkCommandBufferAllocateInfo cmdBufAlllocatInfo = vkTools::initializers::commandBufferAllocateInfo( cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1); VkResult err = vkAllocateCommandBuffers(device, &cmdBufAlllocatInfo, &cmdBuffer); assert(!err); VkCommandBufferBeginInfo cmdBufInfo = vkTools::initializers::commandBufferBeginInfo(); err = vkBeginCommandBuffer(cmdBuffer, &cmdBufInfo); assert(!err); // Load separate cube map faces into linear tiled textures for (uint32_t i = 0; i < layerCount; ++i) { err = vkCreateImage(device, &imageCreateInfo, nullptr, &arrayLayer[i].image); assert(!err); vkGetImageMemoryRequirements(device, arrayLayer[i].image, &memReqs); memAllocInfo.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAllocInfo.memoryTypeIndex); err = vkAllocateMemory(device, &memAllocInfo, nullptr, &arrayLayer[i].memory); assert(!err); err = vkBindImageMemory(device, arrayLayer[i].image, arrayLayer[i].memory, 0); assert(!err); VkImageSubresource subRes = {}; subRes.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; VkSubresourceLayout subResLayout; void *data; vkGetImageSubresourceLayout(device, arrayLayer[i].image, &subRes, &subResLayout); assert(!err); err = vkMapMemory(device, arrayLayer[i].memory, 0, memReqs.size, 0, &data); assert(!err); memcpy(data, tex2DArray[i].data(), tex2DArray[i].size()); vkUnmapMemory(device, arrayLayer[i].memory); // Image barrier for linear image (base) // Linear image will be used as a source for the copy vkTools::setImageLayout( cmdBuffer, arrayLayer[i].image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); } // Transfer cube map faces to optimal tiling // Setup texture as blit target with optimal tiling imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; imageCreateInfo.arrayLayers = layerCount; err = vkCreateImage(device, &imageCreateInfo, nullptr, &textureArray.image); assert(!err); vkGetImageMemoryRequirements(device, textureArray.image, &memReqs); memAllocInfo.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAllocInfo.memoryTypeIndex); err = vkAllocateMemory(device, &memAllocInfo, nullptr, &textureArray.deviceMemory); assert(!err); err = vkBindImageMemory(device, textureArray.image, textureArray.deviceMemory, 0); assert(!err); // Image barrier for optimal image (target) // Set initial layout for all array layers of the optimal (target) tiled texture VkImageSubresourceRange subresourceRange = {}; subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; subresourceRange.baseMipLevel = 0; subresourceRange.levelCount = 1; subresourceRange.layerCount = layerCount; vkTools::setImageLayout( cmdBuffer, textureArray.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, subresourceRange); // Copy cube map faces one by one for (uint32_t i = 0; i < layerCount; ++i) { // Copy region for image blit VkImageCopy copyRegion = {}; copyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copyRegion.srcSubresource.baseArrayLayer = 0; copyRegion.srcSubresource.mipLevel = 0; copyRegion.srcSubresource.layerCount = 1; copyRegion.srcOffset = { 0, 0, 0 }; copyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copyRegion.dstSubresource.baseArrayLayer = i; copyRegion.dstSubresource.mipLevel = 0; copyRegion.dstSubresource.layerCount = 1; copyRegion.dstOffset = { 0, 0, 0 }; copyRegion.extent.width = textureArray.width; copyRegion.extent.height = textureArray.height; copyRegion.extent.depth = 1; // Put image copy into command buffer vkCmdCopyImage( cmdBuffer, arrayLayer[i].image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, textureArray.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region); } // Change texture image layout to shader read after all layers have been copied textureArray.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; vkTools::setImageLayout( cmdBuffer, textureArray.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, textureArray.imageLayout, subresourceRange); err = vkEndCommandBuffer(cmdBuffer); assert(!err); VkFence nullFence = { VK_NULL_HANDLE }; // Submit command buffer to graphis queue VkSubmitInfo submitInfo = vkTools::initializers::submitInfo(); submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &cmdBuffer; err = vkQueueSubmit(queue, 1, &submitInfo, nullFence); assert(!err); err = vkQueueWaitIdle(queue); assert(!err); // Create sampler VkSamplerCreateInfo sampler = vkTools::initializers::samplerCreateInfo(); sampler.magFilter = VK_FILTER_LINEAR; sampler.minFilter = VK_FILTER_LINEAR; sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; sampler.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler.addressModeV = sampler.addressModeU; sampler.addressModeW = sampler.addressModeU; sampler.mipLodBias = 0.0f; sampler.maxAnisotropy = 8; sampler.compareOp = VK_COMPARE_OP_NEVER; sampler.minLod = 0.0f; sampler.maxLod = 0.0f; sampler.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; err = vkCreateSampler(device, &sampler, nullptr, &textureArray.sampler); assert(!err); // Create image view VkImageViewCreateInfo view = vkTools::initializers::imageViewCreateInfo(); view.image = VK_NULL_HANDLE; view.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; view.format = format; view.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; view.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; view.subresourceRange.layerCount = layerCount; view.image = textureArray.image; err = vkCreateImageView(device, &view, nullptr, &textureArray.view); assert(!err); // Cleanup for (auto& layer : arrayLayer) { vkDestroyImage(device, layer.image, nullptr); vkFreeMemory(device, layer.memory, nullptr); } }
void loadTexture(const char* fileName, VkFormat format, bool forceLinearTiling) { VkFormatProperties formatProperties; VkResult err; AAsset* asset = AAssetManager_open(app->activity->assetManager, fileName, AASSET_MODE_STREAMING); assert(asset); size_t size = AAsset_getLength(asset); assert(size > 0); void *textureData = malloc(size); AAsset_read(asset, textureData, size); AAsset_close(asset); gli::texture2D tex2D(gli::load((const char*)textureData, size)); assert(!tex2D.empty()); texture.width = tex2D[0].dimensions().x; texture.height = tex2D[0].dimensions().y; texture.mipLevels = tex2D.levels(); // Get device properites for the requested texture format vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProperties); // Only use linear tiling if requested (and supported by the device) // Support for linear tiling is mostly limited, so prefer to use // optimal tiling instead // On most implementations linear tiling will only support a very // limited amount of formats and features (mip maps, cubemaps, arrays, etc.) VkBool32 useStaging = true; // Only use linear tiling if forced if (forceLinearTiling) { // Don't use linear if format is not supported for (linear) shader sampling useStaging = !(formatProperties.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT); } VkImageCreateInfo imageCreateInfo = vkTools::initializers::imageCreateInfo(); imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; imageCreateInfo.format = format; imageCreateInfo.mipLevels = 1; imageCreateInfo.arrayLayers = 1; imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageCreateInfo.tiling = VK_IMAGE_TILING_LINEAR; imageCreateInfo.usage = (useStaging) ? VK_IMAGE_USAGE_TRANSFER_SRC_BIT : VK_IMAGE_USAGE_SAMPLED_BIT; imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageCreateInfo.flags = 0; imageCreateInfo.extent = { texture.width, texture.height, 1 }; VkMemoryAllocateInfo memAllocInfo = vkTools::initializers::memoryAllocateInfo(); VkMemoryRequirements memReqs; startSetupCommandBuffer(); if (useStaging) { // Load all available mip levels into linear textures // and copy to optimal tiling target struct MipLevel { VkImage image; VkDeviceMemory memory; }; std::vector<MipLevel> mipLevels; mipLevels.resize(texture.mipLevels); // Copy mip levels for (uint32_t level = 0; level < texture.mipLevels; ++level) { imageCreateInfo.extent.width = tex2D[level].dimensions().x; imageCreateInfo.extent.height = tex2D[level].dimensions().y; imageCreateInfo.extent.depth = 1; err = vkCreateImage(device, &imageCreateInfo, nullptr, &mipLevels[level].image); assert(!err); vkGetImageMemoryRequirements(device, mipLevels[level].image, &memReqs); memAllocInfo.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAllocInfo.memoryTypeIndex); err = vkAllocateMemory(device, &memAllocInfo, nullptr, &mipLevels[level].memory); assert(!err); err = vkBindImageMemory(device, mipLevels[level].image, mipLevels[level].memory, 0); assert(!err); VkImageSubresource subRes = {}; subRes.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; VkSubresourceLayout subResLayout; void *data; vkGetImageSubresourceLayout(device, mipLevels[level].image, &subRes, &subResLayout); assert(!err); err = vkMapMemory(device, mipLevels[level].memory, 0, memReqs.size, 0, &data); assert(!err); size_t levelSize = tex2D[level].size(); memcpy(data, tex2D[level].data(), levelSize); vkUnmapMemory(device, mipLevels[level].memory); LOGW("setImageLayout %d", 1); // Image barrier for linear image (base) // Linear image will be used as a source for the copy vkTools::setImageLayout( setupCmdBuffer, mipLevels[level].image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); } // Setup texture as blit target with optimal tiling imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; imageCreateInfo.mipLevels = texture.mipLevels; imageCreateInfo.extent = { texture.width, texture.height, 1 }; err = vkCreateImage(device, &imageCreateInfo, nullptr, &texture.image); assert(!err); vkGetImageMemoryRequirements(device, texture.image, &memReqs); memAllocInfo.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAllocInfo.memoryTypeIndex); err = vkAllocateMemory(device, &memAllocInfo, nullptr, &texture.deviceMemory); assert(!err); err = vkBindImageMemory(device, texture.image, texture.deviceMemory, 0); assert(!err); // Image barrier for optimal image (target) // Optimal image will be used as destination for the copy vkTools::setImageLayout( setupCmdBuffer, texture.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); // Copy mip levels one by one for (uint32_t level = 0; level < texture.mipLevels; ++level) { // Copy region for image blit VkImageCopy copyRegion = {}; copyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copyRegion.srcSubresource.baseArrayLayer = 0; copyRegion.srcSubresource.mipLevel = 0; copyRegion.srcSubresource.layerCount = 1; copyRegion.srcOffset = { 0, 0, 0 }; copyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copyRegion.dstSubresource.baseArrayLayer = 0; // Set mip level to copy the linear image to copyRegion.dstSubresource.mipLevel = level; copyRegion.dstSubresource.layerCount = 1; copyRegion.dstOffset = { 0, 0, 0 }; copyRegion.extent.width = tex2D[level].dimensions().x; copyRegion.extent.height = tex2D[level].dimensions().y; copyRegion.extent.depth = 1; // Put image copy into command buffer vkCmdCopyImage( setupCmdBuffer, mipLevels[level].image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, texture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region); // Change texture image layout to shader read after the copy texture.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; vkTools::setImageLayout( setupCmdBuffer, texture.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, texture.imageLayout); } // Clean up linear images // No longer required after mip levels // have been transformed over to optimal tiling for (auto& level : mipLevels) { vkDestroyImage(device, level.image, nullptr); vkFreeMemory(device, level.memory, nullptr); } } else { // Prefer using optimal tiling, as linear tiling // may support only a small set of features // depending on implementation (e.g. no mip maps, only one layer, etc.) VkImage mappableImage; VkDeviceMemory mappableMemory; // Load mip map level 0 to linear tiling image err = vkCreateImage(device, &imageCreateInfo, nullptr, &mappableImage); assert(!err); // Get memory requirements for this image // like size and alignment vkGetImageMemoryRequirements(device, mappableImage, &memReqs); // Set memory allocation size to required memory size memAllocInfo.allocationSize = memReqs.size; // Get memory type that can be mapped to host memory getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAllocInfo.memoryTypeIndex); // Allocate host memory err = vkAllocateMemory(device, &memAllocInfo, nullptr, &mappableMemory); assert(!err); // Bind allocated image for use err = vkBindImageMemory(device, mappableImage, mappableMemory, 0); assert(!err); // Get sub resource layout // Mip map count, array layer, etc. VkImageSubresource subRes = {}; subRes.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; VkSubresourceLayout subResLayout; void *data; // Get sub resources layout // Includes row pitch, size offsets, etc. vkGetImageSubresourceLayout(device, mappableImage, &subRes, &subResLayout); assert(!err); // Map image memory err = vkMapMemory(device, mappableMemory, 0, memReqs.size, 0, &data); assert(!err); // Copy image data into memory memcpy(data, tex2D[subRes.mipLevel].data(), tex2D[subRes.mipLevel].size()); vkUnmapMemory(device, mappableMemory); // Linear tiled images don't need to be staged // and can be directly used as textures texture.image = mappableImage; texture.deviceMemory = mappableMemory; texture.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; // Setup image memory barrier vkTools::setImageLayout( setupCmdBuffer, texture.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, texture.imageLayout); } flushSetupCommandBuffer(); // Create sampler // In Vulkan textures are accessed by samplers // This separates all the sampling information from the // texture data // This means you could have multiple sampler objects // for the same texture with different settings // Similar to the samplers available with OpenGL 3.3 VkSamplerCreateInfo sampler = vkTools::initializers::samplerCreateInfo(); sampler.magFilter = VK_FILTER_LINEAR; sampler.minFilter = VK_FILTER_LINEAR; sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; sampler.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler.addressModeV = sampler.addressModeU; sampler.addressModeW = sampler.addressModeU; sampler.mipLodBias = 0.0f; sampler.compareOp = VK_COMPARE_OP_NEVER; sampler.minLod = 0.0f; // Max level-of-detail should match mip level count sampler.maxLod = (useStaging) ? (float)texture.mipLevels : 0.0f; // Enable anisotropic filtering sampler.maxAnisotropy = 8; sampler.anisotropyEnable = VK_TRUE; sampler.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; err = vkCreateSampler(device, &sampler, nullptr, &texture.sampler); assert(!err); // Create image view // Textures are not directly accessed by the shaders and // are abstracted by image views containing additional // information and sub resource ranges VkImageViewCreateInfo view = vkTools::initializers::imageViewCreateInfo(); view.image = VK_NULL_HANDLE; view.viewType = VK_IMAGE_VIEW_TYPE_2D; view.format = format; view.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; view.subresourceRange.baseMipLevel = 0; view.subresourceRange.baseArrayLayer = 0; view.subresourceRange.layerCount = 1; // Linear tiling usually won't support mip maps // Only set mip map count if optimal tiling is used view.subresourceRange.levelCount = (useStaging) ? texture.mipLevels : 1; view.image = texture.image; err = vkCreateImageView(device, &view, nullptr, &texture.view); assert(!err); }
void prepareOffscreenFramebuffer() { createSetupCommandBuffer(); offScreenFrameBuf.width = FB_DIM; offScreenFrameBuf.height = FB_DIM; VkFormat fbColorFormat = FB_COLOR_FORMAT; VkResult err; // Color attachment VkImageCreateInfo image = vkTools::initializers::imageCreateInfo(); image.imageType = VK_IMAGE_TYPE_2D; image.format = fbColorFormat; image.extent.width = offScreenFrameBuf.width; image.extent.height = offScreenFrameBuf.height; image.mipLevels = 1; image.arrayLayers = 1; image.samples = VK_SAMPLE_COUNT_1_BIT; image.tiling = VK_IMAGE_TILING_OPTIMAL; // Image of the framebuffer is blit source image.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; image.flags = 0; VkMemoryAllocateInfo memAlloc = vkTools::initializers::memoryAllocateInfo(); VkImageViewCreateInfo colorImageView = vkTools::initializers::imageViewCreateInfo(); colorImageView.viewType = VK_IMAGE_VIEW_TYPE_2D; colorImageView.format = fbColorFormat; colorImageView.flags = 0; colorImageView.subresourceRange = {}; colorImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; colorImageView.subresourceRange.baseMipLevel = 0; colorImageView.subresourceRange.levelCount = 1; colorImageView.subresourceRange.baseArrayLayer = 0; colorImageView.subresourceRange.layerCount = 1; VkMemoryRequirements memReqs; err = vkCreateImage(device, &image, nullptr, &offScreenFrameBuf.color.image); assert(!err); vkGetImageMemoryRequirements(device, offScreenFrameBuf.color.image, &memReqs); memAlloc.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAlloc.memoryTypeIndex); err = vkAllocateMemory(device, &memAlloc, nullptr, &offScreenFrameBuf.color.mem); assert(!err); err = vkBindImageMemory(device, offScreenFrameBuf.color.image, offScreenFrameBuf.color.mem, 0); assert(!err); vkTools::setImageLayout( setupCmdBuffer, offScreenFrameBuf.color.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); colorImageView.image = offScreenFrameBuf.color.image; err = vkCreateImageView(device, &colorImageView, nullptr, &offScreenFrameBuf.color.view); assert(!err); // Depth stencil attachment image.format = DEPTH_FORMAT; image.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; VkImageViewCreateInfo depthStencilView = vkTools::initializers::imageViewCreateInfo(); depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; depthStencilView.format = DEPTH_FORMAT; depthStencilView.flags = 0; depthStencilView.subresourceRange = {}; depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; depthStencilView.subresourceRange.baseMipLevel = 0; depthStencilView.subresourceRange.levelCount = 1; depthStencilView.subresourceRange.baseArrayLayer = 0; depthStencilView.subresourceRange.layerCount = 1; err = vkCreateImage(device, &image, nullptr, &offScreenFrameBuf.depth.image); assert(!err); vkGetImageMemoryRequirements(device, offScreenFrameBuf.depth.image, &memReqs); memAlloc.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAlloc.memoryTypeIndex); err = vkAllocateMemory(device, &memAlloc, nullptr, &offScreenFrameBuf.depth.mem); assert(!err); err = vkBindImageMemory(device, offScreenFrameBuf.depth.image, offScreenFrameBuf.depth.mem, 0); assert(!err); vkTools::setImageLayout( setupCmdBuffer, offScreenFrameBuf.depth.image, VK_IMAGE_ASPECT_DEPTH_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); depthStencilView.image = offScreenFrameBuf.depth.image; err = vkCreateImageView(device, &depthStencilView, nullptr, &offScreenFrameBuf.depth.view); assert(!err); VkImageView attachments[2]; attachments[0] = offScreenFrameBuf.color.view; attachments[1] = offScreenFrameBuf.depth.view; VkFramebufferCreateInfo fbufCreateInfo = {}; fbufCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; fbufCreateInfo.pNext = NULL; fbufCreateInfo.renderPass = renderPass; fbufCreateInfo.attachmentCount = 2; fbufCreateInfo.pAttachments = attachments; fbufCreateInfo.width = offScreenFrameBuf.width; fbufCreateInfo.height = offScreenFrameBuf.height; fbufCreateInfo.layers = 1; err = vkCreateFramebuffer(device, &fbufCreateInfo, nullptr, &offScreenFrameBuf.frameBuffer); assert(!err); flushSetupCommandBuffer(); }
void prepareVertices() { // Setup vertices std::vector<Vertex> vertexBuffer; vertexBuffer.push_back({ { 1.0f, 1.0f, 0.0f },{ 1.0f, 1.0f } }); vertexBuffer.push_back({ { -1.0f, 1.0f, 0.0f },{ 0.0f, 1.0f } }); vertexBuffer.push_back({ { -1.0f, -1.0f, 0.0f },{ 0.0f, 0.0f } }); vertexBuffer.push_back({ { 1.0f, -1.0f, 0.0f },{ 1.0f, 0.0f } }); int vertexBufferSize = vertexBuffer.size() * sizeof(Vertex); // Setup indices std::vector<uint32_t> indexBuffer; indexBuffer.push_back(0); indexBuffer.push_back(1); indexBuffer.push_back(2); indexBuffer.push_back(2); indexBuffer.push_back(3); indexBuffer.push_back(0); int indexBufferSize = indexBuffer.size() * sizeof(uint32_t); VkMemoryAllocateInfo memAlloc = {}; memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; memAlloc.pNext = NULL; memAlloc.allocationSize = 0; memAlloc.memoryTypeIndex = 0; VkMemoryRequirements memReqs; VkResult err; void *data; // Generate vertex buffer // Setup VkBufferCreateInfo bufInfo = {}; bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufInfo.pNext = NULL; bufInfo.size = vertexBufferSize; bufInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; bufInfo.flags = 0; // Copy vertex data to VRAM memset(&vertices, 0, sizeof(vertices)); err = vkCreateBuffer(device, &bufInfo, nullptr, &vertices.buf); assert(!err); vkGetBufferMemoryRequirements(device, vertices.buf, &memReqs); memAlloc.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAlloc.memoryTypeIndex); vkAllocateMemory(device, &memAlloc, nullptr, &vertices.mem); assert(!err); err = vkMapMemory(device, vertices.mem, 0, memAlloc.allocationSize, 0, &data); assert(!err); memcpy(data, vertexBuffer.data(), vertexBufferSize); vkUnmapMemory(device, vertices.mem); assert(!err); err = vkBindBufferMemory(device, vertices.buf, vertices.mem, 0); assert(!err); // Generate index buffer // Setup VkBufferCreateInfo indexbufferInfo = {}; indexbufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; indexbufferInfo.pNext = NULL; indexbufferInfo.size = indexBufferSize; indexbufferInfo.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT; indexbufferInfo.flags = 0; // Copy index data to VRAM memset(&indices, 0, sizeof(indices)); err = vkCreateBuffer(device, &bufInfo, nullptr, &indices.buf); assert(!err); vkGetBufferMemoryRequirements(device, indices.buf, &memReqs); memAlloc.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAlloc.memoryTypeIndex); err = vkAllocateMemory(device, &memAlloc, nullptr, &indices.mem); assert(!err); err = vkMapMemory(device, indices.mem, 0, indexBufferSize, 0, &data); assert(!err); memcpy(data, indexBuffer.data(), indexBufferSize); vkUnmapMemory(device, indices.mem); err = vkBindBufferMemory(device, indices.buf, indices.mem, 0); assert(!err); indices.count = indexBuffer.size(); // Binding description vertices.bindingDescriptions.resize(1); vertices.bindingDescriptions[0] = vkTools::initializers::vertexInputBindingDescription( VERTEX_BUFFER_BIND_ID, sizeof(Vertex), VK_VERTEX_INPUT_RATE_VERTEX); // Attribute descriptions // Describes memory layout and shader positions vertices.attributeDescriptions.resize(2); // Location 0 : Position vertices.attributeDescriptions[0] = vkTools::initializers::vertexInputAttributeDescription( VERTEX_BUFFER_BIND_ID, 0, VK_FORMAT_R32G32B32_SFLOAT, 0); // Location 1 : UV vertices.attributeDescriptions[1] = vkTools::initializers::vertexInputAttributeDescription( VERTEX_BUFFER_BIND_ID, 1, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 3); // Assign to vertex buffer vertices.inputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vertices.inputState.pNext = NULL; vertices.inputState.vertexBindingDescriptionCount = vertices.bindingDescriptions.size(); vertices.inputState.pVertexBindingDescriptions = vertices.bindingDescriptions.data(); vertices.inputState.vertexAttributeDescriptionCount = vertices.attributeDescriptions.size(); vertices.inputState.pVertexAttributeDescriptions = vertices.attributeDescriptions.data(); }
/* * 表示コマンド */ static UW display_command(B *command) { INT point=0; B cmd=0; T_RTST rtst; UB b; UH h; UW w, value1, value2; int no, count; char tstate[TSTATE_LEN]; count = sizeof(mon_display) / sizeof(struct SUBCOMMAND_TABLE); if(command[point]){ for(no = 0 ; no < count ; no++){ if(compare_word(mon_display[no].subcommand, command, 0)){ skip_word(command, &point); cmd = mon_display[no].type; break; } } } switch(cmd){ default: /* デフォルト */ cmd = mon_datatype; case MONDISPLAY_BYTE: /* バイト単位メモリ表示 */ case MONDISPLAY_HALF: /* ハーフ単位メモリ表示 */ case MONDISPLAY_WORD: /* ワード単位メモリ表示 */ value2 = 128; if(!get_value(command, &point, &value1, HEX_BASE)) value1 = mon_address; value1 = MonAlignAddress(value1); if(command[point] == '+'){ point++; if(!get_value(command, &point, &value2, HEX_BASE)) value2 = 128; } else{ if(!get_value(command, &point, &value2, HEX_BASE)) value2 = value1 + 128; value2 -= value1; } mon_datatype = cmd; while((W)value2 > 0){ printf("%08lx ", (long)value1); for(no = 0 ; no < 16 ; no += mon_datatype){ if(no == 8) putchar(' '); switch(mon_datatype){ case DATA_HALF: if(MemoryRead(value1+no, &h, 2) == 0) h = -1; printf("%04x ", h); break; case DATA_WORD: if(MemoryRead(value1+no, &w, 4) == 0) w = -1; printf("%08lx ", (long)w); break; default: if(MemoryRead(value1+no, &b, 1) == 0) b = -1; printf("%02x ", b); break; } } if(getMemoryType(value1+no, 0) == MEMORY_AREA){ for(no = 0 ; no < 16 ; no++){ if(MemoryRead(value1+no, &b, 1)){ if(b < ' ' || b >= 0xE0) b = '.'; else if(b >= 127 && b < 0xA0) b = '.'; } else b = '.'; putchar(b); } } putchar('\n'); value1 += 16; value2 -= 16; tslp_tsk(50); if(monitor_break()) value2 = 0; } mon_address = value1; break; case MONDISPLAY_TASK: /* タスク状態表示 */ printf("cur id pri state pc stack inistack inisize\n"); for(no = 0 ; no < tmax_tskid ; no++){ ref_tst(no+TMIN_TSKID, &rtst); if(current_tskid == (no+TMIN_TSKID)) printf(" * "); else printf(" "); if(MONTASK == (no+TMIN_TSKID)) printf(" mon"); else printf(" %03d", no+TMIN_TSKID); value1 = get_taskstate(rtst.tskstat); for(count = 0 ; count < TSTATE_LEN-1 ; count++){ if((tstate[count] = task_state[value1][count]) == 0) tstate[count] = ' '; } tstate[count] = 0; printf(" %3d %s", rtst.tskpri, (VP_INT)tstate); if(rtst.tskstat == TTS_RUN) printf(" "); else printf(" %08lx", (unsigned long)rtst.tskpc); printf(" %08lx %08lx %5ld\n", (unsigned long)rtst.tsksp, (unsigned long)rtst.inistk, (unsigned long)rtst.inistksz); } putchar('\n'); break; case MONDISPLAY_REG: /* レジスタの表示 */ if(current_tskid != MONTASK) display_registers(current_tskid); break; } return 0; }
void Model::create(const std::string& filepath) { std::ifstream fin(filepath.c_str(), std::ios::in | std::ios::binary); if (fin.is_open()) { ResHeader header = {}; fin.read(reinterpret_cast<char*>(&header), sizeof(header)); m_bindingDescriptions[0].binding = 0; m_bindingDescriptions[0].stride = sizeof(Vertex); m_bindingDescriptions[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; m_attributeDescriptions[0].binding = 0; m_attributeDescriptions[0].location = 0; m_attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT; m_attributeDescriptions[0].offset = 0; m_attributeDescriptions[1].binding = 0; m_attributeDescriptions[1].location = 1; m_attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT; m_attributeDescriptions[1].offset = sizeof(float) * 3; m_vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; m_vertexInputInfo.pNext = NULL; m_vertexInputInfo.flags = 0; m_vertexInputInfo.vertexBindingDescriptionCount = 1; m_vertexInputInfo.pVertexBindingDescriptions = &m_bindingDescriptions[0]; m_vertexInputInfo.vertexAttributeDescriptionCount = 2; m_vertexInputInfo.pVertexAttributeDescriptions = &m_attributeDescriptions[0]; std::unique_ptr<ResVec3> vertices; std::unique_ptr<ResFace> faces; vertices.reset(new ResVec3[header.numVerts]); faces.reset(new ResFace[header.numFaces]); fin.read(reinterpret_cast<char*>(vertices.get()), sizeof(ResVec3) * header.numVerts); fin.read(reinterpret_cast<char*>(faces.get()), sizeof(ResFace) * header.numFaces); { VkBufferCreateInfo bufInfo = {}; bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufInfo.pNext = NULL; bufInfo.size = getDeviceSize(sizeof(Vertex) * header.numVerts, 256); bufInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; bufInfo.flags = 0; auto err = vkCreateBuffer(getDevice(), &bufInfo, nullptr, &m_vertices.buffer); VkMemoryRequirements memReqs = {}; vkGetBufferMemoryRequirements(getDevice(), m_vertices.buffer, &memReqs); VkMemoryAllocateInfo memAlloc = {}; memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; memAlloc.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAlloc.memoryTypeIndex); err = vkAllocateMemory(getDevice(), &memAlloc, nullptr, &m_vertices.memory); Vertex* mapped = nullptr; err = vkMapMemory(getDevice(), m_vertices.memory, 0, bufInfo.size, 0, reinterpret_cast<void**>(&mapped)); for (uint32_t i = 0; i < header.numVerts; i++) { mapped[i].x = vertices.get()[i].x; mapped[i].y = vertices.get()[i].y; mapped[i].z = vertices.get()[i].z; mapped[i].nx = 0.0f; mapped[i].ny = 0.0f; mapped[i].nz = 0.0f; } for (uint32_t i = 0; i < header.numFaces; i++) { Vertex* p0 = &mapped[faces.get()[i].index[0]]; Vertex* p1 = &mapped[faces.get()[i].index[1]]; Vertex* p2 = &mapped[faces.get()[i].index[2]]; p0->nx += faces.get()[i].normal.x; p0->ny += faces.get()[i].normal.y; p0->nz += faces.get()[i].normal.z; p1->nx += faces.get()[i].normal.x; p1->ny += faces.get()[i].normal.y; p1->nz += faces.get()[i].normal.z; p2->nx += faces.get()[i].normal.x; p2->ny += faces.get()[i].normal.y; p2->nz += faces.get()[i].normal.z; } for (uint32_t i = 0; i < header.numVerts; i++) { glm::vec3 n(mapped[i].nx, mapped[i].ny, mapped[i].nz); n = glm::normalize(n); mapped[i].nx = n.x; mapped[i].ny = n.y; mapped[i].nz = n.z; } vkUnmapMemory(getDevice(), m_vertices.memory); vkBindBufferMemory(getDevice(), m_vertices.buffer, m_vertices.memory, 0); } { VkBufferCreateInfo bufInfo = {}; bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufInfo.pNext = NULL; bufInfo.size = getDeviceSize(sizeof(uint32_t) * header.numFaces * 3, 256); bufInfo.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT; bufInfo.flags = 0; auto err = vkCreateBuffer(getDevice(), &bufInfo, nullptr, &m_indices.buffer); VkMemoryRequirements memReqs = {}; vkGetBufferMemoryRequirements(getDevice(), m_indices.buffer, &memReqs); VkMemoryAllocateInfo memAlloc = {}; memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; memAlloc.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAlloc.memoryTypeIndex); err = vkAllocateMemory(getDevice(), &memAlloc, nullptr, &m_indices.memory); uint32_t* mapped = nullptr; err = vkMapMemory(getDevice(), m_indices.memory, 0, bufInfo.size, 0, reinterpret_cast<void**>(&mapped)); uint32_t index = 0; for (uint32_t i = 0; i < header.numFaces; i++) { mapped[index + 0] = faces.get()[i].index[0]; mapped[index + 1] = faces.get()[i].index[1]; mapped[index + 2] = faces.get()[i].index[2]; index += 3; } vkUnmapMemory(getDevice(), m_indices.memory); vkBindBufferMemory(getDevice(), m_indices.buffer, m_indices.memory, 0); m_indexCount = header.numFaces * 3; } fin.close(); } }
void prepareVertices() { // Load mesh from compressed asset AAsset* asset = AAssetManager_open(app->activity->assetManager, "models/vulkanlogo.obj", AASSET_MODE_STREAMING); assert(asset); size_t size = AAsset_getLength(asset); assert(size > 0); char *assetData = new char[size]; AAsset_read(asset, assetData, size); AAsset_close(asset); std::stringstream assetStream(assetData); std::vector<tinyobj::shape_t> shapes; std::vector<tinyobj::material_t> materials; std::string objerr; tinyobj::MaterialFileReader matFileReader(""); bool ret = tinyobj::LoadObj(shapes, materials, objerr, assetStream, matFileReader, true); LOGW("shapes %d", shapes.size()); // Setup vertices float scale = 0.025f; std::vector<Vertex> vertexBuffer; std::vector<uint32_t> indexBuffer; for (auto& shape : shapes) { // Vertices for (size_t i = 0; i < shape.mesh.positions.size() / 3; i++) { Vertex v; v.pos[0] = shape.mesh.positions[3 * i + 0] * scale; v.pos[1] = -shape.mesh.positions[3 * i + 1] * scale; v.pos[2] = shape.mesh.positions[3 * i + 2] * scale; v.normal[0] = shape.mesh.normals[3 * i + 0]; v.normal[1] = shape.mesh.normals[3 * i + 1]; v.normal[2] = shape.mesh.normals[3 * i + 2]; v.color = glm::vec3(1.0f, 0.0f, 0.0f); vertexBuffer.push_back(v); } // Indices for (size_t i = 0; i < shape.mesh.indices.size() / 3; i++) { indexBuffer.push_back(shape.mesh.indices[3 * i + 0]); indexBuffer.push_back(shape.mesh.indices[3 * i + 1]); indexBuffer.push_back(shape.mesh.indices[3 * i + 2]); } } uint32_t vertexBufferSize = vertexBuffer.size() * sizeof(Vertex); uint32_t indexBufferSize = indexBuffer.size() * sizeof(uint32_t); VkMemoryAllocateInfo memAlloc = {}; memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; memAlloc.pNext = NULL; memAlloc.allocationSize = 0; memAlloc.memoryTypeIndex = 0; VkMemoryRequirements memReqs; VkResult err; void *data; // Generate vertex buffer // Setup VkBufferCreateInfo bufInfo = {}; bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufInfo.pNext = NULL; bufInfo.size = vertexBufferSize; bufInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; bufInfo.flags = 0; // Copy vertex data to VRAM memset(&vertices, 0, sizeof(vertices)); err = vkCreateBuffer(device, &bufInfo, nullptr, &vertices.buf); assert(!err); vkGetBufferMemoryRequirements(device, vertices.buf, &memReqs); memAlloc.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAlloc.memoryTypeIndex); vkAllocateMemory(device, &memAlloc, nullptr, &vertices.mem); assert(!err); err = vkMapMemory(device, vertices.mem, 0, memAlloc.allocationSize, 0, &data); assert(!err); memcpy(data, vertexBuffer.data(), vertexBufferSize); vkUnmapMemory(device, vertices.mem); assert(!err); err = vkBindBufferMemory(device, vertices.buf, vertices.mem, 0); assert(!err); // Generate index buffer // Setup VkBufferCreateInfo indexbufferInfo = {}; indexbufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; indexbufferInfo.pNext = NULL; indexbufferInfo.size = indexBufferSize; indexbufferInfo.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT; indexbufferInfo.flags = 0; // Copy index data to VRAM memset(&indices, 0, sizeof(indices)); err = vkCreateBuffer(device, &bufInfo, nullptr, &indices.buf); assert(!err); vkGetBufferMemoryRequirements(device, indices.buf, &memReqs); memAlloc.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAlloc.memoryTypeIndex); err = vkAllocateMemory(device, &memAlloc, nullptr, &indices.mem); assert(!err); err = vkMapMemory(device, indices.mem, 0, indexBufferSize, 0, &data); assert(!err); memcpy(data, indexBuffer.data(), indexBufferSize); vkUnmapMemory(device, indices.mem); err = vkBindBufferMemory(device, indices.buf, indices.mem, 0); assert(!err); indices.count = indexBuffer.size(); // Binding description vertices.bindingDescriptions.resize(1); vertices.bindingDescriptions[0] = vkTools::initializers::vertexInputBindingDescription( VERTEX_BUFFER_BIND_ID, sizeof(Vertex), VK_VERTEX_INPUT_RATE_VERTEX); // Attribute descriptions // Describes memory layout and shader positions vertices.attributeDescriptions.resize(3); // Location 0 : Position vertices.attributeDescriptions[0] = vkTools::initializers::vertexInputAttributeDescription( VERTEX_BUFFER_BIND_ID, 0, VK_FORMAT_R32G32B32_SFLOAT, 0); // Location 1 : Normal vertices.attributeDescriptions[1] = vkTools::initializers::vertexInputAttributeDescription( VERTEX_BUFFER_BIND_ID, 1, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 3); // Location 2 : Color vertices.attributeDescriptions[2] = vkTools::initializers::vertexInputAttributeDescription( VERTEX_BUFFER_BIND_ID, 2, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 6); // Assign to vertex buffer vertices.inputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vertices.inputState.pNext = NULL; vertices.inputState.vertexBindingDescriptionCount = vertices.bindingDescriptions.size(); vertices.inputState.pVertexBindingDescriptions = vertices.bindingDescriptions.data(); vertices.inputState.vertexAttributeDescriptionCount = vertices.attributeDescriptions.size(); vertices.inputState.pVertexAttributeDescriptions = vertices.attributeDescriptions.data(); }
void loadTexture(const char* filename, VkFormat format, bool forceLinearTiling) { VkFormatProperties formatProperties; VkResult err; gli::textureCube texCube(gli::load(filename)); assert(!texCube.empty()); cubeMap.width = texCube[0].dimensions().x; cubeMap.height = texCube[0].dimensions().y; // Get device properites for the requested texture format vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProperties); VkImageCreateInfo imageCreateInfo = vkTools::initializers::imageCreateInfo(); imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; imageCreateInfo.format = format; imageCreateInfo.extent = { cubeMap.width, cubeMap.height, 1 }; imageCreateInfo.mipLevels = 1; imageCreateInfo.arrayLayers = 1; imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageCreateInfo.tiling = VK_IMAGE_TILING_LINEAR; imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; imageCreateInfo.flags = 0; VkMemoryAllocateInfo memAllocInfo = vkTools::initializers::memoryAllocateInfo(); VkMemoryRequirements memReqs; struct { VkImage image; VkDeviceMemory memory; } cubeFace[6]; // Allocate command buffer for image copies and layouts VkCommandBuffer cmdBuffer; VkCommandBufferAllocateInfo cmdBufAlllocatInfo = vkTools::initializers::commandBufferAllocateInfo( cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1); err = vkAllocateCommandBuffers(device, &cmdBufAlllocatInfo, &cmdBuffer); assert(!err); VkCommandBufferBeginInfo cmdBufInfo = vkTools::initializers::commandBufferBeginInfo(); err = vkBeginCommandBuffer(cmdBuffer, &cmdBufInfo); assert(!err); // Load separate cube map faces into linear tiled textures for (uint32_t face = 0; face < 6; ++face) { err = vkCreateImage(device, &imageCreateInfo, nullptr, &cubeFace[face].image); assert(!err); vkGetImageMemoryRequirements(device, cubeFace[face].image, &memReqs); memAllocInfo.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAllocInfo.memoryTypeIndex); err = vkAllocateMemory(device, &memAllocInfo, nullptr, &cubeFace[face].memory); assert(!err); err = vkBindImageMemory(device, cubeFace[face].image, cubeFace[face].memory, 0); assert(!err); VkImageSubresource subRes = {}; subRes.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; VkSubresourceLayout subResLayout; void *data; vkGetImageSubresourceLayout(device, cubeFace[face].image, &subRes, &subResLayout); assert(!err); err = vkMapMemory(device, cubeFace[face].memory, 0, memReqs.size, 0, &data); assert(!err); memcpy(data, texCube[face][subRes.mipLevel].data(), texCube[face][subRes.mipLevel].size()); vkUnmapMemory(device, cubeFace[face].memory); // Image barrier for linear image (base) // Linear image will be used as a source for the copy vkTools::setImageLayout( cmdBuffer, cubeFace[face].image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); } // Transfer cube map faces to optimal tiling // Setup texture as blit target with optimal tiling imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; imageCreateInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; imageCreateInfo.arrayLayers = 6; err = vkCreateImage(device, &imageCreateInfo, nullptr, &cubeMap.image); assert(!err); vkGetImageMemoryRequirements(device, cubeMap.image, &memReqs); memAllocInfo.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAllocInfo.memoryTypeIndex); err = vkAllocateMemory(device, &memAllocInfo, nullptr, &cubeMap.deviceMemory); assert(!err); err = vkBindImageMemory(device, cubeMap.image, cubeMap.deviceMemory, 0); assert(!err); // Image barrier for optimal image (target) // Optimal image will be used as destination for the copy // Set initial layout for all array layers of the optimal (target) tiled texture VkImageSubresourceRange subresourceRange = {}; subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; subresourceRange.baseMipLevel = 0; subresourceRange.levelCount = 1; subresourceRange.layerCount = 6; vkTools::setImageLayout( cmdBuffer, cubeMap.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, subresourceRange); // Copy cube map faces one by one for (uint32_t face = 0; face < 6; ++face) { // Copy region for image blit VkImageCopy copyRegion = {}; copyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copyRegion.srcSubresource.baseArrayLayer = 0; copyRegion.srcSubresource.mipLevel = 0; copyRegion.srcSubresource.layerCount = 1; copyRegion.srcOffset = { 0, 0, 0 }; copyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copyRegion.dstSubresource.baseArrayLayer = face; copyRegion.dstSubresource.mipLevel = 0; copyRegion.dstSubresource.layerCount = 1; copyRegion.dstOffset = { 0, 0, 0 }; copyRegion.extent.width = cubeMap.width; copyRegion.extent.height = cubeMap.height; copyRegion.extent.depth = 1; // Put image copy into command buffer vkCmdCopyImage( cmdBuffer, cubeFace[face].image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, cubeMap.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region); } // Change texture image layout to shader read after all faces have been copied cubeMap.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; vkTools::setImageLayout( cmdBuffer, cubeMap.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, cubeMap.imageLayout, subresourceRange); err = vkEndCommandBuffer(cmdBuffer); assert(!err); VkFence nullFence = { VK_NULL_HANDLE }; // Submit command buffer to graphis queue VkSubmitInfo submitInfo = vkTools::initializers::submitInfo(); submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &cmdBuffer; err = vkQueueSubmit(queue, 1, &submitInfo, nullFence); assert(!err); err = vkQueueWaitIdle(queue); assert(!err); // Create sampler VkSamplerCreateInfo sampler = vkTools::initializers::samplerCreateInfo(); sampler.magFilter = VK_FILTER_LINEAR; sampler.minFilter = VK_FILTER_LINEAR; sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; sampler.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler.addressModeV = sampler.addressModeU; sampler.addressModeW = sampler.addressModeU; sampler.mipLodBias = 0.0f; sampler.maxAnisotropy = 8; sampler.compareOp = VK_COMPARE_OP_NEVER; sampler.minLod = 0.0f; sampler.maxLod = 0.0f; sampler.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; err = vkCreateSampler(device, &sampler, nullptr, &cubeMap.sampler); assert(!err); // Create image view VkImageViewCreateInfo view = vkTools::initializers::imageViewCreateInfo(); view.image = VK_NULL_HANDLE; view.viewType = VK_IMAGE_VIEW_TYPE_CUBE; view.format = format; view.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; view.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; view.subresourceRange.layerCount = 6; view.image = cubeMap.image; err = vkCreateImageView(device, &view, nullptr, &cubeMap.view); assert(!err); // Cleanup for (auto& face : cubeFace) { vkDestroyImage(device, face.image, nullptr); vkFreeMemory(device, face.memory, nullptr); } }
void loadTextureArray(std::string filename, VkFormat format) { #if defined(__ANDROID__) // Textures are stored inside the apk on Android (compressed) // So they need to be loaded via the asset manager AAsset* asset = AAssetManager_open(androidApp->activity->assetManager, filename.c_str(), AASSET_MODE_STREAMING); assert(asset); size_t size = AAsset_getLength(asset); assert(size > 0); void *textureData = malloc(size); AAsset_read(asset, textureData, size); AAsset_close(asset); gli::texture2DArray tex2DArray(gli::load((const char*)textureData, size)); #else gli::texture2DArray tex2DArray(gli::load(filename)); #endif assert(!tex2DArray.empty()); textureArray.width = tex2DArray.dimensions().x; textureArray.height = tex2DArray.dimensions().y; layerCount = tex2DArray.layers(); VkMemoryAllocateInfo memAllocInfo = vkTools::initializers::memoryAllocateInfo(); VkMemoryRequirements memReqs; // Create a host-visible staging buffer that contains the raw image data VkBuffer stagingBuffer; VkDeviceMemory stagingMemory; VkBufferCreateInfo bufferCreateInfo = vkTools::initializers::bufferCreateInfo(); bufferCreateInfo.size = tex2DArray.size(); // This buffer is used as a transfer source for the buffer copy bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; vkTools::checkResult(vkCreateBuffer(device, &bufferCreateInfo, nullptr, &stagingBuffer)); // Get memory requirements for the staging buffer (alignment, memory type bits) vkGetBufferMemoryRequirements(device, stagingBuffer, &memReqs); memAllocInfo.allocationSize = memReqs.size; // Get memory type index for a host visible buffer memAllocInfo.memoryTypeIndex = getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); vkTools::checkResult(vkAllocateMemory(device, &memAllocInfo, nullptr, &stagingMemory)); vkTools::checkResult(vkBindBufferMemory(device, stagingBuffer, stagingMemory, 0)); // Copy texture data into staging buffer uint8_t *data; vkTools::checkResult(vkMapMemory(device, stagingMemory, 0, memReqs.size, 0, (void **)&data)); memcpy(data, tex2DArray.data(), tex2DArray.size()); vkUnmapMemory(device, stagingMemory); // Setup buffer copy regions for array layers std::vector<VkBufferImageCopy> bufferCopyRegions; uint32_t offset = 0; // Check if all array layers have the same dimesions bool sameDims = true; for (uint32_t layer = 0; layer < layerCount; layer++) { if (tex2DArray[layer].dimensions().x != textureArray.width || tex2DArray[layer].dimensions().y != textureArray.height) { sameDims = false; break; } } // If all layers of the texture array have the same dimensions, we only need to do one copy if (sameDims) { VkBufferImageCopy bufferCopyRegion = {}; bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; bufferCopyRegion.imageSubresource.mipLevel = 0; bufferCopyRegion.imageSubresource.baseArrayLayer = 0; bufferCopyRegion.imageSubresource.layerCount = layerCount; bufferCopyRegion.imageExtent.width = tex2DArray[0].dimensions().x; bufferCopyRegion.imageExtent.height = tex2DArray[0].dimensions().y; bufferCopyRegion.imageExtent.depth = 1; bufferCopyRegion.bufferOffset = offset; bufferCopyRegions.push_back(bufferCopyRegion); } else { // If dimensions differ, copy layer by layer and pass offsets for (uint32_t layer = 0; layer < layerCount; layer++) { VkBufferImageCopy bufferCopyRegion = {}; bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; bufferCopyRegion.imageSubresource.mipLevel = 0; bufferCopyRegion.imageSubresource.baseArrayLayer = layer; bufferCopyRegion.imageSubresource.layerCount = 1; bufferCopyRegion.imageExtent.width = tex2DArray[layer].dimensions().x; bufferCopyRegion.imageExtent.height = tex2DArray[layer].dimensions().y; bufferCopyRegion.imageExtent.depth = 1; bufferCopyRegion.bufferOffset = offset; bufferCopyRegions.push_back(bufferCopyRegion); offset += tex2DArray[layer].size(); } } // Create optimal tiled target image VkImageCreateInfo imageCreateInfo = vkTools::initializers::imageCreateInfo(); imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; imageCreateInfo.format = format; imageCreateInfo.mipLevels = 1; imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT; imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; imageCreateInfo.extent = { textureArray.width, textureArray.height, 1 }; imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; imageCreateInfo.arrayLayers = layerCount; VK_CHECK_RESULT(vkCreateImage(device, &imageCreateInfo, nullptr, &textureArray.image)); vkGetImageMemoryRequirements(device, textureArray.image, &memReqs); memAllocInfo.allocationSize = memReqs.size; memAllocInfo.memoryTypeIndex = getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &textureArray.deviceMemory)); VK_CHECK_RESULT(vkBindImageMemory(device, textureArray.image, textureArray.deviceMemory, 0)); VkCommandBuffer copyCmd = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); // Image barrier for optimal image (target) // Set initial layout for all array layers (faces) of the optimal (target) tiled texture VkImageSubresourceRange subresourceRange = {}; subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; subresourceRange.baseMipLevel = 0; subresourceRange.levelCount = 1; subresourceRange.layerCount = layerCount; vkTools::setImageLayout( copyCmd, textureArray.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, subresourceRange); // Copy the cube map faces from the staging buffer to the optimal tiled image vkCmdCopyBufferToImage( copyCmd, stagingBuffer, textureArray.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, bufferCopyRegions.size(), bufferCopyRegions.data() ); // Change texture image layout to shader read after all faces have been copied textureArray.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; vkTools::setImageLayout( copyCmd, textureArray.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, textureArray.imageLayout, subresourceRange); VulkanExampleBase::flushCommandBuffer(copyCmd, queue, true); // Create sampler VkSamplerCreateInfo sampler = vkTools::initializers::samplerCreateInfo(); sampler.magFilter = VK_FILTER_LINEAR; sampler.minFilter = VK_FILTER_LINEAR; sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; sampler.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler.addressModeV = sampler.addressModeU; sampler.addressModeW = sampler.addressModeU; sampler.mipLodBias = 0.0f; sampler.maxAnisotropy = 8; sampler.compareOp = VK_COMPARE_OP_NEVER; sampler.minLod = 0.0f; sampler.maxLod = 0.0f; sampler.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; VK_CHECK_RESULT(vkCreateSampler(device, &sampler, nullptr, &textureArray.sampler)); // Create image view VkImageViewCreateInfo view = vkTools::initializers::imageViewCreateInfo(); view.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; view.format = format; view.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; view.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; view.subresourceRange.layerCount = layerCount; view.image = textureArray.image; VK_CHECK_RESULT(vkCreateImageView(device, &view, nullptr, &textureArray.view)); // Clean up staging resources vkFreeMemory(device, stagingMemory, nullptr); vkDestroyBuffer(device, stagingBuffer, nullptr); }