Vulkan: Add simple manager for compute shaders that upload data to images.

This commit is contained in:
Henrik Rydgård 2017-12-11 11:26:05 +01:00 committed by Unknown W. Brackets
parent 360e138c2c
commit e6bec3e555
4 changed files with 189 additions and 4 deletions

View file

@ -141,7 +141,8 @@ std::vector<std::string> SamplerCache::DebugGetSamplerIDs() const {
TextureCacheVulkan::TextureCacheVulkan(Draw::DrawContext *draw, VulkanContext *vulkan)
: TextureCacheCommon(draw),
vulkan_(vulkan),
samplerCache_(vulkan) {
samplerCache_(vulkan),
upload_(vulkan) {
timesInvalidatedAllThisFrame_ = 0;
DeviceRestore(vulkan, draw);
SetupTextureDecoder();
@ -180,6 +181,8 @@ void TextureCacheVulkan::DeviceLost() {
if (samplerNearest_)
vulkan_->Delete().QueueDeleteSampler(samplerNearest_);
upload_.DeviceLost();
nextTexture_ = nullptr;
}
@ -200,6 +203,8 @@ void TextureCacheVulkan::DeviceRestore(VulkanContext *vulkan, Draw::DrawContext
samp.minFilter = VK_FILTER_NEAREST;
samp.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
vkCreateSampler(vulkan_->GetDevice(), &samp, nullptr, &samplerNearest_);
upload_.DeviceRestore(vulkan);
}
void TextureCacheVulkan::ReleaseTexture(TexCacheEntry *entry, bool delete_them) {

View file

@ -25,6 +25,7 @@
#include "Common/Vulkan/VulkanContext.h"
#include "GPU/Vulkan/TextureScalerVulkan.h"
#include "GPU/Common/TextureCacheCommon.h"
#include "GPU/Vulkan/VulkanUtil.h"
struct VirtualFramebuffer;
class FramebufferManagerVulkan;
@ -126,6 +127,8 @@ private:
VulkanDeviceAllocator *allocator_ = nullptr;
VulkanPushBuffer *push_ = nullptr;
VulkanComputeUploader upload_;
SamplerCache samplerCache_;
TextureScalerVulkan scaler;

View file

@ -51,17 +51,14 @@ void Vulkan2D::DestroyDeviceObjects() {
VkDevice device = vulkan_->GetDevice();
if (descriptorSetLayout_ != VK_NULL_HANDLE) {
vulkan_->Delete().QueueDeleteDescriptorSetLayout(descriptorSetLayout_);
descriptorSetLayout_ = VK_NULL_HANDLE;
}
if (pipelineLayout_ != VK_NULL_HANDLE) {
vulkan_->Delete().QueueDeletePipelineLayout(pipelineLayout_);
pipelineLayout_ = VK_NULL_HANDLE;
}
// pipelineBasicTex_ and pipelineBasicTex_ come from vulkan2D_.
if (pipelineCache_ != VK_NULL_HANDLE) {
vulkan_->Delete().QueueDeletePipelineCache(pipelineCache_);
pipelineCache_ = VK_NULL_HANDLE;
}
}
@ -401,3 +398,139 @@ VkShaderModule CompileShaderModule(VulkanContext *vulkan, VkShaderStageFlagBits
}
}
}
VulkanComputeUploader::VulkanComputeUploader(VulkanContext *vulkan) : vulkan_(vulkan), pipelines_(8) {
}
VulkanComputeUploader::~VulkanComputeUploader() {}
void VulkanComputeUploader::InitDeviceObjects() {
pipelineCache_ = vulkan_->CreatePipelineCache();
VkDescriptorSetLayoutBinding bindings[2] = {};
bindings[0].descriptorCount = 1;
bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
bindings[0].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
bindings[0].binding = 0;
bindings[1].descriptorCount = 1;
bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
bindings[1].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
bindings[1].binding = 1;
VkDevice device = vulkan_->GetDevice();
VkDescriptorSetLayoutCreateInfo dsl = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
dsl.bindingCount = 2;
dsl.pBindings = bindings;
VkResult res = vkCreateDescriptorSetLayout(device, &dsl, nullptr, &descriptorSetLayout_);
assert(VK_SUCCESS == res);
VkDescriptorPoolSize dpTypes[2];
dpTypes[0].descriptorCount = 300;
dpTypes[0].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
dpTypes[1].descriptorCount = 300;
dpTypes[1].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
VkDescriptorPoolCreateInfo dp = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
dp.flags = 0; // Don't want to mess around with individually freeing these, let's go fixed each frame and zap the whole array. Might try the dynamic approach later.
dp.maxSets = 300;
dp.pPoolSizes = dpTypes;
dp.poolSizeCount = ARRAY_SIZE(dpTypes);
for (int i = 0; i < ARRAY_SIZE(frameData_); i++) {
VkResult res = vkCreateDescriptorPool(vulkan_->GetDevice(), &dp, nullptr, &frameData_[i].descPool);
assert(VK_SUCCESS == res);
}
VkPushConstantRange push = {};
push.offset = 0;
push.size = 48;
push.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
VkPipelineLayoutCreateInfo pl = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
pl.pPushConstantRanges = &push;
pl.pushConstantRangeCount = 1;
pl.setLayoutCount = 1;
pl.pSetLayouts = &descriptorSetLayout_;
pl.flags = 0;
res = vkCreatePipelineLayout(device, &pl, nullptr, &pipelineLayout_);
assert(VK_SUCCESS == res);
}
void VulkanComputeUploader::DestroyDeviceObjects() {
for (int i = 0; i < ARRAY_SIZE(frameData_); i++) {
vulkan_->Delete().QueueDeleteDescriptorPool(frameData_[i].descPool);
}
if (descriptorSetLayout_) {
vulkan_->Delete().QueueDeleteDescriptorSetLayout(descriptorSetLayout_);
}
pipelines_.Iterate([&](const PipelineKey &key, VkPipeline pipeline) {
vulkan_->Delete().QueueDeletePipeline(pipeline);
});
pipelines_.Clear();
if (pipelineLayout_) {
vulkan_->Delete().QueueDeletePipelineLayout(pipelineLayout_);
}
if (pipelineCache_ != VK_NULL_HANDLE) {
vulkan_->Delete().QueueDeletePipelineCache(pipelineCache_);
}
}
VkDescriptorSet VulkanComputeUploader::GetDescriptorSet(VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range, VkImageView image) {
int curFrame = vulkan_->GetCurFrame();
FrameData *frame = &frameData_[curFrame];
VkDescriptorSet desc;
VkDescriptorSetAllocateInfo descAlloc = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
descAlloc.pSetLayouts = &descriptorSetLayout_;
descAlloc.descriptorPool = frame->descPool;
descAlloc.descriptorSetCount = 1;
VkResult result = vkAllocateDescriptorSets(vulkan_->GetDevice(), &descAlloc, &desc);
assert(result == VK_SUCCESS);
VkWriteDescriptorSet writes[2]{};
int n = 0;
VkDescriptorBufferInfo bufferInfo = {};
VkDescriptorImageInfo imageInfo = {};
bufferInfo.buffer = buffer;
bufferInfo.offset = offset;
bufferInfo.range = range;
writes[n].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writes[n].dstBinding = 0;
writes[n].pBufferInfo = &bufferInfo;
writes[n].descriptorCount = 1;
writes[n].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
writes[n].dstSet = desc;
n++;
imageInfo.imageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
imageInfo.imageView = image;
imageInfo.sampler = VK_NULL_HANDLE;
writes[n].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writes[n].dstBinding = 1;
writes[n].pImageInfo = &imageInfo;
writes[n].descriptorCount = 1;
writes[n].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
writes[n].dstSet = desc;
n++;
vkUpdateDescriptorSets(vulkan_->GetDevice(), n, writes, 0, nullptr);
return desc;
}
VkPipeline VulkanComputeUploader::GetPipeline(VkShaderModule cs) {
PipelineKey key{ cs };
VkPipeline pipeline = pipelines_.Get(key);
if (pipeline)
return pipeline;
VkComputePipelineCreateInfo pci{ VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO };
pci.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
pci.stage.module = cs;
pci.stage.pName = "main";
pci.layout = pipelineLayout_;
pci.flags = 0;
vkCreateComputePipelines(vulkan_->GetDevice(), pipelineCache_, 1, &pci, nullptr, &pipeline);
pipelines_.Insert(key, pipeline);
return pipeline;
}

View file

@ -20,6 +20,7 @@
#include <tuple>
#include <map>
#include "Common/Hashmaps.h"
#include "Common/Vulkan/VulkanContext.h"
#include "Common/Vulkan/VulkanLoader.h"
#include "Common/Vulkan/VulkanImage.h"
@ -124,5 +125,48 @@ private:
std::vector<VkPipeline> keptPipelines_;
};
// Manager for compute shaders that upload things (and those have two bindings: a storage buffer to read from and an image to write to).
class VulkanComputeUploader {
public:
VulkanComputeUploader(VulkanContext *vulkan);
~VulkanComputeUploader();
void DeviceLost() {
DestroyDeviceObjects();
}
void DeviceRestore(VulkanContext *vulkan) {
vulkan_ = vulkan;
InitDeviceObjects();
}
// Note: This doesn't cache. The descriptor is for immediate use only.
VkDescriptorSet GetDescriptorSet(VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range, VkImageView image);
// This of course caches though.
VkPipeline GetPipeline(VkShaderModule cs);
VkPipelineLayout GetPipelineLayout() const { return pipelineLayout_; }
private:
void InitDeviceObjects();
void DestroyDeviceObjects();
VulkanContext *vulkan_ = nullptr;
VkPipelineCache cache_ = VK_NULL_HANDLE;
VkDescriptorSetLayout descriptorSetLayout_ = VK_NULL_HANDLE;
VkPipelineLayout pipelineLayout_ = VK_NULL_HANDLE;
VkPipelineCache pipelineCache_ = VK_NULL_HANDLE;
struct FrameData {
VkDescriptorPool descPool;
};
FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES];
struct PipelineKey {
VkShaderModule module;
};
DenseHashMap<PipelineKey, VkPipeline, VK_NULL_HANDLE> pipelines_;
};
VkShaderModule CompileShaderModule(VulkanContext *vulkan, VkShaderStageFlagBits stage, const char *code, std::string *error);