mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-02-17 12:47:46 +00:00
Vulkan: Add code (disabled) to be able to run with more in-flight frames. Only improves performance marginally and needs more testing.
This commit is contained in:
parent
d65547edb5
commit
560eaa5390
@ -71,8 +71,7 @@ VulkanContext::VulkanContext(const char *app_name, int app_ver, uint32_t flags)
|
||||
swapchainImageCount(0),
|
||||
swap_chain_(VK_NULL_HANDLE),
|
||||
cmd_pool_(VK_NULL_HANDLE),
|
||||
queue_count(0),
|
||||
curFrame_(0) {
|
||||
queue_count(0) {
|
||||
if (!VulkanLoad()) {
|
||||
init_error_ = "Failed to load Vulkan driver library";
|
||||
// No DLL?
|
||||
@ -311,7 +310,10 @@ void VulkanContext::EndFrame() {
|
||||
assert(!res);
|
||||
|
||||
frame->deleteList.Take(globalDeleteList_);
|
||||
curFrame_ ^= 1;
|
||||
curFrame_++;
|
||||
if (curFrame_ >= inflightFrames_) {
|
||||
curFrame_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanContext::WaitUntilQueueIdle() {
|
||||
@ -353,18 +355,17 @@ bool VulkanContext::InitObjects(bool depthPresent) {
|
||||
VkCommandBufferAllocateInfo cmd_alloc = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
|
||||
cmd_alloc.commandPool = cmd_pool_;
|
||||
cmd_alloc.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
cmd_alloc.commandBufferCount = 4;
|
||||
cmd_alloc.commandBufferCount = MAX_INFLIGHT_FRAMES * 2;
|
||||
|
||||
VkCommandBuffer cmdBuf[4];
|
||||
VkCommandBuffer cmdBuf[MAX_INFLIGHT_FRAMES * 2];
|
||||
VkResult res = vkAllocateCommandBuffers(device_, &cmd_alloc, cmdBuf);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
frame_[0].cmdBuf = cmdBuf[0];
|
||||
frame_[0].cmdInit = cmdBuf[1];
|
||||
frame_[0].fence = CreateFence(true); // So it can be instantly waited on
|
||||
frame_[1].cmdBuf = cmdBuf[2];
|
||||
frame_[1].cmdInit = cmdBuf[3];
|
||||
frame_[1].fence = CreateFence(true);
|
||||
for (int i = 0; i < MAX_INFLIGHT_FRAMES; i++) {
|
||||
frame_[i].cmdBuf = cmdBuf[i * 2];
|
||||
frame_[i].cmdInit = cmdBuf[i * 2 + 1];
|
||||
frame_[i].fence = CreateFence(true); // So it can be instantly waited on
|
||||
}
|
||||
|
||||
VkCommandBuffer cmd = GetInitCommandBuffer();
|
||||
if (!InitSwapchain(cmd)) {
|
||||
@ -381,11 +382,16 @@ bool VulkanContext::InitObjects(bool depthPresent) {
|
||||
}
|
||||
|
||||
void VulkanContext::DestroyObjects() {
|
||||
VkCommandBuffer cmdBuf[4] = { frame_[0].cmdBuf, frame_[0].cmdInit, frame_[1].cmdBuf, frame_[1].cmdInit };
|
||||
|
||||
vkFreeCommandBuffers(device_, cmd_pool_, sizeof(cmdBuf) / sizeof(cmdBuf[0]), cmdBuf);
|
||||
vkDestroyFence(device_, frame_[0].fence, nullptr);
|
||||
vkDestroyFence(device_, frame_[1].fence, nullptr);
|
||||
VkCommandBuffer *cmdBuf = new VkCommandBuffer[MAX_INFLIGHT_FRAMES * 2];
|
||||
for (int i = 0; i < MAX_INFLIGHT_FRAMES; i++) {
|
||||
cmdBuf[i * 2] = frame_[i].cmdBuf;
|
||||
cmdBuf[i * 2 + 1] = frame_[i].cmdInit;
|
||||
}
|
||||
vkFreeCommandBuffers(device_, cmd_pool_, MAX_INFLIGHT_FRAMES * 2, cmdBuf);
|
||||
delete[] cmdBuf;
|
||||
for (int i = 0; i < MAX_INFLIGHT_FRAMES; i++) {
|
||||
vkDestroyFence(device_, frame_[i].fence, nullptr);
|
||||
}
|
||||
|
||||
DestroyFramebuffers();
|
||||
DestroySurfaceRenderPass();
|
||||
|
@ -263,7 +263,7 @@ public:
|
||||
}
|
||||
// This must only be accessed between BeginSurfaceRenderPass and EndSurfaceRenderPass.
|
||||
VkCommandBuffer GetSurfaceCommandBuffer() {
|
||||
return frame_[curFrame_ & 1].cmdBuf;
|
||||
return frame_[curFrame_].cmdBuf;
|
||||
}
|
||||
|
||||
VkCommandBuffer BeginFrame();
|
||||
@ -314,7 +314,15 @@ public:
|
||||
const VkPhysicalDeviceFeatures &GetFeaturesEnabled() const { return featuresEnabled_; }
|
||||
const VulkanPhysicalDeviceInfo &GetDeviceInfo() const { return deviceInfo_; }
|
||||
|
||||
int GetInflightFrames() const {
|
||||
return inflightFrames_;
|
||||
}
|
||||
|
||||
enum {
|
||||
MAX_INFLIGHT_FRAMES = 2,
|
||||
};
|
||||
private:
|
||||
|
||||
VkSemaphore acquireSemaphore;
|
||||
VkSemaphore renderingCompleteSemaphore;
|
||||
|
||||
@ -368,6 +376,8 @@ private:
|
||||
VkSwapchainKHR swap_chain_;
|
||||
std::vector<swap_chain_buffer> swapChainBuffers;
|
||||
|
||||
int inflightFrames_ = MAX_INFLIGHT_FRAMES;
|
||||
|
||||
// Manages flipping command buffers for the backbuffer render pass.
|
||||
// It is recommended to do the same for other rendering passes.
|
||||
struct FrameData {
|
||||
@ -380,8 +390,8 @@ private:
|
||||
|
||||
VulkanDeleteList deleteList;
|
||||
};
|
||||
FrameData frame_[2];
|
||||
int curFrame_;
|
||||
FrameData frame_[MAX_INFLIGHT_FRAMES];
|
||||
int curFrame_ = 0;
|
||||
|
||||
// At the end of the frame, this is copied into the frame's delete list, so it can be processed
|
||||
// the next time the frame comes around again.
|
||||
|
@ -162,7 +162,7 @@ void DrawEngineVulkan::InitDeviceObjects() {
|
||||
|
||||
// We are going to use one-shot descriptors in the initial implementation. Might look into caching them
|
||||
// if creating and updating them turns out to be expensive.
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) {
|
||||
// If we run out of memory, try with less descriptors.
|
||||
for (int tries = 0; tries < 3; ++tries) {
|
||||
VkResult res = vkCreateDescriptorPool(vulkan_->GetDevice(), &dp, nullptr, &frame_[i].descPool);
|
||||
@ -274,7 +274,7 @@ void DrawEngineVulkan::BeginFrame() {
|
||||
lastCmd_ = VK_NULL_HANDLE;
|
||||
lastPipeline_ = nullptr;
|
||||
|
||||
FrameData *frame = &frame_[curFrame_ & 1];
|
||||
FrameData *frame = &frame_[curFrame_];
|
||||
vkResetDescriptorPool(vulkan_->GetDevice(), frame->descPool, 0);
|
||||
frame->descSets.clear();
|
||||
|
||||
@ -347,7 +347,7 @@ void DrawEngineVulkan::BeginFrame() {
|
||||
}
|
||||
|
||||
void DrawEngineVulkan::EndFrame() {
|
||||
FrameData *frame = &frame_[curFrame_ & 1];
|
||||
FrameData *frame = &frame_[curFrame_];
|
||||
stats_.pushUBOSpaceUsed = (int)frame->pushUBO->GetOffset();
|
||||
stats_.pushVertexSpaceUsed = (int)frame->pushVertex->GetOffset();
|
||||
stats_.pushIndexSpaceUsed = (int)frame->pushIndex->GetOffset();
|
||||
@ -355,6 +355,8 @@ void DrawEngineVulkan::EndFrame() {
|
||||
frame->pushVertex->End();
|
||||
frame->pushIndex->End();
|
||||
curFrame_++;
|
||||
if (curFrame_ >= vulkan_->GetInflightFrames())
|
||||
curFrame_ = 0;
|
||||
vertexCache_->End();
|
||||
}
|
||||
|
||||
@ -508,7 +510,7 @@ VkDescriptorSet DrawEngineVulkan::GetDescriptorSet(VkImageView imageView, VkSamp
|
||||
assert(light != VK_NULL_HANDLE);
|
||||
assert(bone != VK_NULL_HANDLE);
|
||||
|
||||
FrameData *frame = &frame_[curFrame_ & 1];
|
||||
FrameData *frame = &frame_[curFrame_];
|
||||
if (!(gstate_c.bezier || gstate_c.spline)) { // Has no cache when HW tessellation.
|
||||
auto iter = frame->descSets.find(key);
|
||||
if (iter != frame->descSets.end()) {
|
||||
@ -645,7 +647,7 @@ void DrawEngineVulkan::DoFlush() {
|
||||
if (!rp)
|
||||
Crash();
|
||||
|
||||
FrameData *frame = &frame_[curFrame_ & 1];
|
||||
FrameData *frame = &frame_[curFrame_];
|
||||
|
||||
bool textureNeedsApply = false;
|
||||
if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) {
|
||||
|
@ -162,7 +162,7 @@ public:
|
||||
void DirtyAllUBOs();
|
||||
|
||||
VulkanPushBuffer *GetPushBufferForTextureData() {
|
||||
return frame_[curFrame_ & 1].pushUBO;
|
||||
return frame_[curFrame_].pushUBO;
|
||||
}
|
||||
|
||||
const DrawEngineVulkanStats &GetStats() const {
|
||||
@ -230,7 +230,7 @@ private:
|
||||
|
||||
GEPrimitiveType lastPrim_ = GE_PRIM_INVALID;
|
||||
int curFrame_;
|
||||
FrameData frame_[2];
|
||||
FrameData frame_[VulkanContext::MAX_INFLIGHT_FRAMES];
|
||||
|
||||
// Other
|
||||
ShaderManagerVulkan *shaderManager_ = nullptr;
|
||||
|
@ -115,7 +115,7 @@ void FramebufferManagerVulkan::SetShaderManager(ShaderManagerVulkan *sm) {
|
||||
|
||||
void FramebufferManagerVulkan::InitDeviceObjects() {
|
||||
// Initialize framedata
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) {
|
||||
frameData_[i].push_ = new VulkanPushBuffer(vulkan_, 64 * 1024);
|
||||
}
|
||||
|
||||
@ -146,7 +146,7 @@ void FramebufferManagerVulkan::InitDeviceObjects() {
|
||||
}
|
||||
|
||||
void FramebufferManagerVulkan::DestroyDeviceObjects() {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) {
|
||||
if (frameData_[i].push_) {
|
||||
frameData_[i].push_->Destroy(vulkan_);
|
||||
delete frameData_[i].push_;
|
||||
@ -948,7 +948,9 @@ void FramebufferManagerVulkan::EndFrame() {
|
||||
vulkan2D_.EndFrame();
|
||||
|
||||
curFrame_++;
|
||||
curFrame_ &= 1;
|
||||
if (curFrame_ >= vulkan_->GetInflightFrames()) {
|
||||
curFrame_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void FramebufferManagerVulkan::DeviceLost() {
|
||||
|
@ -163,7 +163,7 @@ private:
|
||||
VulkanPushBuffer *push_;
|
||||
};
|
||||
|
||||
FrameData frameData_[2];
|
||||
FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES];
|
||||
int curFrame_;
|
||||
|
||||
// This gets copied to the current frame's push buffer as needed.
|
||||
|
@ -60,7 +60,7 @@ void Vulkan2D::Shutdown() {
|
||||
}
|
||||
|
||||
void Vulkan2D::DestroyDeviceObjects() {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int i = 0; i < vulkan_->GetInflightFrames(); i++) {
|
||||
if (frameData_[i].descPool != VK_NULL_HANDLE) {
|
||||
vulkan_->Delete().QueueDeleteDescriptorPool(frameData_[i].descPool);
|
||||
}
|
||||
@ -146,7 +146,9 @@ void Vulkan2D::BeginFrame() {
|
||||
}
|
||||
|
||||
void Vulkan2D::EndFrame() {
|
||||
curFrame_ = (curFrame_ + 1) & 1;
|
||||
curFrame_++;
|
||||
if (curFrame_ >= vulkan_->GetInflightFrames())
|
||||
curFrame_ = 0;
|
||||
}
|
||||
|
||||
VkDescriptorSet Vulkan2D::GetDescriptorSet(VkImageView tex1, VkSampler sampler1, VkImageView tex2, VkSampler sampler2) {
|
||||
@ -156,7 +158,7 @@ VkDescriptorSet Vulkan2D::GetDescriptorSet(VkImageView tex1, VkSampler sampler1,
|
||||
key.sampler[0] = sampler1;
|
||||
key.sampler[1] = sampler2;
|
||||
|
||||
FrameData *frame = &frameData_[curFrame_ & 1];
|
||||
FrameData *frame = &frameData_[curFrame_];
|
||||
auto iter = frame->descSets.find(key);
|
||||
if (iter != frame->descSets.end()) {
|
||||
return iter->second;
|
||||
|
@ -131,8 +131,8 @@ private:
|
||||
std::map<DescriptorSetKey, VkDescriptorSet> descSets;
|
||||
};
|
||||
|
||||
FrameData frameData_[2];
|
||||
int curFrame_;
|
||||
FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES];
|
||||
int curFrame_ = 0;
|
||||
|
||||
std::map<PipelineKey, VkPipeline> pipelines_;
|
||||
};
|
||||
|
@ -1090,6 +1090,7 @@ retry:
|
||||
NativeDeviceLost();
|
||||
renderer_inited = false;
|
||||
|
||||
ILOG("Shutting down graphics context.");
|
||||
graphicsContext->Shutdown();
|
||||
delete graphicsContext;
|
||||
graphicsContext = nullptr;
|
||||
|
@ -541,7 +541,7 @@ private:
|
||||
VkDescriptorPool descriptorPool;
|
||||
};
|
||||
|
||||
FrameData frame_[2]{};
|
||||
FrameData frame_[VulkanContext::MAX_INFLIGHT_FRAMES]{};
|
||||
|
||||
int frameNum_ = 0;
|
||||
VulkanPushBuffer *push_ = nullptr;
|
||||
@ -735,7 +735,7 @@ VKContext::VKContext(VulkanContext *vulkan)
|
||||
p.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
|
||||
p.queueFamilyIndex = vulkan->GetGraphicsQueueFamilyIndex();
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) {
|
||||
VkResult res = vkCreateDescriptorPool(device_, &dp, nullptr, &frame_[i].descriptorPool);
|
||||
assert(VK_SUCCESS == res);
|
||||
res = vkCreateCommandPool(device_, &p, nullptr, &frame_[i].cmdPool_);
|
||||
@ -846,7 +846,7 @@ VKContext::~VKContext() {
|
||||
vulkan_->Delete().QueueDeleteRenderPass(renderPasses_[i]);
|
||||
}
|
||||
// This also destroys all descriptor sets.
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) {
|
||||
frame_[i].descSets_.clear();
|
||||
vulkan_->Delete().QueueDeleteDescriptorPool(frame_[i].descriptorPool);
|
||||
frame_[i].pushBuffer->Destroy(vulkan_);
|
||||
@ -860,7 +860,7 @@ VKContext::~VKContext() {
|
||||
|
||||
// Effectively wiped every frame, just allocate new ones!
|
||||
VkCommandBuffer VKContext::AllocCmdBuf() {
|
||||
FrameData *frame = &frame_[frameNum_ & 1];
|
||||
FrameData *frame = &frame_[frameNum_];
|
||||
|
||||
if (frame->numCmdBufs >= MAX_FRAME_COMMAND_BUFFERS)
|
||||
Crash();
|
||||
@ -887,7 +887,7 @@ VkCommandBuffer VKContext::AllocCmdBuf() {
|
||||
void VKContext::BeginFrame() {
|
||||
vulkan_->BeginFrame();
|
||||
|
||||
FrameData &frame = frame_[frameNum_ & 1];
|
||||
FrameData &frame = frame_[frameNum_];
|
||||
frame.startCmdBufs_ = 0;
|
||||
frame.numCmdBufs = 0;
|
||||
vkResetCommandPool(vulkan_->GetDevice(), frame.cmdPool_, 0);
|
||||
@ -924,7 +924,7 @@ void VKContext::EndFrame() {
|
||||
Crash();
|
||||
|
||||
// Cap off and submit all the command buffers we recorded during the frame.
|
||||
FrameData &frame = frame_[frameNum_ & 1];
|
||||
FrameData &frame = frame_[frameNum_];
|
||||
for (int i = frame.startCmdBufs_; i < frame.numCmdBufs; i++) {
|
||||
vkEndCommandBuffer(frame.cmdBufs[i]);
|
||||
vulkan_->QueueBeforeSurfaceRender(frame.cmdBufs[i]);
|
||||
@ -936,6 +936,8 @@ void VKContext::EndFrame() {
|
||||
vulkan_->EndFrame();
|
||||
|
||||
frameNum_++;
|
||||
if (frameNum_ >= vulkan_->GetInflightFrames())
|
||||
frameNum_ = 0;
|
||||
push_ = nullptr;
|
||||
|
||||
DirtyDynamicState();
|
||||
@ -944,7 +946,7 @@ void VKContext::EndFrame() {
|
||||
VkDescriptorSet VKContext::GetOrCreateDescriptorSet(VkBuffer buf) {
|
||||
DescriptorSetKey key;
|
||||
|
||||
FrameData *frame = &frame_[frameNum_ & 1];
|
||||
FrameData *frame = &frame_[frameNum_];
|
||||
|
||||
key.texture_ = boundTextures_[0];
|
||||
key.sampler_ = boundSamplers_[0];
|
||||
|
Loading…
x
Reference in New Issue
Block a user