mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Vulkan: Add simple manager for compute shaders that upload data to images.
This commit is contained in:
parent
360e138c2c
commit
e6bec3e555
4 changed files with 189 additions and 4 deletions
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue