Add a hidden debug option [Graphics]GfxDebugSplitSubmit to try to narrow down some Vulkan issues, see #10163. Also improve some asserts.

This commit is contained in:
Henrik Rydgård 2017-11-22 10:46:23 +01:00
parent acdb89c898
commit b6911d2764
10 changed files with 38 additions and 27 deletions

View File

@ -18,6 +18,7 @@
// Additionally, Common/Vulkan/* , including this file, are also licensed // Additionally, Common/Vulkan/* , including this file, are also licensed
// under the public domain. // under the public domain.
#include "Common/Log.h"
#include "Common/Vulkan/VulkanMemory.h" #include "Common/Vulkan/VulkanMemory.h"
VulkanPushBuffer::VulkanPushBuffer(VulkanContext *vulkan, size_t size) : device_(vulkan->GetDevice()), buf_(0), offset_(0), size_(size), writePtr_(nullptr) { VulkanPushBuffer::VulkanPushBuffer(VulkanContext *vulkan, size_t size) : device_(vulkan->GetDevice()), buf_(0), offset_(0), size_(size), writePtr_(nullptr) {
@ -44,7 +45,7 @@ bool VulkanPushBuffer::AddBuffer() {
VkResult res = vkCreateBuffer(device_, &b, nullptr, &info.buffer); VkResult res = vkCreateBuffer(device_, &b, nullptr, &info.buffer);
if (VK_SUCCESS != res) { if (VK_SUCCESS != res) {
ELOG("vkCreateBuffer failed! result=%d", (int)res); _assert_msg_(G3D, false, "vkCreateBuffer failed! result=%d", (int)res);
return false; return false;
} }
@ -61,7 +62,7 @@ bool VulkanPushBuffer::AddBuffer() {
res = vkAllocateMemory(device_, &alloc, nullptr, &info.deviceMemory); res = vkAllocateMemory(device_, &alloc, nullptr, &info.deviceMemory);
if (VK_SUCCESS != res) { if (VK_SUCCESS != res) {
ELOG("vkAllocateMemory failed! result=%d", (int)res); _assert_msg_(G3D, false, "vkAllocateMemory failed! size=%d result=%d", (int)reqs.size, (int)res);
vkDestroyBuffer(device_, info.buffer, nullptr); vkDestroyBuffer(device_, info.buffer, nullptr);
return false; return false;
} }

View File

@ -545,6 +545,7 @@ static ConfigSetting graphicsSettings[] = {
ReportedConfigSetting("FragmentTestCache", &g_Config.bFragmentTestCache, true, true, true), ReportedConfigSetting("FragmentTestCache", &g_Config.bFragmentTestCache, true, true, true),
ConfigSetting("GfxDebugOutput", &g_Config.bGfxDebugOutput, false, false, false), ConfigSetting("GfxDebugOutput", &g_Config.bGfxDebugOutput, false, false, false),
ConfigSetting("GfxDebugSplitSubmit", &g_Config.bGfxDebugSplitSubmit, false, false, false),
ConfigSetting("LogFrameDrops", &g_Config.bLogFrameDrops, false, true, false), ConfigSetting("LogFrameDrops", &g_Config.bLogFrameDrops, false, true, false),
ConfigSetting(false), ConfigSetting(false),

View File

@ -218,6 +218,7 @@ public:
bool bHardwareTessellation; bool bHardwareTessellation;
std::string sPostShaderName; // Off for off. std::string sPostShaderName; // Off for off.
bool bGfxDebugOutput; bool bGfxDebugOutput;
bool bGfxDebugSplitSubmit;
// Sound // Sound
bool bEnableSound; bool bEnableSound;

View File

@ -473,7 +473,7 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView
descAlloc.descriptorSetCount = 1; descAlloc.descriptorSetCount = 1;
VkResult result = vkAllocateDescriptorSets(vulkan_->GetDevice(), &descAlloc, &desc); VkResult result = vkAllocateDescriptorSets(vulkan_->GetDevice(), &descAlloc, &desc);
// Even in release mode, this is bad. // Even in release mode, this is bad.
_assert_msg_(G3D, result == VK_SUCCESS, "Ran out of descriptor space in pool. sz=%d", (int)frame->descSets.size()); _assert_msg_(G3D, result == VK_SUCCESS, "Ran out of descriptor space in pool. sz=%d res=%d", (int)frame->descSets.size(), (int)result);
// We just don't write to the slots we don't care about. // We just don't write to the slots we don't care about.
// We need 8 now that we support secondary texture bindings. // We need 8 now that we support secondary texture bindings.
@ -1041,8 +1041,6 @@ DrawEngineVulkan::TessellationDataTransferVulkan::~TessellationDataTransferVulka
void DrawEngineVulkan::TessellationDataTransferVulkan::PrepareBuffers(float *&pos, float *&tex, float *&col, int &posStride, int &texStride, int &colStride, int size, bool hasColor, bool hasTexCoords) { void DrawEngineVulkan::TessellationDataTransferVulkan::PrepareBuffers(float *&pos, float *&tex, float *&col, int &posStride, int &texStride, int &colStride, int size, bool hasColor, bool hasTexCoords) {
colStride = 4; colStride = 4;
assert(size > 0);
// TODO: This SHOULD work without padding but I can't get it to work on nvidia, so had // TODO: This SHOULD work without padding but I can't get it to work on nvidia, so had
// to expand to vec4. Driver bug? // to expand to vec4. Driver bug?
struct TessData { struct TessData {
@ -1064,6 +1062,5 @@ void DrawEngineVulkan::TessellationDataTransferVulkan::PrepareBuffers(float *&po
} }
void DrawEngineVulkan::TessellationDataTransferVulkan::SendDataToShader(const float *pos, const float *tex, const float *col, int size, bool hasColor, bool hasTexCoords) { void DrawEngineVulkan::TessellationDataTransferVulkan::SendDataToShader(const float *pos, const float *tex, const float *col, int size, bool hasColor, bool hasTexCoords) {
assert(pos);
// Nothing to do here! // Nothing to do here!
} }

View File

@ -278,6 +278,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
VkPipeline pipeline; VkPipeline pipeline;
VkResult result = vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipe, nullptr, &pipeline); VkResult result = vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipe, nullptr, &pipeline);
if (result != VK_SUCCESS) { if (result != VK_SUCCESS) {
_assert_msg_(G3D, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result));
ERROR_LOG(G3D, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result)); ERROR_LOG(G3D, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result));
return nullptr; return nullptr;
} }

View File

@ -212,7 +212,9 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m
return false; return false;
} }
draw_ = Draw::T3DCreateVulkanContext(g_Vulkan); bool splitSubmit = g_Config.bGfxDebugSplitSubmit;
draw_ = Draw::T3DCreateVulkanContext(g_Vulkan, splitSubmit);
bool success = draw_->CreatePresets(); bool success = draw_->CreatePresets();
assert(success); // Doesn't fail, we include the compiler. assert(success); // Doesn't fail, we include the compiler.
draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight());

View File

@ -762,8 +762,7 @@ void VulkanRenderManager::Submit(int frame, bool triggerFence) {
if (frameData.hasInitCommands) { if (frameData.hasInitCommands) {
cmdBufs[numCmdBufs++] = frameData.initCmd; cmdBufs[numCmdBufs++] = frameData.initCmd;
frameData.hasInitCommands = false; frameData.hasInitCommands = false;
} if (splitSubmit_) {
if (false) {
// Send the init commands off separately. Used this once to confirm that the cause of a device loss was in the init cmdbuf. // Send the init commands off separately. Used this once to confirm that the cause of a device loss was in the init cmdbuf.
VkSubmitInfo submit_info{ VK_STRUCTURE_TYPE_SUBMIT_INFO }; VkSubmitInfo submit_info{ VK_STRUCTURE_TYPE_SUBMIT_INFO };
submit_info.commandBufferCount = (uint32_t)numCmdBufs; submit_info.commandBufferCount = (uint32_t)numCmdBufs;
@ -772,10 +771,11 @@ void VulkanRenderManager::Submit(int frame, bool triggerFence) {
if (res == VK_ERROR_DEVICE_LOST) { if (res == VK_ERROR_DEVICE_LOST) {
_assert_msg_(G3D, false, "Lost the Vulkan device!"); _assert_msg_(G3D, false, "Lost the Vulkan device!");
} else { } else {
_assert_msg_(G3D, res == VK_SUCCESS, "vkQueueSubmit failed! result=%d", (int)res); _assert_msg_(G3D, res == VK_SUCCESS, "vkQueueSubmit failed (init)! result=%d", (int)res);
} }
numCmdBufs = 0; numCmdBufs = 0;
} }
}
cmdBufs[numCmdBufs++] = frameData.mainCmd; cmdBufs[numCmdBufs++] = frameData.mainCmd;
VkSubmitInfo submit_info{ VK_STRUCTURE_TYPE_SUBMIT_INFO }; VkSubmitInfo submit_info{ VK_STRUCTURE_TYPE_SUBMIT_INFO };
@ -795,7 +795,7 @@ void VulkanRenderManager::Submit(int frame, bool triggerFence) {
if (res == VK_ERROR_DEVICE_LOST) { if (res == VK_ERROR_DEVICE_LOST) {
_assert_msg_(G3D, false, "Lost the Vulkan device!"); _assert_msg_(G3D, false, "Lost the Vulkan device!");
} else { } else {
_assert_msg_(G3D, res == VK_SUCCESS, "vkQueueSubmit failed! result=%d", (int)res); _assert_msg_(G3D, res == VK_SUCCESS, "vkQueueSubmit failed (main, split=%d)! result=%d", (int)splitSubmit_, (int)res);
} }
// When !triggerFence, we notify after syncing with Vulkan. // When !triggerFence, we notify after syncing with Vulkan.
@ -823,8 +823,8 @@ void VulkanRenderManager::EndSubmitFrame(int frame) {
present.waitSemaphoreCount = 1; present.waitSemaphoreCount = 1;
VkResult res = vkQueuePresentKHR(vulkan_->GetGraphicsQueue(), &present); VkResult res = vkQueuePresentKHR(vulkan_->GetGraphicsQueue(), &present);
// TODO: Deal with VK_SUBOPTIMAL_WSI ? // TODO: Deal with VK_SUBOPTIMAL_KHR ?
if (res == VK_ERROR_OUT_OF_DATE_KHR) { if (res == VK_ERROR_OUT_OF_DATE_KHR || res == VK_SUBOPTIMAL_KHR) {
// ignore, it'll be fine. this happens sometimes during resizes, and we do make sure to recreate the swap chain. // ignore, it'll be fine. this happens sometimes during resizes, and we do make sure to recreate the swap chain.
} else { } else {
_assert_msg_(G3D, res == VK_SUCCESS, "vkQueuePresentKHR failed! result=%d", (int)res); _assert_msg_(G3D, res == VK_SUCCESS, "vkQueuePresentKHR failed! result=%d", (int)res);

View File

@ -208,6 +208,10 @@ public:
return !framebuffers_.empty(); return !framebuffers_.empty();
} }
void SetSplitSubmit(bool split) {
splitSubmit_ = split;
}
private: private:
bool InitBackbufferFramebuffers(int width, int height); bool InitBackbufferFramebuffers(int width, int height);
bool InitDepthStencilBuffer(VkCommandBuffer cmd); // Used for non-buffered rendering. bool InitDepthStencilBuffer(VkCommandBuffer cmd); // Used for non-buffered rendering.
@ -259,6 +263,7 @@ private:
bool insideFrame_ = false; bool insideFrame_ = false;
VKRStep *curRenderStep_ = nullptr; VKRStep *curRenderStep_ = nullptr;
std::vector<VKRStep *> steps_; std::vector<VKRStep *> steps_;
bool splitSubmit_ = false;
// Execution time state // Execution time state
bool run_ = true; bool run_ = true;

View File

@ -665,7 +665,7 @@ DrawContext *T3DCreateDX9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapt
DrawContext *T3DCreateD3D11Context(ID3D11Device *device, ID3D11DeviceContext *context, ID3D11Device1 *device1, ID3D11DeviceContext1 *context1, D3D_FEATURE_LEVEL featureLevel, HWND hWnd); DrawContext *T3DCreateD3D11Context(ID3D11Device *device, ID3D11DeviceContext *context, ID3D11Device1 *device1, ID3D11DeviceContext1 *context1, D3D_FEATURE_LEVEL featureLevel, HWND hWnd);
#endif #endif
DrawContext *T3DCreateVulkanContext(VulkanContext *context); DrawContext *T3DCreateVulkanContext(VulkanContext *context, bool split);
// UBs for the preset shaders // UBs for the preset shaders

View File

@ -22,6 +22,7 @@
#include <assert.h> #include <assert.h>
#include "Common/Vulkan/SPIRVDisasm.h" #include "Common/Vulkan/SPIRVDisasm.h"
#include "Core/Config.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/display.h" #include "base/display.h"
@ -348,7 +349,7 @@ class VKFramebuffer;
class VKContext : public DrawContext { class VKContext : public DrawContext {
public: public:
VKContext(VulkanContext *vulkan); VKContext(VulkanContext *vulkan, bool splitSubmit);
virtual ~VKContext(); virtual ~VKContext();
const DeviceCaps &GetDeviceCaps() const override { const DeviceCaps &GetDeviceCaps() const override {
@ -674,7 +675,7 @@ bool VKTexture::Create(VkCommandBuffer cmd, const TextureDesc &desc) {
return true; return true;
} }
VKContext::VKContext(VulkanContext *vulkan) VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit)
: vulkan_(vulkan), caps_{}, renderManager_(vulkan) { : vulkan_(vulkan), caps_{}, renderManager_(vulkan) {
caps_.anisoSupported = vulkan->GetFeaturesAvailable().samplerAnisotropy != 0; caps_.anisoSupported = vulkan->GetFeaturesAvailable().samplerAnisotropy != 0;
caps_.geometryShaderSupported = vulkan->GetFeaturesAvailable().geometryShader != 0; caps_.geometryShaderSupported = vulkan->GetFeaturesAvailable().geometryShader != 0;
@ -755,6 +756,8 @@ VKContext::VKContext(VulkanContext *vulkan)
assert(VK_SUCCESS == res); assert(VK_SUCCESS == res);
pipelineCache_ = vulkan_->CreatePipelineCache(); pipelineCache_ = vulkan_->CreatePipelineCache();
renderManager_.SetSplitSubmit(splitSubmit);
} }
VKContext::~VKContext() { VKContext::~VKContext() {
@ -1188,8 +1191,8 @@ void VKContext::Clear(int clearMask, uint32_t colorval, float depthVal, int sten
renderManager_.Clear(colorval, depthVal, stencilVal, mask); renderManager_.Clear(colorval, depthVal, stencilVal, mask);
} }
DrawContext *T3DCreateVulkanContext(VulkanContext *vulkan) { DrawContext *T3DCreateVulkanContext(VulkanContext *vulkan, bool split) {
return new VKContext(vulkan); return new VKContext(vulkan, split);
} }
void AddFeature(std::vector<std::string> &features, const char *name, VkBool32 available, VkBool32 enabled) { void AddFeature(std::vector<std::string> &features, const char *name, VkBool32 available, VkBool32 enabled) {