diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index d2c04172b7..a0f17daaf2 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -65,6 +65,16 @@ std::string VulkanVendorString(uint32_t vendorId) { } } +const char *PresentModeString(VkPresentModeKHR presentMode) { + switch (presentMode) { + case VK_PRESENT_MODE_IMMEDIATE_KHR: return "IMMEDIATE"; + case VK_PRESENT_MODE_MAILBOX_KHR: return "MAILBOX"; + case VK_PRESENT_MODE_FIFO_KHR: return "FIFO"; + case VK_PRESENT_MODE_FIFO_RELAXED_KHR: return "FIFO_RELAXED"; + default: return "UNKNOWN"; + } +} + VulkanContext::VulkanContext() { if (!VulkanLoad()) { init_error_ = "Failed to load Vulkan driver library"; @@ -165,8 +175,13 @@ VkResult VulkanContext::CreateInstance(const char *app_name, int app_ver, uint32 } VulkanContext::~VulkanContext() { + assert(instance_ == VK_NULL_HANDLE); +} + +void VulkanContext::DestroyInstance() { vkDestroyInstance(instance_, nullptr); VulkanFree(); + instance_ = VK_NULL_HANDLE; } void VulkanContext::BeginFrame() { @@ -214,6 +229,7 @@ bool VulkanContext::InitObjects() { } void VulkanContext::DestroyObjects() { + ILOG("VulkanContext::DestroyObjects (including swapchain)"); if (swapchain_ != VK_NULL_HANDLE) vkDestroySwapchainKHR(device_, swapchain_, nullptr); swapchain_ = VK_NULL_HANDLE; @@ -580,12 +596,15 @@ void VulkanContext::InitSurfaceAndroid(ANativeWindow *wnd, int width, int height void VulkanContext::ReinitSurfaceAndroid(int width, int height) { if (surface_ != VK_NULL_HANDLE) { + ILOG("Destroying Android Vulkan surface (%d, %d)", width_, height_); vkDestroySurfaceKHR(instance_, surface_, nullptr); surface_ = VK_NULL_HANDLE; } VkResult U_ASSERT_ONLY res; + ILOG("Creating Android Vulkan surface (%d, %d)", width, height); + VkAndroidSurfaceCreateInfoKHR android = { VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR }; android.flags = 0; android.window = native_window; @@ -710,7 +729,7 @@ bool VulkanContext::InitSwapchain() { // to fall back in a sensible way. VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR; for (size_t i = 0; i < presentModeCount; i++) { - ILOG("Supported present mode: %d", presentModes[i]); + ILOG("Supported present mode: %d (%s)", presentModes[i], PresentModeString(presentModes[i])); } for (size_t i = 0; i < presentModeCount; i++) { if (swapchainPresentMode == VK_PRESENT_MODE_MAX_ENUM_KHR) { @@ -734,7 +753,7 @@ bool VulkanContext::InitSwapchain() { // HACK swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; #endif - ILOG("Chosen present mode: %d", swapchainPresentMode); + ILOG("Chosen present mode: %d (%s)", swapchainPresentMode, PresentModeString(swapchainPresentMode)); delete[] presentModes; // Determine the number of VkImage's to use in the swap chain (we desire to // own only 1 image at a time, besides the images being displayed and @@ -797,6 +816,7 @@ VkFence VulkanContext::CreateFence(bool presignalled) { } void VulkanContext::DestroyDevice() { + ILOG("VulkanContext::DestroyDevice (performing deletes)"); // If there happen to be any pending deletes, now is a good time. for (int i = 0; i < ARRAY_SIZE(frame_); i++) { frame_[i].deleteList.PerformDeletes(device_); @@ -962,3 +982,103 @@ const char *VulkanResultToString(VkResult res) { return "VK_ERROR_...(unknown)"; } } + +void VulkanDeleteList::Take(VulkanDeleteList &del) { + assert(cmdPools_.size() == 0); + assert(descPools_.size() == 0); + assert(modules_.size() == 0); + assert(buffers_.size() == 0); + assert(bufferViews_.size() == 0); + assert(images_.size() == 0); + assert(imageViews_.size() == 0); + assert(deviceMemory_.size() == 0); + assert(samplers_.size() == 0); + assert(pipelines_.size() == 0); + assert(pipelineCaches_.size() == 0); + assert(renderPasses_.size() == 0); + assert(framebuffers_.size() == 0); + assert(callbacks_.size() == 0); + cmdPools_ = std::move(del.cmdPools_); + descPools_ = std::move(del.descPools_); + modules_ = std::move(del.modules_); + buffers_ = std::move(del.buffers_); + bufferViews_ = std::move(del.bufferViews_); + images_ = std::move(del.images_); + imageViews_ = std::move(del.imageViews_); + deviceMemory_ = std::move(del.deviceMemory_); + samplers_ = std::move(del.samplers_); + pipelines_ = std::move(del.pipelines_); + pipelineCaches_ = std::move(del.pipelineCaches_); + renderPasses_ = std::move(del.renderPasses_); + framebuffers_ = std::move(del.framebuffers_); + pipelineLayouts_ = std::move(del.pipelineLayouts_); + descSetLayouts_ = std::move(del.descSetLayouts_); + callbacks_ = std::move(del.callbacks_); +} + +void VulkanDeleteList::PerformDeletes(VkDevice device) { + for (auto &cmdPool : cmdPools_) { + vkDestroyCommandPool(device, cmdPool, nullptr); + } + cmdPools_.clear(); + for (auto &descPool : descPools_) { + vkDestroyDescriptorPool(device, descPool, nullptr); + } + descPools_.clear(); + for (auto &module : modules_) { + vkDestroyShaderModule(device, module, nullptr); + } + modules_.clear(); + for (auto &buf : buffers_) { + vkDestroyBuffer(device, buf, nullptr); + } + buffers_.clear(); + for (auto &bufView : bufferViews_) { + vkDestroyBufferView(device, bufView, nullptr); + } + bufferViews_.clear(); + for (auto &image : images_) { + vkDestroyImage(device, image, nullptr); + } + images_.clear(); + for (auto &imageView : imageViews_) { + vkDestroyImageView(device, imageView, nullptr); + } + imageViews_.clear(); + for (auto &mem : deviceMemory_) { + vkFreeMemory(device, mem, nullptr); + } + deviceMemory_.clear(); + for (auto &sampler : samplers_) { + vkDestroySampler(device, sampler, nullptr); + } + samplers_.clear(); + for (auto &pipeline : pipelines_) { + vkDestroyPipeline(device, pipeline, nullptr); + } + pipelines_.clear(); + for (auto &pcache : pipelineCaches_) { + vkDestroyPipelineCache(device, pcache, nullptr); + } + pipelineCaches_.clear(); + for (auto &renderPass : renderPasses_) { + vkDestroyRenderPass(device, renderPass, nullptr); + } + renderPasses_.clear(); + for (auto &framebuffer : framebuffers_) { + vkDestroyFramebuffer(device, framebuffer, nullptr); + } + framebuffers_.clear(); + for (auto &pipeLayout : pipelineLayouts_) { + vkDestroyPipelineLayout(device, pipeLayout, nullptr); + } + pipelineLayouts_.clear(); + for (auto &descSetLayout : descSetLayouts_) { + vkDestroyDescriptorSetLayout(device, descSetLayout, nullptr); + } + descSetLayouts_.clear(); + for (auto &callback : callbacks_) { + callback.func(callback.userdata); + } + callbacks_.clear(); +} diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h index 8b1044c093..07f82ead75 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/Vulkan/VulkanContext.h @@ -71,6 +71,7 @@ class VulkanDeleteList { }; public: + // NOTE: These all take reference handles so they can zero the input value. void QueueDeleteCommandPool(VkCommandPool &pool) { cmdPools_.push_back(pool); pool = VK_NULL_HANDLE; } void QueueDeleteDescriptorPool(VkDescriptorPool &pool) { descPools_.push_back(pool); pool = VK_NULL_HANDLE; } void QueueDeleteShaderModule(VkShaderModule &module) { modules_.push_back(module); module = VK_NULL_HANDLE; } @@ -88,105 +89,8 @@ public: void QueueDeleteDescriptorSetLayout(VkDescriptorSetLayout &descSetLayout) { descSetLayouts_.push_back(descSetLayout); descSetLayout = VK_NULL_HANDLE; } void QueueCallback(void(*func)(void *userdata), void *userdata) { callbacks_.push_back(Callback(func, userdata)); } - void Take(VulkanDeleteList &del) { - assert(cmdPools_.size() == 0); - assert(descPools_.size() == 0); - assert(modules_.size() == 0); - assert(buffers_.size() == 0); - assert(bufferViews_.size() == 0); - assert(images_.size() == 0); - assert(imageViews_.size() == 0); - assert(deviceMemory_.size() == 0); - assert(samplers_.size() == 0); - assert(pipelines_.size() == 0); - assert(pipelineCaches_.size() == 0); - assert(renderPasses_.size() == 0); - assert(framebuffers_.size() == 0); - assert(callbacks_.size() == 0); - cmdPools_ = std::move(del.cmdPools_); - descPools_ = std::move(del.descPools_); - modules_ = std::move(del.modules_); - buffers_ = std::move(del.buffers_); - bufferViews_ = std::move(del.bufferViews_); - images_ = std::move(del.images_); - imageViews_ = std::move(del.imageViews_); - deviceMemory_ = std::move(del.deviceMemory_); - samplers_ = std::move(del.samplers_); - pipelines_ = std::move(del.pipelines_); - pipelineCaches_ = std::move(del.pipelineCaches_); - renderPasses_ = std::move(del.renderPasses_); - framebuffers_ = std::move(del.framebuffers_); - pipelineLayouts_ = std::move(del.pipelineLayouts_); - descSetLayouts_ = std::move(del.descSetLayouts_); - callbacks_ = std::move(del.callbacks_); - } - - void PerformDeletes(VkDevice device) { - for (auto &cmdPool : cmdPools_) { - vkDestroyCommandPool(device, cmdPool, nullptr); - } - cmdPools_.clear(); - for (auto &descPool : descPools_) { - vkDestroyDescriptorPool(device, descPool, nullptr); - } - descPools_.clear(); - for (auto &module : modules_) { - vkDestroyShaderModule(device, module, nullptr); - } - modules_.clear(); - for (auto &buf : buffers_) { - vkDestroyBuffer(device, buf, nullptr); - } - buffers_.clear(); - for (auto &bufView : bufferViews_) { - vkDestroyBufferView(device, bufView, nullptr); - } - bufferViews_.clear(); - for (auto &image : images_) { - vkDestroyImage(device, image, nullptr); - } - images_.clear(); - for (auto &imageView : imageViews_) { - vkDestroyImageView(device, imageView, nullptr); - } - imageViews_.clear(); - for (auto &mem : deviceMemory_) { - vkFreeMemory(device, mem, nullptr); - } - deviceMemory_.clear(); - for (auto &sampler : samplers_) { - vkDestroySampler(device, sampler, nullptr); - } - samplers_.clear(); - for (auto &pipeline : pipelines_) { - vkDestroyPipeline(device, pipeline, nullptr); - } - pipelines_.clear(); - for (auto &pcache : pipelineCaches_) { - vkDestroyPipelineCache(device, pcache, nullptr); - } - pipelineCaches_.clear(); - for (auto &renderPass : renderPasses_) { - vkDestroyRenderPass(device, renderPass, nullptr); - } - renderPasses_.clear(); - for (auto &framebuffer : framebuffers_) { - vkDestroyFramebuffer(device, framebuffer, nullptr); - } - framebuffers_.clear(); - for (auto &pipeLayout : pipelineLayouts_) { - vkDestroyPipelineLayout(device, pipeLayout, nullptr); - } - pipelineLayouts_.clear(); - for (auto &descSetLayout : descSetLayouts_) { - vkDestroyDescriptorSetLayout(device, descSetLayout, nullptr); - } - descSetLayouts_.clear(); - for (auto &callback : callbacks_) { - callback.func(callback.userdata); - } - callbacks_.clear(); - } + void Take(VulkanDeleteList &del); + void PerformDeletes(VkDevice device); private: std::vector cmdPools_; @@ -214,7 +118,8 @@ public: ~VulkanContext(); VkResult CreateInstance(const char *app_name, int app_ver, uint32_t flags); - + void DestroyInstance(); + int GetBestPhysicalDevice(); void ChooseDevice(int physical_device); bool EnableDeviceExtension(const char *extension); diff --git a/Common/Vulkan/VulkanMemory.cpp b/Common/Vulkan/VulkanMemory.cpp index 260be7d9d6..57b219b472 100644 --- a/Common/Vulkan/VulkanMemory.cpp +++ b/Common/Vulkan/VulkanMemory.cpp @@ -78,7 +78,6 @@ void VulkanPushBuffer::Destroy(VulkanContext *vulkan) { vulkan->Delete().QueueDeleteBuffer(info.buffer); vulkan->Delete().QueueDeleteDeviceMemory(info.deviceMemory); } - buffers_.clear(); } diff --git a/Core/Core.cpp b/Core/Core.cpp index 55783375a8..73696842f6 100644 --- a/Core/Core.cpp +++ b/Core/Core.cpp @@ -172,7 +172,7 @@ bool UpdateScreenScale(int width, int height) { dp_yres = new_dp_yres; pixel_xres = width; pixel_yres = height; - INFO_LOG(SYSTEM, "pixel_res: %dx%d", pixel_xres, pixel_yres); + INFO_LOG(SYSTEM, "pixel_res: %dx%d. Calling NativeResized()", pixel_xres, pixel_yres); NativeResized(); return true; } diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index f55c793c47..fa34e321d5 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -137,13 +137,6 @@ void SoftwareTransform( bool throughmode = (vertType & GE_VTYPE_THROUGH_MASK) != 0; bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled(); - // TODO: Split up into multiple draw calls for GLES 2.0 where you can't guarantee support for more than 0x10000 verts. - -#if defined(MOBILE_DEVICE) - if (vertexCount > 0x10000/3) - vertexCount = 0x10000/3; -#endif - float uscale = 1.0f; float vscale = 1.0f; if (throughmode) { diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index d917437b83..fe1f1e0653 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -701,8 +701,15 @@ rotateVBO: params.allowSeparateAlphaClear = true; int maxIndex = indexGen.MaxIndex(); + int vertexCount = indexGen.VertexCount(); + + // TODO: Split up into multiple draw calls for GLES 2.0 where you can't guarantee support for more than 0x10000 verts. +#if defined(MOBILE_DEVICE) + if (vertexCount > 0x10000 / 3) + vertexCount = 0x10000 / 3; +#endif SoftwareTransform( - prim, indexGen.VertexCount(), + prim, vertexCount, dec_->VertexType(), inds, GE_VTYPE_IDX_16BIT, dec_->GetDecVtxFmt(), maxIndex, drawBuffer, numTrans, drawIndexed, ¶ms, &result); ApplyDrawStateLate(); diff --git a/GPU/Vulkan/DepalettizeShaderVulkan.cpp b/GPU/Vulkan/DepalettizeShaderVulkan.cpp index ce71a9babd..a080b27416 100644 --- a/GPU/Vulkan/DepalettizeShaderVulkan.cpp +++ b/GPU/Vulkan/DepalettizeShaderVulkan.cpp @@ -60,14 +60,26 @@ static VkFormat GetClutDestFormat(GEPaletteFormat format, VkComponentMapping *co DepalShaderCacheVulkan::DepalShaderCacheVulkan(Draw::DrawContext *draw, VulkanContext *vulkan) : draw_(draw), vulkan_(vulkan) { - std::string errors; - vshader_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_VERTEX_BIT, depal_vs, &errors); - assert(vshader_ != VK_NULL_HANDLE); + DeviceRestore(draw, vulkan); } DepalShaderCacheVulkan::~DepalShaderCacheVulkan() { + DeviceLost(); +} + +void DepalShaderCacheVulkan::DeviceLost() { Clear(); vulkan_->Delete().QueueDeleteShaderModule(vshader_); + draw_ = nullptr; + vulkan_ = nullptr; +} + +void DepalShaderCacheVulkan::DeviceRestore(Draw::DrawContext *draw, VulkanContext *vulkan) { + draw_ = draw; + vulkan_ = vulkan; + std::string errors; + vshader_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_VERTEX_BIT, depal_vs, &errors); + assert(vshader_ != VK_NULL_HANDLE); } DepalShaderVulkan *DepalShaderCacheVulkan::GetDepalettizeShader(uint32_t clutMode, GEBufferFormat pixelFormat) { diff --git a/GPU/Vulkan/DepalettizeShaderVulkan.h b/GPU/Vulkan/DepalettizeShaderVulkan.h index bba40a2c09..f06057e0c1 100644 --- a/GPU/Vulkan/DepalettizeShaderVulkan.h +++ b/GPU/Vulkan/DepalettizeShaderVulkan.h @@ -52,6 +52,8 @@ class DepalShaderCacheVulkan : public DepalShaderCacheCommon { public: DepalShaderCacheVulkan(Draw::DrawContext *draw, VulkanContext *vulkan); ~DepalShaderCacheVulkan(); + void DeviceLost(); + void DeviceRestore(Draw::DrawContext *draw, VulkanContext *vulkan); // This also uploads the palette and binds the correct texture. DepalShaderVulkan *GetDepalettizeShader(uint32_t clutMode, GEBufferFormat pixelFormat); diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 580c5bef20..c4d2b9400a 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -93,8 +93,6 @@ DrawEngineVulkan::DrawEngineVulkan(VulkanContext *vulkan, Draw::DrawContext *dra indexGen.Setup(decIndex); InitDeviceObjects(); - - tessDataTransfer = new TessellationDataTransferVulkan(vulkan, draw); } void DrawEngineVulkan::InitDeviceObjects() { @@ -206,6 +204,8 @@ void DrawEngineVulkan::InitDeviceObjects() { assert(VK_SUCCESS == res); vertexCache_ = new VulkanPushBuffer(vulkan_, VERTEX_CACHE_SIZE); + + tessDataTransfer = new TessellationDataTransferVulkan(vulkan_, draw_); } DrawEngineVulkan::~DrawEngineVulkan() { @@ -214,8 +214,6 @@ DrawEngineVulkan::~DrawEngineVulkan() { FreeMemoryPages(splineBuffer, SPLINE_BUFFER_SIZE); DestroyDeviceObjects(); - - delete tessDataTransfer; } void DrawEngineVulkan::FrameData::Destroy(VulkanContext *vulkan) { @@ -241,6 +239,9 @@ void DrawEngineVulkan::FrameData::Destroy(VulkanContext *vulkan) { } void DrawEngineVulkan::DestroyDeviceObjects() { + delete tessDataTransfer; + tessDataTransfer = nullptr; + for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) { frame_[i].Destroy(vulkan_); } @@ -249,11 +250,9 @@ void DrawEngineVulkan::DestroyDeviceObjects() { if (nullSampler_ != VK_NULL_HANDLE) vulkan_->Delete().QueueDeleteSampler(nullSampler_); if (pipelineLayout_ != VK_NULL_HANDLE) - vkDestroyPipelineLayout(vulkan_->GetDevice(), pipelineLayout_, nullptr); - pipelineLayout_ = VK_NULL_HANDLE; + vulkan_->Delete().QueueDeletePipelineLayout(pipelineLayout_); if (descriptorSetLayout_ != VK_NULL_HANDLE) - vkDestroyDescriptorSetLayout(vulkan_->GetDevice(), descriptorSetLayout_, nullptr); - descriptorSetLayout_ = VK_NULL_HANDLE; + vulkan_->Delete().QueueDeleteDescriptorSetLayout(descriptorSetLayout_); if (nullTexture_) { nullTexture_->Destroy(); delete nullTexture_; @@ -262,6 +261,7 @@ void DrawEngineVulkan::DestroyDeviceObjects() { vertexCache_->Destroy(vulkan_); delete vertexCache_; vertexCache_ = nullptr; + vai_.Clear(); // Need to clear this to get rid of all remaining references to the dead buffers. } void DrawEngineVulkan::DeviceLost() { @@ -269,8 +269,9 @@ void DrawEngineVulkan::DeviceLost() { DirtyAllUBOs(); } -void DrawEngineVulkan::DeviceRestore(VulkanContext *vulkan) { +void DrawEngineVulkan::DeviceRestore(VulkanContext *vulkan, Draw::DrawContext *draw) { vulkan_ = vulkan; + draw_ = draw; InitDeviceObjects(); } diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index 2322dfdc45..de4c5e04ef 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -137,7 +137,7 @@ public: } void DeviceLost(); - void DeviceRestore(VulkanContext *vulkan); + void DeviceRestore(VulkanContext *vulkan, Draw::DrawContext *draw); void SetupVertexDecoder(u32 vertType); void SetupVertexDecoderInternal(u32 vertType); diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp index 6abc89637b..9cb3019553 100644 --- a/GPU/Vulkan/FramebufferVulkan.cpp +++ b/GPU/Vulkan/FramebufferVulkan.cpp @@ -88,8 +88,7 @@ FramebufferManagerVulkan::FramebufferManagerVulkan(Draw::DrawContext *draw, Vulk convBufSize_(0), textureCacheVulkan_(nullptr), shaderManagerVulkan_(nullptr), - pipelinePostShader_(VK_NULL_HANDLE), - depalVulkan_(draw, vulkan) { + pipelinePostShader_(VK_NULL_HANDLE) { InitDeviceObjects(); @@ -593,8 +592,9 @@ void FramebufferManagerVulkan::DeviceLost() { DestroyDeviceObjects(); } -void FramebufferManagerVulkan::DeviceRestore(VulkanContext *vulkan) { +void FramebufferManagerVulkan::DeviceRestore(VulkanContext *vulkan, Draw::DrawContext *draw) { vulkan_ = vulkan; + draw_ = draw; vulkan2D_->DeviceRestore(vulkan_); InitDeviceObjects(); diff --git a/GPU/Vulkan/FramebufferVulkan.h b/GPU/Vulkan/FramebufferVulkan.h index 9c37034842..98ac4d9e25 100644 --- a/GPU/Vulkan/FramebufferVulkan.h +++ b/GPU/Vulkan/FramebufferVulkan.h @@ -70,7 +70,7 @@ public: void Resized() override; void DeviceLost(); - void DeviceRestore(VulkanContext *vulkan); + void DeviceRestore(VulkanContext *vulkan, Draw::DrawContext *draw); int GetLineWidth(); void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) override; @@ -120,7 +120,6 @@ private: DrawEngineVulkan *drawEngineVulkan_; VulkanPushBuffer *push_; - DepalShaderCacheVulkan depalVulkan_; enum { MAX_COMMAND_BUFFERS = 32, }; diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 659762c5bf..ecb4c340c3 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -781,13 +781,16 @@ void GPU_Vulkan::FastLoadBoneMatrix(u32 target) { } void GPU_Vulkan::InitDeviceObjects() { + ILOG("GPU_Vulkan::InitDeviceObjects"); // Initialize framedata for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) { + assert(!frameData_[i].push_); frameData_[i].push_ = new VulkanPushBuffer(vulkan_, 64 * 1024); } } void GPU_Vulkan::DestroyDeviceObjects() { + ILOG("GPU_Vulkan::DestroyDeviceObjects"); for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) { if (frameData_[i].push_) { frameData_[i].push_->Destroy(vulkan_); @@ -804,21 +807,25 @@ void GPU_Vulkan::DeviceLost() { drawEngine_.DeviceLost(); pipelineManager_->DeviceLost(); textureCacheVulkan_->DeviceLost(); - depalShaderCache_.Clear(); + depalShaderCache_.DeviceLost(); shaderManagerVulkan_->ClearShaders(); } void GPU_Vulkan::DeviceRestore() { vulkan_ = (VulkanContext *)PSP_CoreParameter().graphicsContext->GetAPIContext(); + draw_ = (Draw::DrawContext *)PSP_CoreParameter().graphicsContext->GetDrawContext(); + InitDeviceObjects(); + CheckGPUFeatures(); BuildReportingInfo(); UpdateCmdInfo(); - framebufferManagerVulkan_->DeviceRestore(vulkan_); - drawEngine_.DeviceRestore(vulkan_); + framebufferManagerVulkan_->DeviceRestore(vulkan_, draw_); + drawEngine_.DeviceRestore(vulkan_, draw_); pipelineManager_->DeviceRestore(vulkan_); - textureCacheVulkan_->DeviceRestore(vulkan_); + textureCacheVulkan_->DeviceRestore(vulkan_, draw_); shaderManagerVulkan_->DeviceRestore(vulkan_); + depalShaderCache_.DeviceRestore(draw_, vulkan_); } void GPU_Vulkan::GetStats(char *buffer, size_t bufsize) { diff --git a/GPU/Vulkan/GPU_Vulkan.h b/GPU/Vulkan/GPU_Vulkan.h index 289a8463f1..d94c4ee768 100644 --- a/GPU/Vulkan/GPU_Vulkan.h +++ b/GPU/Vulkan/GPU_Vulkan.h @@ -119,8 +119,6 @@ private: // Manages state and pipeline objects PipelineManagerVulkan *pipelineManager_; - int lastVsync_; - VkCommandBuffer curCmd_; int vertexCost_ = 0; std::string reportingPrimaryInfo_; diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index 20664c7831..c5ec5d708e 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -126,36 +126,14 @@ void SamplerCache::DeviceRestore(VulkanContext *vulkan) { TextureCacheVulkan::TextureCacheVulkan(Draw::DrawContext *draw, VulkanContext *vulkan) : TextureCacheCommon(draw), vulkan_(vulkan), - samplerCache_(vulkan), - texelsScaledThisFrame_(0) { + samplerCache_(vulkan) { timesInvalidatedAllThisFrame_ = 0; - lastBoundTexture = nullptr; - allocator_ = new VulkanDeviceAllocator(vulkan_, TEXCACHE_MIN_SLAB_SIZE, TEXCACHE_MAX_SLAB_SIZE); - - VkSamplerCreateInfo samp{ VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; - samp.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samp.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samp.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samp.magFilter = VK_FILTER_NEAREST; - samp.minFilter = VK_FILTER_NEAREST; - samp.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; - vkCreateSampler(vulkan_->GetDevice(), &samp, nullptr, &samplerNearest_); + DeviceRestore(vulkan, draw); SetupTextureDecoder(); } TextureCacheVulkan::~TextureCacheVulkan() { - vulkan_->Delete().QueueDeleteSampler(samplerNearest_); - Clear(true); - - if (allocator_) { - allocator_->Destroy(); - - // We have to delete on queue, so this can free its queued deletions. - vulkan_->Delete().QueueCallback([](void *ptr) { - auto allocator = static_cast(ptr); - delete allocator; - }, allocator_); - } + DeviceLost(); } void TextureCacheVulkan::SetFramebufferManager(FramebufferManagerVulkan *fbManager) { @@ -183,17 +161,28 @@ void TextureCacheVulkan::DeviceLost() { } samplerCache_.DeviceLost(); + vulkan_->Delete().QueueDeleteSampler(samplerNearest_); nextTexture_ = nullptr; } -void TextureCacheVulkan::DeviceRestore(VulkanContext *vulkan) { +void TextureCacheVulkan::DeviceRestore(VulkanContext *vulkan, Draw::DrawContext *draw) { vulkan_ = vulkan; + draw_ = draw; assert(!allocator_); allocator_ = new VulkanDeviceAllocator(vulkan_, TEXCACHE_MIN_SLAB_SIZE, TEXCACHE_MAX_SLAB_SIZE); samplerCache_.DeviceRestore(vulkan); + + VkSamplerCreateInfo samp{ VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; + samp.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samp.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samp.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samp.magFilter = VK_FILTER_NEAREST; + samp.minFilter = VK_FILTER_NEAREST; + samp.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + vkCreateSampler(vulkan_->GetDevice(), &samp, nullptr, &samplerNearest_); } void TextureCacheVulkan::ReleaseTexture(TexCacheEntry *entry, bool delete_them) { diff --git a/GPU/Vulkan/TextureCacheVulkan.h b/GPU/Vulkan/TextureCacheVulkan.h index 1b168fd0f5..fa2b070bfe 100644 --- a/GPU/Vulkan/TextureCacheVulkan.h +++ b/GPU/Vulkan/TextureCacheVulkan.h @@ -72,7 +72,7 @@ public: void EndFrame(); void DeviceLost(); - void DeviceRestore(VulkanContext *vulkan); + void DeviceRestore(VulkanContext *vulkan, Draw::DrawContext *draw); void SetFramebufferManager(FramebufferManagerVulkan *fbManager); void SetDepalShaderCache(DepalShaderCacheVulkan *dpCache) { @@ -122,19 +122,19 @@ private: void ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffer *framebuffer) override; void BuildTexture(TexCacheEntry *const entry, bool replaceImages) override; - VulkanContext *vulkan_; - VulkanDeviceAllocator *allocator_; - VulkanPushBuffer *push_; + VulkanContext *vulkan_ = nullptr; + VulkanDeviceAllocator *allocator_ = nullptr; + VulkanPushBuffer *push_ = nullptr; SamplerCache samplerCache_; TextureScalerVulkan scaler; - CachedTextureVulkan *lastBoundTexture; + CachedTextureVulkan *lastBoundTexture = nullptr; - int decimationCounter_; - int texelsScaledThisFrame_; - int timesInvalidatedAllThisFrame_; + int decimationCounter_ = 0; + int texelsScaledThisFrame_ = 0; + int timesInvalidatedAllThisFrame_ = 0; FramebufferManagerVulkan *framebufferManagerVulkan_; DepalShaderCacheVulkan *depalShaderCache_; diff --git a/GPU/Vulkan/VulkanUtil.cpp b/GPU/Vulkan/VulkanUtil.cpp index 01d001a0e3..662f5196c1 100644 --- a/GPU/Vulkan/VulkanUtil.cpp +++ b/GPU/Vulkan/VulkanUtil.cpp @@ -46,11 +46,11 @@ void Vulkan2D::DestroyDeviceObjects() { VkDevice device = vulkan_->GetDevice(); if (descriptorSetLayout_ != VK_NULL_HANDLE) { - vkDestroyDescriptorSetLayout(device, descriptorSetLayout_, nullptr); + vulkan_->Delete().QueueDeleteDescriptorSetLayout(descriptorSetLayout_); descriptorSetLayout_ = VK_NULL_HANDLE; } if (pipelineLayout_ != VK_NULL_HANDLE) { - vkDestroyPipelineLayout(device, pipelineLayout_, nullptr); + vulkan_->Delete().QueueDeletePipelineLayout(pipelineLayout_); pipelineLayout_ = VK_NULL_HANDLE; } diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index bbeb5c9b6d..de5abdf55d 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1104,12 +1104,16 @@ void EmuScreen::deviceLost() { ILOG("EmuScreen::deviceLost()"); if (gpu) gpu->DeviceLost(); + else + ILOG("No gpu to deviceLost!"); } void EmuScreen::deviceRestore() { ILOG("EmuScreen::deviceRestore()"); if (gpu) gpu->DeviceRestore(); + else + ILOG("No gpu to deviceRestore!"); RecreateViews(); } diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index b97edf440d..3c54be8a3c 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -127,6 +127,8 @@ std::unique_ptr uiTexture; ScreenManager *screenManager; std::string config_filename; +bool g_graphicsInited; + #ifdef IOS bool iosCanUseJit; bool targetIsJailbroken; @@ -675,10 +677,13 @@ void NativeInitGraphics(GraphicsContext *graphicsContext) { #endif g_gameInfoCache = new GameInfoCache(); + + g_graphicsInited = true; ILOG("NativeInitGraphics completed"); } void NativeShutdownGraphics() { + g_graphicsInited = false; ILOG("NativeShutdownGraphics"); #ifdef _WIN32 @@ -817,6 +822,7 @@ void NativeRender(GraphicsContext *graphicsContext) { } if (resized) { + ILOG("resized was set to true - resizing"); resized = false; if (uiContext) { @@ -839,6 +845,12 @@ void NativeRender(GraphicsContext *graphicsContext) { graphicsContext->Resize(); screenManager->resized(); + // Do not enable unless you are testing device-loss on Windows +#if 0 + screenManager->deviceLost(); + screenManager->deviceRestore(); +#endif + // TODO: Move this to new GraphicsContext objects for each backend. #ifndef _WIN32 if (GetGPUBackend() == GPUBackend::OPENGL) { @@ -1072,7 +1084,11 @@ void NativeMessageReceived(const char *message, const char *value) { void NativeResized() { // NativeResized can come from any thread so we just set a flag, then process it later. - resized = true; + if (g_graphicsInited) { + resized = true; + } else { + ILOG("NativeResized ignored, not initialized"); + } } void NativeSetRestarting() { diff --git a/Windows/GPU/WindowsVulkanContext.cpp b/Windows/GPU/WindowsVulkanContext.cpp index 4d8e8f152f..0a240afeb4 100644 --- a/Windows/GPU/WindowsVulkanContext.cpp +++ b/Windows/GPU/WindowsVulkanContext.cpp @@ -218,6 +218,8 @@ void WindowsVulkanContext::Shutdown() { g_Vulkan->DestroyObjects(); g_Vulkan->DestroyDevice(); g_Vulkan->DestroyDebugMsgCallback(); + g_Vulkan->DestroyInstance(); + delete g_Vulkan; g_Vulkan = nullptr; diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 8517e5bdf1..d1260fce3c 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -189,6 +189,11 @@ static VulkanContext *g_Vulkan; class AndroidVulkanContext : public AndroidGraphicsContext { public: AndroidVulkanContext() : draw_(nullptr) {} + ~AndroidVulkanContext() { + delete g_Vulkan; + g_Vulkan = nullptr; + } + bool Init(ANativeWindow *wnd, int desiredBackbufferSizeX, int desiredBackbufferSizeY, int backbufferFormat, int androidVersion) override; void Shutdown() override; void SwapInterval(int interval) override; @@ -270,10 +275,7 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL Vulkan_Dbg(VkDebugReportFlagsEXT msgFlags, } bool AndroidVulkanContext::Init(ANativeWindow *wnd, int desiredBackbufferSizeX, int desiredBackbufferSizeY, int backbufferFormat, int androidVersion) { - if (g_Vulkan) { - return false; - } - + ILOG("AndroidVulkanContext::Init"); init_glslang(); g_LogOptions.breakOnError = true; @@ -282,7 +284,10 @@ bool AndroidVulkanContext::Init(ANativeWindow *wnd, int desiredBackbufferSizeX, ILOG("Creating vulkan context"); Version gitVer(PPSSPP_GIT_VERSION); - g_Vulkan = new VulkanContext(); + + if (!g_Vulkan) { + g_Vulkan = new VulkanContext(); + } if (VK_SUCCESS != g_Vulkan->CreateInstance("PPSSPP", gitVer.ToInteger(), VULKAN_FLAG_PRESENT_MAILBOX | VULKAN_FLAG_PRESENT_FIFO_RELAXED)) { ELOG("Failed to create vulkan context: %s", g_Vulkan->InitError().c_str()); delete g_Vulkan; @@ -326,6 +331,7 @@ bool AndroidVulkanContext::Init(ANativeWindow *wnd, int desiredBackbufferSizeX, bool success = draw_->CreatePresets(); // Doesn't fail, we ship the compiler. assert(success); draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); + ILOG("AndroidVulkanContext::Init completed"); return true; } @@ -334,22 +340,27 @@ void AndroidVulkanContext::Shutdown() { draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); delete draw_; draw_ = nullptr; + ILOG("Calling NativeShutdownGraphics"); NativeShutdownGraphics(); g_Vulkan->WaitUntilQueueIdle(); g_Vulkan->DestroyObjects(); - g_Vulkan->DestroyDebugMsgCallback(); g_Vulkan->DestroyDevice(); + g_Vulkan->DestroyDebugMsgCallback(); - delete g_Vulkan; - g_Vulkan = nullptr; + g_Vulkan->DestroyInstance(); + + // We keep the g_Vulkan context around to avoid invalidating a ton of pointers around the app. finalize_glslang(); + ILOG("AndroidVulkanContext::Shutdown completed"); } void AndroidVulkanContext::SwapBuffers() { } void AndroidVulkanContext::Resize() { + ILOG("AndroidVulkanContext::Resize begin (%d, %d)", g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); + draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); g_Vulkan->DestroyObjects(); @@ -357,6 +368,7 @@ void AndroidVulkanContext::Resize() { g_Vulkan->ReinitSurfaceAndroid(pixel_xres, pixel_yres); g_Vulkan->InitObjects(); draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); + ILOG("AndroidVulkanContext::Resize end (%d, %d)", g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); } void AndroidVulkanContext::SwapInterval(int interval) { @@ -729,6 +741,9 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * env, extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_backbufferResize(JNIEnv *, jclass, jint bufw, jint bufh, jint format) { ILOG("NativeApp.backbufferResize(%d x %d)", bufw, bufh); + bool new_size = pixel_xres != bufw || pixel_yres != bufh; + int old_w = pixel_xres; + int old_h = pixel_yres; // pixel_*res is the backbuffer resolution. pixel_xres = bufw; pixel_yres = bufh; @@ -755,7 +770,12 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_backbufferResize(JNIEnv ILOG("dp_xres=%d dp_yres=%d", dp_xres, dp_yres); ILOG("pixel_xres=%d pixel_yres=%d", pixel_xres, pixel_yres); - NativeResized(); + if (new_size) { + ILOG("Size change detected (previously %d,%d) - calling NativeResized()", old_w, old_h); + NativeResized(); + } else { + ILOG("Size didn't change."); + } } @@ -1124,7 +1144,7 @@ retry: ProcessFrameCommands(env); } - ILOG("After render loop."); + ILOG("Leaving EGL/Vulkan render loop."); g_gameInfoCache->WorkQueue()->Flush(); NativeDeviceLost(); diff --git a/android/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java index b48cfae5c1..984ec4ff13 100644 --- a/android/src/org/ppsspp/ppsspp/NativeActivity.java +++ b/android/src/org/ppsspp/ppsspp/NativeActivity.java @@ -58,7 +58,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C // Remember to loadLibrary your JNI .so in a static {} block // Adjust these as necessary - private static String TAG = "NativeActivity"; + private static String TAG = "PPSSPPNativeActivity"; // Allows us to skip a lot of initialization on secondary calls to onCreate. private static boolean initialized = false; @@ -518,24 +518,29 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C } } + Point desiredSize = new Point(); + @Override public void surfaceCreated(SurfaceHolder holder) { pixelWidth = holder.getSurfaceFrame().width(); pixelHeight = holder.getSurfaceFrame().height(); Log.d(TAG, "Surface created. pixelWidth=" + pixelWidth + ", pixelHeight=" + pixelHeight); NativeApp.setDisplayParameters(pixelWidth, pixelHeight, (int)densityDpi, refreshRate); - Point sz = new Point(); - getDesiredBackbufferSize(sz); - Log.d(TAG, "Setting fixed size " + sz.x + " x " + sz.y); + getDesiredBackbufferSize(desiredSize); + Log.d(TAG, "Setting fixed size " + desiredSize.x + " x " + desiredSize.y); if (mGLSurfaceView != null) { - mGLSurfaceView.getHolder().setFixedSize(sz.x, sz.y); + mGLSurfaceView.getHolder().setFixedSize(desiredSize.x, desiredSize.y); } else { - mSurfaceView.getHolder().setFixedSize(sz.x, sz.y); + mSurfaceView.getHolder().setFixedSize(desiredSize.x, desiredSize.y); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + if (width != desiredSize.x || height != desiredSize.y) { + Log.w(TAG, "Surface changed but not to desired size. Ignoring."); + return; + } Log.w(TAG, "Surface changed. Resolution: " + width + "x" + height + " Format: " + format); NativeApp.backbufferResize(width, height, format); mSurface = holder.getSurface(); @@ -647,10 +652,10 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C loseAudioFocus(this.audioManager, this.audioFocusChangeListener); NativeApp.pause(); if (!javaGL) { - Log.i(TAG, "Pausing surface view"); mSurfaceView.onPause(); - Log.i(TAG, "Joining render thread"); + Log.i(TAG, "Joining render thread..."); joinRenderLoopThread(); + Log.i(TAG, "Joined render thread"); } else { if (mGLSurfaceView != null) { mGLSurfaceView.onPause(); diff --git a/ext/native/base/logging.h b/ext/native/base/logging.h index 6650d865b9..3bbff36204 100644 --- a/ext/native/base/logging.h +++ b/ext/native/base/logging.h @@ -53,7 +53,7 @@ void OutputDebugStringUTF8(const char *p); // Must only be used for logging #ifndef APP_NAME -#define APP_NAME "NativeApp" +#define APP_NAME "PPSSPP" #endif #ifdef _DEBUG diff --git a/ext/native/gfx_es2/draw_text_android.cpp b/ext/native/gfx_es2/draw_text_android.cpp index cb5ab910a2..c8e7ed1925 100644 --- a/ext/native/gfx_es2/draw_text_android.cpp +++ b/ext/native/gfx_es2/draw_text_android.cpp @@ -29,7 +29,8 @@ TextDrawerAndroid::TextDrawerAndroid(Draw::DrawContext *draw) : TextDrawer(draw) } else { ELOG("Failed to find class: '%s'", textRendererClassName); } - dpiScale_ = 1.0f; + dpiScale_ = CalculateDPIScale(); + ILOG("Initializing TextDrawerAndroid with DPI scale %f", dpiScale_); } TextDrawerAndroid::~TextDrawerAndroid() { @@ -269,7 +270,8 @@ void TextDrawerAndroid::OncePerFrame() { // If DPI changed (small-mode, future proper monitor DPI support), drop everything. float newDpiScale = CalculateDPIScale(); if (newDpiScale != dpiScale_) { - ILOG("Scale changed - wiping cache"); + // TODO: Don't bother if it's a no-op (cache already empty) + ILOG("DPI Scale changed (%f to %f) - wiping font cache (%d items, %d fonts)", dpiScale_, newDpiScale, (int)cache_.size(), (int)fontMap_.size()); dpiScale_ = newDpiScale; ClearCache(); fontMap_.clear(); // size is precomputed using dpiScale_. diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/ext/native/thin3d/VulkanQueueRunner.cpp index df43465603..bcaaf086a3 100644 --- a/ext/native/thin3d/VulkanQueueRunner.cpp +++ b/ext/native/thin3d/VulkanQueueRunner.cpp @@ -2,13 +2,14 @@ #include "VulkanQueueRunner.h" #include "VulkanRenderManager.h" -// Debug help: adb logcat -s DEBUG NativeActivity NativeApp PPSSPP +// Debug help: adb logcat -s DEBUG PPSSPPNativeActivity PPSSPP // TODO: This is only enough for 4x render resolution / 4x texture upscale for debugger. // Maybe we should use a dynamically allocated one for larger? const uint32_t readbackBufferSize = 2048 * 2048 * 4; void VulkanQueueRunner::CreateDeviceObjects() { + ILOG("VulkanQueueRunner::CreateDeviceObjects"); InitBackbufferRenderPass(); InitRenderpasses(); @@ -36,16 +37,22 @@ void VulkanQueueRunner::CreateDeviceObjects() { } void VulkanQueueRunner::DestroyDeviceObjects() { + ILOG("VulkanQueueRunner::DestroyDeviceObjects"); VkDevice device = vulkan_->GetDevice(); + vulkan_->Delete().QueueDeleteDeviceMemory(readbackMemory_); vkFreeMemory(device, readbackMemory_, nullptr); + readbackMemory_ = VK_NULL_HANDLE; vulkan_->Delete().QueueDeleteBuffer(readbackBuffer_); + readbackBuffer_ = VK_NULL_HANDLE; for (int i = 0; i < ARRAY_SIZE(renderPasses_); i++) { assert(renderPasses_[i] != VK_NULL_HANDLE); - vkDestroyRenderPass(device, renderPasses_[i], nullptr); + vulkan_->Delete().QueueDeleteRenderPass(renderPasses_[i]); + renderPasses_[i] = VK_NULL_HANDLE; } assert(backbufferRenderPass_ != VK_NULL_HANDLE); - vkDestroyRenderPass(device, backbufferRenderPass_, nullptr); + vulkan_->Delete().QueueDeleteRenderPass(backbufferRenderPass_); + backbufferRenderPass_ = VK_NULL_HANDLE; } void VulkanQueueRunner::InitBackbufferRenderPass() { @@ -419,8 +426,8 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c VkClearRect rc{}; rc.baseArrayLayer = 0; rc.layerCount = 1; - rc.rect.extent.width = curWidth; - rc.rect.extent.height = curHeight; + rc.rect.extent.width = (uint32_t)curWidth; + rc.rect.extent.height = (uint32_t)curHeight; VkClearAttachment attachments[2]; if (c.clear.clearMask & VK_IMAGE_ASPECT_COLOR_BIT) { VkClearAttachment &attachment = attachments[numAttachments++]; @@ -436,7 +443,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c attachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; } if (c.clear.clearMask & VK_IMAGE_ASPECT_STENCIL_BIT) { - attachment.clearValue.depthStencil.stencil = c.clear.clearStencil; + attachment.clearValue.depthStencil.stencil = (uint32_t)c.clear.clearStencil; attachment.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; } } diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index 03d1d3b0ce..c2fce09b6f 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -194,12 +194,12 @@ void VulkanRenderManager::CreateBackbuffers() { run_ = true; // Won't necessarily be 0. threadInitFrame_ = vulkan_->GetCurFrame(); - VLOG("starting thread"); + ILOG("Starting Vulkan submission thread (threadInitFrame_ = %d)", vulkan_->GetCurFrame()); thread_ = std::thread(&VulkanRenderManager::ThreadFunc, this); } } -void VulkanRenderManager::StopThread(bool shutdown) { +void VulkanRenderManager::StopThread() { if (useThread && run_) { run_ = false; // Stop the thread. @@ -215,12 +215,21 @@ void VulkanRenderManager::StopThread(bool shutdown) { } } thread_.join(); - VLOG("thread joined."); + ILOG("Vulkan submission thread joined. Frame=%d", vulkan_->GetCurFrame()); + + // Eat whatever has been queued up for this frame if anything. + Wipe(); // Wait for any fences to finish and be resignaled, so we don't have sync issues. + // Also clean out any queued data, which might refer to things that might not be valid + // when we restart... for (int i = 0; i < vulkan_->GetInflightFrames(); i++) { auto &frameData = frameData_[i]; + if (frameData.readyForRun || frameData.hasInitCommands || frameData.steps.size() != 0) { + Crash(); + } frameData.readyForRun = false; + frameData.steps.clear(); std::unique_lock lock(frameData.push_mutex); while (!frameData.readyForFence) { @@ -228,11 +237,13 @@ void VulkanRenderManager::StopThread(bool shutdown) { frameData.push_condVar.wait(lock); } } + } else { + ILOG("Vulkan submission thread was already stopped."); } } void VulkanRenderManager::DestroyBackbuffers() { - StopThread(false); + StopThread(); vulkan_->WaitUntilQueueIdle(); VkDevice device = vulkan_->GetDevice(); @@ -253,7 +264,8 @@ void VulkanRenderManager::DestroyBackbuffers() { } VulkanRenderManager::~VulkanRenderManager() { - StopThread(true); + ILOG("VulkanRenderManager destructor"); + StopThread(); vulkan_->WaitUntilQueueIdle(); VkDevice device = vulkan_->GetDevice(); @@ -274,6 +286,7 @@ void VulkanRenderManager::ThreadFunc() { setCurrentThreadName("RenderMan"); int threadFrame = threadInitFrame_; bool nextFrame = false; + bool firstFrame = true; while (true) { { if (nextFrame) { @@ -301,9 +314,17 @@ void VulkanRenderManager::ThreadFunc() { assert(frameData.type == VKRRunType::END || frameData.type == VKRRunType::SYNC); } VLOG("PULL: Running frame %d", threadFrame); + if (firstFrame) { + ILOG("Running first frame (%d)", threadFrame); + firstFrame = false; + } Run(threadFrame); VLOG("PULL: Finished frame %d", threadFrame); } + + // Wait for the device to be done with everything, before tearing stuff down. + vkDeviceWaitIdle(vulkan_->GetDevice()); + VLOG("PULL: Quitting"); } @@ -330,6 +351,9 @@ void VulkanRenderManager::BeginFrame() { // Must be after the fence - this performs deletes. VLOG("PUSH: BeginFrame %d", curFrame); + if (!run_) { + WLOG("BeginFrame while !run_!"); + } vulkan_->BeginFrame(); insideFrame_ = true; @@ -368,9 +392,7 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR curRenderStep_ = nullptr; } if (curRenderStep_ && curRenderStep_->commands.size() == 0) { -#ifdef _DEBUG - ILOG("Empty render step. Usually happens after uploading pixels.."); -#endif + VLOG("Empty render step. Usually happens after uploading pixels.."); } VKRStep *step = new VKRStep{ VKRStepType::RENDER }; diff --git a/ext/native/thin3d/VulkanRenderManager.h b/ext/native/thin3d/VulkanRenderManager.h index a9faf1ccdd..5a47111226 100644 --- a/ext/native/thin3d/VulkanRenderManager.h +++ b/ext/native/thin3d/VulkanRenderManager.h @@ -222,7 +222,7 @@ private: void FlushSync(); void EndSyncFrame(int frame); - void StopThread(bool shutdown); + void StopThread(); // Permanent objects VkSemaphore acquireSemaphore_; diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 1925f057c3..fffc1f7a1b 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -193,7 +193,7 @@ public: const std::string &GetSource() const { return source_; } ~VKShaderModule() { if (module_) { - vkDestroyShaderModule(device_, module_, nullptr); + vulkan_->Delete().QueueDeleteShaderModule(module_); } } VkShaderModule Get() const { return module_; } @@ -202,7 +202,7 @@ public: } private: - VkDevice device_; + VulkanContext *vulkan_; VkShaderModule module_; VkShaderStageFlagBits vkstage_; bool ok_; @@ -211,9 +211,9 @@ private: }; bool VKShaderModule::Compile(VulkanContext *vulkan, ShaderLanguage language, const uint8_t *data, size_t size) { + vulkan_ = vulkan; // We'll need this to free it later. - device_ = vulkan->GetDevice(); - this->source_ = (const char *)data; + source_ = (const char *)data; std::vector spirv; if (!GLSLtoSPV(vkstage_, source_.c_str(), spirv)) { return false; diff --git a/ext/native/thread/prioritizedworkqueue.cpp b/ext/native/thread/prioritizedworkqueue.cpp index f3b6d3f0e7..1583738f40 100644 --- a/ext/native/thread/prioritizedworkqueue.cpp +++ b/ext/native/thread/prioritizedworkqueue.cpp @@ -31,7 +31,9 @@ void PrioritizedWorkQueue::Flush() { flush_count++; } queue_.clear(); - ILOG("Flushed %d un-executed tasks", flush_count); + if (flush_count > 0) { + ILOG("PrioritizedWorkQueue: Flushed %d un-executed tasks", flush_count); + } } bool PrioritizedWorkQueue::WaitUntilDone(bool all) {