mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-13 01:29:41 +01:00
Merge pull request #10079 from hrydgard/vulkan-android-fixes
Vulkan lost-device fixes
This commit is contained in:
29 files changed
+326
-214
No files matched your search
@@ -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();
|
||||
}
|
||||
@@ -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<VkCommandPool> 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);
|
||||
|
||||
@@ -78,7 +78,6 @@ void VulkanPushBuffer::Destroy(VulkanContext *vulkan) {
|
||||
vulkan->Delete().QueueDeleteBuffer(info.buffer);
|
||||
vulkan->Delete().QueueDeleteDeviceMemory(info.deviceMemory);
|
||||
}
|
||||
|
||||
buffers_.clear();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -119,8 +119,6 @@ private:
|
||||
// Manages state and pipeline objects
|
||||
PipelineManagerVulkan *pipelineManager_;
|
||||
|
||||
int lastVsync_;
|
||||
VkCommandBuffer curCmd_;
|
||||
int vertexCost_ = 0;
|
||||
|
||||
std::string reportingPrimaryInfo_;
|
||||
|
||||
@@ -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<VulkanDeviceAllocator *>(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) {
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
+17
-1
@@ -127,6 +127,8 @@ std::unique_ptr<ManagedTexture> 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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
+30
-10
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<std::mutex> 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 };
|
||||
|
||||
@@ -222,7 +222,7 @@ private:
|
||||
void FlushSync();
|
||||
void EndSyncFrame(int frame);
|
||||
|
||||
void StopThread(bool shutdown);
|
||||
void StopThread();
|
||||
|
||||
// Permanent objects
|
||||
VkSemaphore acquireSemaphore_;
|
||||
|
||||
@@ -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<uint32_t> spirv;
|
||||
if (!GLSLtoSPV(vkstage_, source_.c_str(), spirv)) {
|
||||
return false;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in new issue
Block a user