Merge branch 'master' into TemporaryHackishBranch

# Conflicts:
#	Core/Compatibility.cpp
#	Core/Compatibility.h
#	Core/Config.h
#	UI/GameSettingsScreen.h
#	assets/compat.ini
This commit is contained in:
LunaMoo committed 2019-08-27 01:27:09 +02:00
commit 54f0f224ca
61 files changed
+1330 -621

No files matched your search

+5 -36
View File
@@ -648,10 +648,8 @@ bool CreateEmptyFile(const std::string &filename)
// Deletes the given directory and anything under it. Returns true on success.
bool DeleteDirRecursively(const std::string &directory)
{
#if PPSSPP_PLATFORM(UWP)
return false;
#else
{
//Removed check, it prevents the UWP from deleting store downloads
INFO_LOG(COMMON, "DeleteDirRecursively: %s", directory.c_str());
#ifdef _WIN32
@@ -720,7 +718,6 @@ bool DeleteDirRecursively(const std::string &directory)
closedir(dirp);
#endif
return File::DeleteDir(directory);
#endif
}
@@ -763,43 +760,15 @@ void CopyDir(const std::string &source_path, const std::string &dest_path)
#endif
}
void openIniFile(const std::string fileName) {
std::string iniFile;
void openIniFile(const std::string& fileName) {
#if defined(_WIN32)
#if PPSSPP_PLATFORM(UWP)
// Do nothing.
#else
iniFile = fileName;
// Can't rely on a .txt file extension to auto-open in the right editor,
// so let's find notepad
wchar_t notepad_path[MAX_PATH + 1];
GetSystemDirectory(notepad_path, MAX_PATH);
wcscat(notepad_path, L"\\notepad.exe");
wchar_t ini_path[MAX_PATH + 1] = { 0 };
wcsncpy(ini_path, ConvertUTF8ToWString(iniFile).c_str(), MAX_PATH);
// Flip any slashes...
for (size_t i = 0; i < wcslen(ini_path); i++) {
if (ini_path[i] == '/')
ini_path[i] = '\\';
}
// One for the space, one for the null.
wchar_t command_line[MAX_PATH * 2 + 1 + 1];
wsprintf(command_line, L"%s %s", notepad_path, ini_path);
STARTUPINFO si{};
si.cb = sizeof(si);
si.wShowWindow = SW_SHOW;
PROCESS_INFORMATION pi{};
UINT retval = CreateProcess(0, command_line, 0, 0, 0, 0, 0, 0, &si, &pi);
if (!retval) {
ERROR_LOG(COMMON, "Failed creating notepad process");
}
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
ShellExecuteW(nullptr, L"open", ConvertUTF8ToWString(fileName).c_str(), nullptr, nullptr, SW_SHOW);
#endif
#elif !defined(MOBILE_DEVICE)
std::string iniFile;
#if defined(__APPLE__)
iniFile = "open ";
#else
+1 -1
View File
@@ -117,7 +117,7 @@ std::string GetCurrentDir();
void CopyDir(const std::string &source_path, const std::string &dest_path);
// Opens ini file (cheats, texture replacements etc.)
void openIniFile(const std::string fileName);
void openIniFile(const std::string& fileName);
// Set the current directory to given directory
bool SetCurrentDir(const std::string &directory);
+21 -4
View File
@@ -19,6 +19,7 @@
#ifdef __ANDROID__
#include "base/logging.h"
#include "MemoryUtil.h"
#include "MemArena.h"
#include "StringUtils.h"
@@ -102,12 +103,28 @@ void MemArena::ReleaseView(void* view, size_t size) {
u8* MemArena::Find4GBBase() {
#if PPSSPP_ARCH(64BIT)
// Just grab some random 4GB...
return reinterpret_cast<u8*>(0x2300000000ULL);
// We should probably just go look in /proc/self/maps for some free space.
// But let's try the anonymous mmap trick, just like on 32-bit, but bigger and
// aligned to 4GB for the movk trick. We can ensure that we get an aligned 4GB
// address by grabbing 8GB and aligning the pointer.
const uint64_t EIGHT_GIGS = 0x200000000ULL;
void *base = mmap(0, EIGHT_GIGS, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
if (base) {
ILOG("base: %p", base);
uint64_t aligned_base = ((uint64_t)base + 0xFFFFFFFF) & ~0xFFFFFFFFULL;
ILOG("aligned_base: %p", (void *)aligned_base);
munmap(base, EIGHT_GIGS);
return reinterpret_cast<u8 *>(aligned_base);
} else {
u8 *hardcoded_ptr = reinterpret_cast<u8*>(0x2300000000ULL);
ILOG("Failed to anonymously map 8GB. Fall back to the hardcoded pointer %p.", hardcoded_ptr);
// Just grab some random 4GB...
// This has been known to fail lately though, see issue #12249.
return hardcoded_ptr;
}
#else
// Address masking is used in 32-bit mode, so we can get away with less memory.
void* base = mmap(0, 0x10000000, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_SHARED, -1, 0);
void* base = mmap(0, 0x10000000, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
if (base == MAP_FAILED) {
PanicAlert("Failed to map 256 MB of memory space: %s", strerror(errno));
return 0;
+6 -4
View File
@@ -516,8 +516,8 @@ void VulkanContext::ChooseDevice(int physical_device) {
vkGetPhysicalDeviceQueueFamilyProperties(physical_devices_[physical_device_], &queue_count, nullptr);
assert(queue_count >= 1);
queue_props.resize(queue_count);
vkGetPhysicalDeviceQueueFamilyProperties(physical_devices_[physical_device_], &queue_count, queue_props.data());
queueFamilyProperties_.resize(queue_count);
vkGetPhysicalDeviceQueueFamilyProperties(physical_devices_[physical_device_], &queue_count, queueFamilyProperties_.data());
assert(queue_count >= 1);
// Detect preferred formats, in this order.
@@ -619,7 +619,7 @@ VkResult VulkanContext::CreateDevice() {
queue_info.pQueuePriorities = queue_priorities;
bool found = false;
for (int i = 0; i < (int)queue_count; i++) {
if (queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
if (queueFamilyProperties_[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
queue_info.queueFamilyIndex = i;
found = true;
break;
@@ -816,7 +816,7 @@ bool VulkanContext::InitQueue() {
uint32_t graphicsQueueNodeIndex = UINT32_MAX;
uint32_t presentQueueNodeIndex = UINT32_MAX;
for (uint32_t i = 0; i < queue_count; i++) {
if ((queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
if ((queueFamilyProperties_[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
if (graphicsQueueNodeIndex == UINT32_MAX) {
graphicsQueueNodeIndex = i;
}
@@ -1014,6 +1014,8 @@ bool VulkanContext::InitSwapchain() {
g_display_rot_matrix.setRotationZ270();
std::swap(swapChainExtent_.width, swapChainExtent_.height);
break;
default:
assert(false);
}
} else {
// Let the OS rotate the image (potentially slow on many Android devices)
+6 -2
View File
@@ -201,6 +201,10 @@ public:
return physicalDeviceProperties_[i];
}
const VkQueueFamilyProperties &GetQueueFamilyProperties(int family) const {
return queueFamilyProperties_[family];
}
VkResult GetInstanceLayerExtensionList(const char *layerName, std::vector<VkExtensionProperties> &extensions);
VkResult GetInstanceLayerProperties();
@@ -303,8 +307,8 @@ private:
int physical_device_ = -1;
uint32_t graphics_queue_family_index_ = -1;
std::vector<PhysicalDeviceProps> physicalDeviceProperties_{};
std::vector<VkQueueFamilyProperties> queue_props;
std::vector<PhysicalDeviceProps> physicalDeviceProperties_;
std::vector<VkQueueFamilyProperties> queueFamilyProperties_;
VkPhysicalDeviceMemoryProperties memory_properties{};
// Custom collection of things that are good to know
+7
View File
@@ -113,6 +113,13 @@ VkBool32 VKAPI_CALL VulkanDebugUtilsCallback(
std::ostringstream message;
const char *pMessage = pCallbackData->pMessage;
// Apparent bugs around timestamp validation in the validation layers
if (strstr(pMessage, "vkCmdBeginQuery(): VkQueryPool"))
return false;
if (strstr(pMessage, "vkGetQueryPoolResults() on VkQueryPool"))
return false;
int messageCode = pCallbackData->messageIdNumber;
const char *pLayerPrefix = "";
if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
+1 -4
View File
@@ -142,10 +142,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, VulkanDeviceAllocator *all
if (mapping) {
view_info.components = *mapping;
} else {
view_info.components.r = VK_COMPONENT_SWIZZLE_R;
view_info.components.g = VK_COMPONENT_SWIZZLE_G;
view_info.components.b = VK_COMPONENT_SWIZZLE_B;
view_info.components.a = VK_COMPONENT_SWIZZLE_A;
view_info.components = { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY };
}
view_info.subresourceRange.aspectMask = aspect;
view_info.subresourceRange.baseMipLevel = 0;
+190 -144
View File
@@ -17,8 +17,11 @@
#include "Common/Vulkan/VulkanLoader.h"
#include <vector>
#include <string>
#include "base/logging.h"
#include "base/basictypes.h"
#include "base/NativeApp.h"
#ifndef _WIN32
#include <dlfcn.h>
@@ -61,9 +64,7 @@ PFN_vkGetPhysicalDeviceSparseImageFormatProperties vkGetPhysicalDeviceSparseImag
PFN_vkQueueBindSparse vkQueueBindSparse;
PFN_vkCreateFence vkCreateFence;
PFN_vkDestroyFence vkDestroyFence;
PFN_vkResetFences vkResetFences;
PFN_vkGetFenceStatus vkGetFenceStatus;
PFN_vkWaitForFences vkWaitForFences;
PFN_vkCreateSemaphore vkCreateSemaphore;
PFN_vkDestroySemaphore vkDestroySemaphore;
PFN_vkCreateEvent vkCreateEvent;
@@ -115,7 +116,7 @@ PFN_vkResetCommandPool vkResetCommandPool;
PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers;
PFN_vkFreeCommandBuffers vkFreeCommandBuffers;
// Used frequently
// Used frequently together
PFN_vkCmdBindPipeline vkCmdBindPipeline;
PFN_vkCmdSetViewport vkCmdSetViewport;
PFN_vkCmdSetScissor vkCmdSetScissor;
@@ -128,14 +129,16 @@ PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer;
PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers;
PFN_vkCmdDraw vkCmdDraw;
PFN_vkCmdDrawIndexed vkCmdDrawIndexed;
PFN_vkCmdClearAttachments vkCmdClearAttachments;
PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier;
PFN_vkCmdPushConstants vkCmdPushConstants;
// Every frame to a few times per frame
PFN_vkWaitForFences vkWaitForFences;
PFN_vkResetFences vkResetFences;
PFN_vkBeginCommandBuffer vkBeginCommandBuffer;
PFN_vkEndCommandBuffer vkEndCommandBuffer;
PFN_vkResetCommandBuffer vkResetCommandBuffer;
PFN_vkCmdClearAttachments vkCmdClearAttachments;
PFN_vkCmdSetEvent vkCmdSetEvent;
PFN_vkCmdResetEvent vkCmdResetEvent;
PFN_vkCmdWaitEvents vkCmdWaitEvents;
@@ -147,6 +150,7 @@ PFN_vkCmdBlitImage vkCmdBlitImage;
PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage;
PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer;
// Rare or not used
PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds;
PFN_vkCmdSetLineWidth vkCmdSetLineWidth;
PFN_vkCmdSetDepthBias vkCmdSetDepthBias;
@@ -226,9 +230,15 @@ bool g_vulkanMayBeAvailable = false;
#define LOAD_GLOBAL_FUNC_LOCAL(lib, x) (PFN_ ## x)dlsym(lib, #x);
static const char *device_name_blacklist[] = {
"NVIDIA:SHIELD Tablet K1",
};
static const char *so_names[] = {
"libvulkan.so",
#if !defined(__ANDROID__)
"libvulkan.so.1",
#endif
};
void VulkanSetAvailable(bool available) {
@@ -239,11 +249,23 @@ void VulkanSetAvailable(bool available) {
bool VulkanMayBeAvailable() {
if (g_vulkanAvailabilityChecked)
return g_vulkanMayBeAvailable;
std::string name = System_GetProperty(SYSPROP_NAME);
for (const char *blacklisted_name : device_name_blacklist) {
if (!strcmp(name.c_str(), blacklisted_name)) {
g_vulkanAvailabilityChecked = true;
g_vulkanMayBeAvailable = false;
return false;
}
}
ILOG("VulkanMayBeAvailable: Device allowed ('%s')", name.c_str());
#ifndef _WIN32
void *lib = nullptr;
for (int i = 0; i < ARRAY_SIZE(so_names); i++) {
lib = dlopen(so_names[i], RTLD_NOW | RTLD_LOCAL);
if (lib) {
ILOG("VulkanMayBeAvailable: Library loaded ('%s')", so_names[i]);
break;
}
}
@@ -252,6 +274,7 @@ bool VulkanMayBeAvailable() {
HINSTANCE lib = LoadLibrary(L"vulkan-1.dll");
#endif
if (!lib) {
ILOG("Vulkan loader: Library not available");
g_vulkanAvailabilityChecked = true;
g_vulkanMayBeAvailable = false;
return false;
@@ -270,15 +293,15 @@ bool VulkanMayBeAvailable() {
VkApplicationInfo info{ VK_STRUCTURE_TYPE_APPLICATION_INFO };
std::vector<VkPhysicalDevice> devices;
bool anyGood = false;
const char *instanceExtensions[2]{};
const char *instanceExtensions[10]{};
VkInstance instance = VK_NULL_HANDLE;
VkResult res;
VkResult res = VK_SUCCESS;
uint32_t physicalDeviceCount = 0;
uint32_t instanceExtCount = 1;
uint32_t instanceExtCount = 0;
bool surfaceExtensionFound = false;
bool platformSurfaceExtensionFound = false;
std::vector<VkExtensionProperties> instanceExts;
instanceExtensions[ci.enabledExtensionCount++] = VK_KHR_SURFACE_EXTENSION_NAME;
ci.enabledExtensionCount = 0; // Should have been reset by struct initialization anyway, just paranoia.
#ifdef _WIN32
const char * const platformSurfaceExtension = VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
@@ -288,9 +311,12 @@ bool VulkanMayBeAvailable() {
const char *platformSurfaceExtension = 0;
#endif
if (!localEnumerateInstanceExtensionProperties || !localCreateInstance || !localEnumerate || !localDestroyInstance || !localGetPhysicalDeviceProperties)
if (!localEnumerateInstanceExtensionProperties || !localCreateInstance || !localEnumerate || !localDestroyInstance || !localGetPhysicalDeviceProperties) {
WLOG("VulkanMayBeAvailable: Function pointer missing, bailing");
goto bail;
}
ILOG("VulkanMayBeAvailable: Enumerating instance extensions");
res = localEnumerateInstanceExtensionProperties(nullptr, &instanceExtCount, nullptr);
// Maximum paranoia.
if (res != VK_SUCCESS) {
@@ -301,6 +327,7 @@ bool VulkanMayBeAvailable() {
ELOG("No VK instance extensions - won't be able to present.");
goto bail;
}
ILOG("VulkanMayBeAvailable: Instance extension count: %d", instanceExtCount);
instanceExts.resize(instanceExtCount);
res = localEnumerateInstanceExtensionProperties(nullptr, &instanceExtCount, instanceExts.data());
if (res != VK_SUCCESS) {
@@ -310,11 +337,14 @@ bool VulkanMayBeAvailable() {
if (platformSurfaceExtension) {
for (auto iter : instanceExts) {
ILOG("VulkanMaybeAvailable: Instance extension found: %s (%08x)", iter.extensionName, iter.specVersion);
if (!strcmp(iter.extensionName, platformSurfaceExtension)) {
ILOG("VulkanMayBeAvailable: Found platform surface extension '%s'", platformSurfaceExtension);
instanceExtensions[ci.enabledExtensionCount++] = platformSurfaceExtension;
platformSurfaceExtensionFound = true;
break;
} else if (!strcmp(iter.extensionName, VK_KHR_SURFACE_EXTENSION_NAME)) {
instanceExtensions[ci.enabledExtensionCount++] = VK_KHR_SURFACE_EXTENSION_NAME;
surfaceExtensionFound = true;
}
}
@@ -323,6 +353,11 @@ bool VulkanMayBeAvailable() {
goto bail;
}
}
// This can't happen unless the driver is double-reporting a surface extension.
if (ci.enabledExtensionCount > 2) {
ELOG("Unexpected number of enabled instance extensions");
goto bail;
}
ci.ppEnabledExtensionNames = instanceExtensions;
ci.enabledLayerCount = 0;
@@ -330,29 +365,30 @@ bool VulkanMayBeAvailable() {
info.applicationVersion = 1;
info.engineVersion = 1;
info.pApplicationName = "VulkanChecker";
info.pEngineName = "VulkanChecker";
info.pEngineName = "VulkanCheckerEngine";
ci.pApplicationInfo = &info;
ci.flags = 0;
ILOG("VulkanMayBeAvailable: Calling vkCreateInstance");
res = localCreateInstance(&ci, nullptr, &instance);
if (res != VK_SUCCESS) {
instance = nullptr;
ELOG("Failed to create vulkan instance.");
goto bail;
}
ILOG("Vulkan test instance created successfully.");
ILOG("VulkanMayBeAvailable: Vulkan test instance created successfully.");
res = localEnumerate(instance, &physicalDeviceCount, nullptr);
if (res != VK_SUCCESS) {
ELOG("Failed to count physical devices.");
ELOG("VulkanMayBeAvailable: Failed to count physical devices.");
goto bail;
}
if (physicalDeviceCount == 0) {
ELOG("No physical Vulkan devices.");
ELOG("VulkanMayBeAvailable: No physical Vulkan devices.");
goto bail;
}
devices.resize(physicalDeviceCount);
res = localEnumerate(instance, &physicalDeviceCount, devices.data());
if (res != VK_SUCCESS) {
ELOG("Failed to enumerate physical devices.");
ELOG("VulkanMayBeAvailable: Failed to enumerate physical devices.");
goto bail;
}
anyGood = false;
@@ -372,16 +408,17 @@ bool VulkanMayBeAvailable() {
}
if (!anyGood) {
WLOG("Found Vulkan API, but no good Vulkan device!");
WLOG("VulkanMayBeAvailable: Found Vulkan API, but no good Vulkan device!");
g_vulkanMayBeAvailable = false;
} else {
ILOG("Found working Vulkan API!");
ILOG("VulkanMayBeAvailable: Found working Vulkan API!");
g_vulkanMayBeAvailable = true;
}
bail:
g_vulkanAvailabilityChecked = true;
if (instance) {
ILOG("VulkanMayBeAvailable: Destroying instance");
localDestroyInstance(instance, nullptr);
}
if (lib) {
@@ -401,8 +438,10 @@ bool VulkanLoad() {
#ifndef _WIN32
for (int i = 0; i < ARRAY_SIZE(so_names); i++) {
vulkanLibrary = dlopen(so_names[i], RTLD_NOW | RTLD_LOCAL);
if (vulkanLibrary)
if (vulkanLibrary) {
ILOG("VulkanLoad: Found library '%s'", so_names[i]);
break;
}
}
#else
// LoadLibrary etc
@@ -420,8 +459,19 @@ bool VulkanLoad() {
LOAD_GLOBAL_FUNC(vkEnumerateInstanceExtensionProperties);
LOAD_GLOBAL_FUNC(vkEnumerateInstanceLayerProperties);
WLOG("Vulkan base functions loaded.");
return true;
if (vkCreateInstance && vkGetInstanceProcAddr && vkGetDeviceProcAddr && vkEnumerateInstanceExtensionProperties && vkEnumerateInstanceLayerProperties) {
WLOG("VulkanLoad: Base functions loaded.");
return true;
} else {
ELOG("VulkanLoad: Failed to load Vulkan base functions.");
#ifndef _WIN32
dlclose(vulkanLibrary);
#else
FreeLibrary(vulkanLibrary);
#endif
vulkanLibrary = nullptr;
return false;
}
}
void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanDeviceExtensions &enabledExtensions) {
@@ -439,125 +489,7 @@ void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanDeviceExtensio
LOAD_INSTANCE_FUNC(instance, vkEnumerateDeviceExtensionProperties);
LOAD_INSTANCE_FUNC(instance, vkEnumerateDeviceLayerProperties);
LOAD_INSTANCE_FUNC(instance, vkGetDeviceQueue);
LOAD_INSTANCE_FUNC(instance, vkQueueSubmit);
LOAD_INSTANCE_FUNC(instance, vkQueueWaitIdle);
LOAD_INSTANCE_FUNC(instance, vkDeviceWaitIdle);
LOAD_INSTANCE_FUNC(instance, vkAllocateMemory);
LOAD_INSTANCE_FUNC(instance, vkFreeMemory);
LOAD_INSTANCE_FUNC(instance, vkMapMemory);
LOAD_INSTANCE_FUNC(instance, vkUnmapMemory);
LOAD_INSTANCE_FUNC(instance, vkFlushMappedMemoryRanges);
LOAD_INSTANCE_FUNC(instance, vkInvalidateMappedMemoryRanges);
LOAD_INSTANCE_FUNC(instance, vkGetDeviceMemoryCommitment);
LOAD_INSTANCE_FUNC(instance, vkBindBufferMemory);
LOAD_INSTANCE_FUNC(instance, vkBindImageMemory);
LOAD_INSTANCE_FUNC(instance, vkGetBufferMemoryRequirements);
LOAD_INSTANCE_FUNC(instance, vkGetImageMemoryRequirements);
LOAD_INSTANCE_FUNC(instance, vkGetImageSparseMemoryRequirements);
LOAD_INSTANCE_FUNC(instance, vkGetPhysicalDeviceSparseImageFormatProperties);
LOAD_INSTANCE_FUNC(instance, vkQueueBindSparse);
LOAD_INSTANCE_FUNC(instance, vkCreateFence);
LOAD_INSTANCE_FUNC(instance, vkDestroyFence);
LOAD_INSTANCE_FUNC(instance, vkResetFences);
LOAD_INSTANCE_FUNC(instance, vkGetFenceStatus);
LOAD_INSTANCE_FUNC(instance, vkWaitForFences);
LOAD_INSTANCE_FUNC(instance, vkCreateSemaphore);
LOAD_INSTANCE_FUNC(instance, vkDestroySemaphore);
LOAD_INSTANCE_FUNC(instance, vkCreateEvent);
LOAD_INSTANCE_FUNC(instance, vkDestroyEvent);
LOAD_INSTANCE_FUNC(instance, vkGetEventStatus);
LOAD_INSTANCE_FUNC(instance, vkSetEvent);
LOAD_INSTANCE_FUNC(instance, vkResetEvent);
LOAD_INSTANCE_FUNC(instance, vkCreateQueryPool);
LOAD_INSTANCE_FUNC(instance, vkDestroyQueryPool);
LOAD_INSTANCE_FUNC(instance, vkGetQueryPoolResults);
LOAD_INSTANCE_FUNC(instance, vkCreateBuffer);
LOAD_INSTANCE_FUNC(instance, vkDestroyBuffer);
LOAD_INSTANCE_FUNC(instance, vkCreateBufferView);
LOAD_INSTANCE_FUNC(instance, vkDestroyBufferView);
LOAD_INSTANCE_FUNC(instance, vkCreateImage);
LOAD_INSTANCE_FUNC(instance, vkDestroyImage);
LOAD_INSTANCE_FUNC(instance, vkGetImageSubresourceLayout);
LOAD_INSTANCE_FUNC(instance, vkCreateImageView);
LOAD_INSTANCE_FUNC(instance, vkDestroyImageView);
LOAD_INSTANCE_FUNC(instance, vkCreateShaderModule);
LOAD_INSTANCE_FUNC(instance, vkDestroyShaderModule);
LOAD_INSTANCE_FUNC(instance, vkCreatePipelineCache);
LOAD_INSTANCE_FUNC(instance, vkDestroyPipelineCache);
LOAD_INSTANCE_FUNC(instance, vkGetPipelineCacheData);
LOAD_INSTANCE_FUNC(instance, vkMergePipelineCaches);
LOAD_INSTANCE_FUNC(instance, vkCreateGraphicsPipelines);
LOAD_INSTANCE_FUNC(instance, vkCreateComputePipelines);
LOAD_INSTANCE_FUNC(instance, vkDestroyPipeline);
LOAD_INSTANCE_FUNC(instance, vkCreatePipelineLayout);
LOAD_INSTANCE_FUNC(instance, vkDestroyPipelineLayout);
LOAD_INSTANCE_FUNC(instance, vkCreateSampler);
LOAD_INSTANCE_FUNC(instance, vkDestroySampler);
LOAD_INSTANCE_FUNC(instance, vkCreateDescriptorSetLayout);
LOAD_INSTANCE_FUNC(instance, vkDestroyDescriptorSetLayout);
LOAD_INSTANCE_FUNC(instance, vkCreateDescriptorPool);
LOAD_INSTANCE_FUNC(instance, vkDestroyDescriptorPool);
LOAD_INSTANCE_FUNC(instance, vkResetDescriptorPool);
LOAD_INSTANCE_FUNC(instance, vkAllocateDescriptorSets);
LOAD_INSTANCE_FUNC(instance, vkFreeDescriptorSets);
LOAD_INSTANCE_FUNC(instance, vkUpdateDescriptorSets);
LOAD_INSTANCE_FUNC(instance, vkCreateFramebuffer);
LOAD_INSTANCE_FUNC(instance, vkDestroyFramebuffer);
LOAD_INSTANCE_FUNC(instance, vkCreateRenderPass);
LOAD_INSTANCE_FUNC(instance, vkDestroyRenderPass);
LOAD_INSTANCE_FUNC(instance, vkGetRenderAreaGranularity);
LOAD_INSTANCE_FUNC(instance, vkCreateCommandPool);
LOAD_INSTANCE_FUNC(instance, vkDestroyCommandPool);
LOAD_INSTANCE_FUNC(instance, vkResetCommandPool);
LOAD_INSTANCE_FUNC(instance, vkAllocateCommandBuffers);
LOAD_INSTANCE_FUNC(instance, vkFreeCommandBuffers);
LOAD_INSTANCE_FUNC(instance, vkBeginCommandBuffer);
LOAD_INSTANCE_FUNC(instance, vkEndCommandBuffer);
LOAD_INSTANCE_FUNC(instance, vkResetCommandBuffer);
LOAD_INSTANCE_FUNC(instance, vkCmdBindPipeline);
LOAD_INSTANCE_FUNC(instance, vkCmdSetViewport);
LOAD_INSTANCE_FUNC(instance, vkCmdSetScissor);
LOAD_INSTANCE_FUNC(instance, vkCmdSetLineWidth);
LOAD_INSTANCE_FUNC(instance, vkCmdSetDepthBias);
LOAD_INSTANCE_FUNC(instance, vkCmdSetBlendConstants);
LOAD_INSTANCE_FUNC(instance, vkCmdSetDepthBounds);
LOAD_INSTANCE_FUNC(instance, vkCmdSetStencilCompareMask);
LOAD_INSTANCE_FUNC(instance, vkCmdSetStencilWriteMask);
LOAD_INSTANCE_FUNC(instance, vkCmdSetStencilReference);
LOAD_INSTANCE_FUNC(instance, vkCmdBindDescriptorSets);
LOAD_INSTANCE_FUNC(instance, vkCmdBindIndexBuffer);
LOAD_INSTANCE_FUNC(instance, vkCmdBindVertexBuffers);
LOAD_INSTANCE_FUNC(instance, vkCmdDraw);
LOAD_INSTANCE_FUNC(instance, vkCmdDrawIndexed);
LOAD_INSTANCE_FUNC(instance, vkCmdDrawIndirect);
LOAD_INSTANCE_FUNC(instance, vkCmdDrawIndexedIndirect);
LOAD_INSTANCE_FUNC(instance, vkCmdDispatch);
LOAD_INSTANCE_FUNC(instance, vkCmdDispatchIndirect);
LOAD_INSTANCE_FUNC(instance, vkCmdCopyBuffer);
LOAD_INSTANCE_FUNC(instance, vkCmdCopyImage);
LOAD_INSTANCE_FUNC(instance, vkCmdBlitImage);
LOAD_INSTANCE_FUNC(instance, vkCmdCopyBufferToImage);
LOAD_INSTANCE_FUNC(instance, vkCmdCopyImageToBuffer);
LOAD_INSTANCE_FUNC(instance, vkCmdUpdateBuffer);
LOAD_INSTANCE_FUNC(instance, vkCmdFillBuffer);
LOAD_INSTANCE_FUNC(instance, vkCmdClearColorImage);
LOAD_INSTANCE_FUNC(instance, vkCmdClearDepthStencilImage);
LOAD_INSTANCE_FUNC(instance, vkCmdClearAttachments);
LOAD_INSTANCE_FUNC(instance, vkCmdResolveImage);
LOAD_INSTANCE_FUNC(instance, vkCmdSetEvent);
LOAD_INSTANCE_FUNC(instance, vkCmdResetEvent);
LOAD_INSTANCE_FUNC(instance, vkCmdWaitEvents);
LOAD_INSTANCE_FUNC(instance, vkCmdPipelineBarrier);
LOAD_INSTANCE_FUNC(instance, vkCmdBeginQuery);
LOAD_INSTANCE_FUNC(instance, vkCmdEndQuery);
LOAD_INSTANCE_FUNC(instance, vkCmdResetQueryPool);
LOAD_INSTANCE_FUNC(instance, vkCmdWriteTimestamp);
LOAD_INSTANCE_FUNC(instance, vkCmdCopyQueryPoolResults);
LOAD_INSTANCE_FUNC(instance, vkCmdPushConstants);
LOAD_INSTANCE_FUNC(instance, vkCmdBeginRenderPass);
LOAD_INSTANCE_FUNC(instance, vkCmdNextSubpass);
LOAD_INSTANCE_FUNC(instance, vkCmdEndRenderPass);
LOAD_INSTANCE_FUNC(instance, vkCmdExecuteCommands);
LOAD_INSTANCE_FUNC(instance, vkGetPhysicalDeviceSurfaceSupportKHR);
LOAD_INSTANCE_FUNC(instance, vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
@@ -609,15 +541,129 @@ void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanDeviceExtensio
// On some implementations, loading functions (that have Device as their first parameter) via vkGetDeviceProcAddr may
// increase performance - but then these function pointers will only work on that specific device. Thus, this loader is not very
// good for multi-device.
// good for multi-device - not likely we'll ever try that anyway though.
void VulkanLoadDeviceFunctions(VkDevice device, const VulkanDeviceExtensions &enabledExtensions) {
WLOG("Vulkan device functions loaded.");
// TODO: Move more functions VulkanLoadInstanceFunctions to here.
LOAD_DEVICE_FUNC(device, vkCreateSwapchainKHR);
LOAD_DEVICE_FUNC(device, vkDestroySwapchainKHR);
LOAD_DEVICE_FUNC(device, vkGetSwapchainImagesKHR);
LOAD_DEVICE_FUNC(device, vkAcquireNextImageKHR);
LOAD_DEVICE_FUNC(device, vkQueuePresentKHR);
LOAD_DEVICE_FUNC(device, vkQueueSubmit);
LOAD_DEVICE_FUNC(device, vkQueueWaitIdle);
LOAD_DEVICE_FUNC(device, vkAllocateMemory);
LOAD_DEVICE_FUNC(device, vkFreeMemory);
LOAD_DEVICE_FUNC(device, vkMapMemory);
LOAD_DEVICE_FUNC(device, vkUnmapMemory);
LOAD_DEVICE_FUNC(device, vkFlushMappedMemoryRanges);
LOAD_DEVICE_FUNC(device, vkInvalidateMappedMemoryRanges);
LOAD_DEVICE_FUNC(device, vkGetDeviceMemoryCommitment);
LOAD_DEVICE_FUNC(device, vkBindBufferMemory);
LOAD_DEVICE_FUNC(device, vkBindImageMemory);
LOAD_DEVICE_FUNC(device, vkGetBufferMemoryRequirements);
LOAD_DEVICE_FUNC(device, vkGetImageMemoryRequirements);
LOAD_DEVICE_FUNC(device, vkGetImageSparseMemoryRequirements);
LOAD_DEVICE_FUNC(device, vkGetPhysicalDeviceSparseImageFormatProperties);
LOAD_DEVICE_FUNC(device, vkQueueBindSparse);
LOAD_DEVICE_FUNC(device, vkCreateFence);
LOAD_DEVICE_FUNC(device, vkDestroyFence);
LOAD_DEVICE_FUNC(device, vkResetFences);
LOAD_DEVICE_FUNC(device, vkGetFenceStatus);
LOAD_DEVICE_FUNC(device, vkWaitForFences);
LOAD_DEVICE_FUNC(device, vkCreateSemaphore);
LOAD_DEVICE_FUNC(device, vkDestroySemaphore);
LOAD_DEVICE_FUNC(device, vkCreateEvent);
LOAD_DEVICE_FUNC(device, vkDestroyEvent);
LOAD_DEVICE_FUNC(device, vkGetEventStatus);
LOAD_DEVICE_FUNC(device, vkSetEvent);
LOAD_DEVICE_FUNC(device, vkResetEvent);
LOAD_DEVICE_FUNC(device, vkCreateQueryPool);
LOAD_DEVICE_FUNC(device, vkDestroyQueryPool);
LOAD_DEVICE_FUNC(device, vkGetQueryPoolResults);
LOAD_DEVICE_FUNC(device, vkCreateBuffer);
LOAD_DEVICE_FUNC(device, vkDestroyBuffer);
LOAD_DEVICE_FUNC(device, vkCreateBufferView);
LOAD_DEVICE_FUNC(device, vkDestroyBufferView);
LOAD_DEVICE_FUNC(device, vkCreateImage);
LOAD_DEVICE_FUNC(device, vkDestroyImage);
LOAD_DEVICE_FUNC(device, vkGetImageSubresourceLayout);
LOAD_DEVICE_FUNC(device, vkCreateImageView);
LOAD_DEVICE_FUNC(device, vkDestroyImageView);
LOAD_DEVICE_FUNC(device, vkCreateShaderModule);
LOAD_DEVICE_FUNC(device, vkDestroyShaderModule);
LOAD_DEVICE_FUNC(device, vkCreatePipelineCache);
LOAD_DEVICE_FUNC(device, vkDestroyPipelineCache);
LOAD_DEVICE_FUNC(device, vkGetPipelineCacheData);
LOAD_DEVICE_FUNC(device, vkMergePipelineCaches);
LOAD_DEVICE_FUNC(device, vkCreateGraphicsPipelines);
LOAD_DEVICE_FUNC(device, vkCreateComputePipelines);
LOAD_DEVICE_FUNC(device, vkDestroyPipeline);
LOAD_DEVICE_FUNC(device, vkCreatePipelineLayout);
LOAD_DEVICE_FUNC(device, vkDestroyPipelineLayout);
LOAD_DEVICE_FUNC(device, vkCreateSampler);
LOAD_DEVICE_FUNC(device, vkDestroySampler);
LOAD_DEVICE_FUNC(device, vkCreateDescriptorSetLayout);
LOAD_DEVICE_FUNC(device, vkDestroyDescriptorSetLayout);
LOAD_DEVICE_FUNC(device, vkCreateDescriptorPool);
LOAD_DEVICE_FUNC(device, vkDestroyDescriptorPool);
LOAD_DEVICE_FUNC(device, vkResetDescriptorPool);
LOAD_DEVICE_FUNC(device, vkAllocateDescriptorSets);
LOAD_DEVICE_FUNC(device, vkFreeDescriptorSets);
LOAD_DEVICE_FUNC(device, vkUpdateDescriptorSets);
LOAD_DEVICE_FUNC(device, vkCreateFramebuffer);
LOAD_DEVICE_FUNC(device, vkDestroyFramebuffer);
LOAD_DEVICE_FUNC(device, vkCreateRenderPass);
LOAD_DEVICE_FUNC(device, vkDestroyRenderPass);
LOAD_DEVICE_FUNC(device, vkGetRenderAreaGranularity);
LOAD_DEVICE_FUNC(device, vkCreateCommandPool);
LOAD_DEVICE_FUNC(device, vkDestroyCommandPool);
LOAD_DEVICE_FUNC(device, vkResetCommandPool);
LOAD_DEVICE_FUNC(device, vkAllocateCommandBuffers);
LOAD_DEVICE_FUNC(device, vkFreeCommandBuffers);
LOAD_DEVICE_FUNC(device, vkBeginCommandBuffer);
LOAD_DEVICE_FUNC(device, vkEndCommandBuffer);
LOAD_DEVICE_FUNC(device, vkResetCommandBuffer);
LOAD_DEVICE_FUNC(device, vkCmdBindPipeline);
LOAD_DEVICE_FUNC(device, vkCmdSetViewport);
LOAD_DEVICE_FUNC(device, vkCmdSetScissor);
LOAD_DEVICE_FUNC(device, vkCmdSetLineWidth);
LOAD_DEVICE_FUNC(device, vkCmdSetDepthBias);
LOAD_DEVICE_FUNC(device, vkCmdSetBlendConstants);
LOAD_DEVICE_FUNC(device, vkCmdSetDepthBounds);
LOAD_DEVICE_FUNC(device, vkCmdSetStencilCompareMask);
LOAD_DEVICE_FUNC(device, vkCmdSetStencilWriteMask);
LOAD_DEVICE_FUNC(device, vkCmdSetStencilReference);
LOAD_DEVICE_FUNC(device, vkCmdBindDescriptorSets);
LOAD_DEVICE_FUNC(device, vkCmdBindIndexBuffer);
LOAD_DEVICE_FUNC(device, vkCmdBindVertexBuffers);
LOAD_DEVICE_FUNC(device, vkCmdDraw);
LOAD_DEVICE_FUNC(device, vkCmdDrawIndexed);
LOAD_DEVICE_FUNC(device, vkCmdDrawIndirect);
LOAD_DEVICE_FUNC(device, vkCmdDrawIndexedIndirect);
LOAD_DEVICE_FUNC(device, vkCmdDispatch);
LOAD_DEVICE_FUNC(device, vkCmdDispatchIndirect);
LOAD_DEVICE_FUNC(device, vkCmdCopyBuffer);
LOAD_DEVICE_FUNC(device, vkCmdCopyImage);
LOAD_DEVICE_FUNC(device, vkCmdBlitImage);
LOAD_DEVICE_FUNC(device, vkCmdCopyBufferToImage);
LOAD_DEVICE_FUNC(device, vkCmdCopyImageToBuffer);
LOAD_DEVICE_FUNC(device, vkCmdUpdateBuffer);
LOAD_DEVICE_FUNC(device, vkCmdFillBuffer);
LOAD_DEVICE_FUNC(device, vkCmdClearColorImage);
LOAD_DEVICE_FUNC(device, vkCmdClearDepthStencilImage);
LOAD_DEVICE_FUNC(device, vkCmdClearAttachments);
LOAD_DEVICE_FUNC(device, vkCmdResolveImage);
LOAD_DEVICE_FUNC(device, vkCmdSetEvent);
LOAD_DEVICE_FUNC(device, vkCmdResetEvent);
LOAD_DEVICE_FUNC(device, vkCmdWaitEvents);
LOAD_DEVICE_FUNC(device, vkCmdPipelineBarrier);
LOAD_DEVICE_FUNC(device, vkCmdBeginQuery);
LOAD_DEVICE_FUNC(device, vkCmdEndQuery);
LOAD_DEVICE_FUNC(device, vkCmdResetQueryPool);
LOAD_DEVICE_FUNC(device, vkCmdWriteTimestamp);
LOAD_DEVICE_FUNC(device, vkCmdCopyQueryPoolResults);
LOAD_DEVICE_FUNC(device, vkCmdPushConstants);
LOAD_DEVICE_FUNC(device, vkCmdBeginRenderPass);
LOAD_DEVICE_FUNC(device, vkCmdNextSubpass);
LOAD_DEVICE_FUNC(device, vkCmdEndRenderPass);
LOAD_DEVICE_FUNC(device, vkCmdExecuteCommands);
if (enabledExtensions.EXT_external_memory_host) {
LOAD_DEVICE_FUNC(device, vkGetMemoryHostPointerPropertiesEXT);
}
+1
View File
@@ -68,6 +68,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) {
CheckSetting(iniFile, gameID, "DisableAccurateDepth", &flags_.DisableAccurateDepth);
CheckSetting(iniFile, gameID, "MGS2AcidHack", &flags_.MGS2AcidHack);
CheckSetting(iniFile, gameID, "SonicRivalsHack", &flags_.SonicRivalsHack);
CheckSetting(iniFile, gameID, "RenderPassMerge", &flags_.RenderPassMerge);
CheckSetting(iniFile, gameID, "AdhocHackDisableNBSwitch", &flags_.AdhocHackDisableNBSwitch);
CheckSetting(iniFile, gameID, "AdhocHackStopFriendClear", &flags_.AdhocHackStopFriendClear);
CheckSetting(iniFile, gameID, "AdhocHackPhantasyStarOffset", &flags_.AdhocHackPhantasyStarOffset);
+1
View File
@@ -68,6 +68,7 @@ struct CompatFlags {
bool DisableAccurateDepth;
bool MGS2AcidHack;
bool SonicRivalsHack;
bool RenderPassMerge;
bool AdhocHackDisableNBSwitch;
bool AdhocHackStopFriendClear;
bool AdhocHackPhantasyStarOffset;
+9 -1
View File
@@ -582,7 +582,14 @@ static int DefaultGPUBackend() {
if (DoesVersionMatchWindows(6, 2, 0, 0, true)) {
return (int)GPUBackend::DIRECT3D11;
}
#elif PPSSPP_PLATFORM(ANDROID)
// Default to Vulkan only on Pie (level 28) devices or newer. Drivers before Pie
// were generally too unreliable to default to (with some exceptions, of course).
if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 28) {
return (int)GPUBackend::VULKAN;
}
#endif
// TODO: On some additional Linux platforms, we should also default to Vulkan.
return (int)GPUBackend::OPENGL;
}
@@ -980,9 +987,10 @@ static ConfigSetting debuggerSettings[] = {
ConfigSetting("FontWidth", &g_Config.iFontWidth, 8),
ConfigSetting("FontHeight", &g_Config.iFontHeight, 12),
ConfigSetting("DisplayStatusBar", &g_Config.bDisplayStatusBar, true),
ConfigSetting("ShowBottomTabTitles",&g_Config.bShowBottomTabTitles,true),
ConfigSetting("ShowBottomTabTitles",&g_Config.bShowBottomTabTitles, true),
ConfigSetting("ShowDeveloperMenu", &g_Config.bShowDeveloperMenu, false),
ConfigSetting("ShowAllocatorDebug", &g_Config.bShowAllocatorDebug, false, false),
ConfigSetting("ShowGpuProfile", &g_Config.bShowGpuProfile, false, false),
ConfigSetting("SkipDeadbeefFilling", &g_Config.bSkipDeadbeefFilling, false),
ConfigSetting("FuncHashMap", &g_Config.bFuncHashMap, false),
+9 -10
View File
@@ -71,21 +71,20 @@ public:
bool bEnableLogging;
bool bDumpDecryptedEboot;
bool bFullscreenOnDoubleclick;
#if defined(USING_WIN_UI)
// These four are Win UI only
bool bPauseOnLostFocus;
bool bTopMost;
bool bIgnoreWindowsKey;
bool bRestartRequired;
#endif
#if defined(USING_WIN_UI) || defined(USING_QT_UI) || PPSSPP_PLATFORM(UWP)
std::string sFont;
#endif
bool bPauseWhenMinimized;
#if !defined(MOBILE_DEVICE)
// Not used on mobile devices.
bool bPauseExitsEmulator;
#endif
bool bPauseMenuExitsEmulator;
// Core
@@ -136,9 +135,8 @@ public:
// We have separate device parameters for each backend so it doesn't get erased if you switch backends.
// If not set, will use the "best" device.
std::string sVulkanDevice;
#ifdef _WIN32
std::string sD3D11Device;
#endif
std::string sD3D11Device; // Windows only
bool bSoftwareRendering;
bool bHardwareTransform; // only used in the GLES backend
bool bSoftwareSkinning; // may speed up some games
@@ -247,6 +245,7 @@ public:
bool bLogFrameDrops;
bool bShowDebugStats;
bool bShowAudioDebug;
bool bShowGpuProfile;
bool bAudioResampler;
//Analog stick tilting
@@ -379,8 +378,8 @@ public:
int iPSPModel;
int iFirmwareVersion;
// TODO: Make this work with your platform, too!
#if defined(USING_WIN_UI)
bool bBypassOSKWithKeyboard;
#if defined(USING_WIN_UI)
bool bDisableWinMenu;
bool bDisableWinBorders;
#endif
+12 -8
View File
@@ -23,6 +23,7 @@
#include "Core/HLE/FunctionWrappers.h"
#include "Core/HLE/sceJpeg.h"
#include "Core/HLE/sceMpeg.h"
#include "GPU/GPUCommon.h"
#include "Core/MemMap.h"
#include "Core/Reporting.h"
@@ -112,7 +113,10 @@ static void __JpegCsc(u32 imageAddr, u32 yCbCrAddr, int widthHeight, int bufferW
static int sceJpegMJpegCsc(u32 imageAddr, u32 yCbCrAddr, int widthHeight, int bufferWidth) {
__JpegCsc(imageAddr, yCbCrAddr, widthHeight, bufferWidth);
DEBUG_LOG(ME, "sceJpegMJpegCsc(%i, %i, %i, %i)", imageAddr, yCbCrAddr, widthHeight, bufferWidth);
int width = (widthHeight >> 16) & 0xFFF;
int height = widthHeight & 0xFFF;
DEBUG_LOG(ME, "sceJpegMJpegCsc(%08x, %08x, (%dx%d), %i)", imageAddr, yCbCrAddr, width, height, bufferWidth);
gpu->NotifyVideoUpload(imageAddr, width * height * 4, width, GE_FORMAT_8888);
return 0;
}
@@ -165,7 +169,7 @@ static int sceJpegDecodeMJpeg(u32 jpegAddr, int jpegSize, u32 imageAddr, int dht
return 0;
}
DEBUG_LOG(ME, "sceJpegDecodeMJpeg(%i, %i, %i, %i)", jpegAddr, jpegSize, imageAddr, dhtMode);
DEBUG_LOG(ME, "sceJpegDecodeMJpeg(%08x, %i, %08x, %i)", jpegAddr, jpegSize, imageAddr, dhtMode);
return __DecodeJpeg(jpegAddr, jpegSize, imageAddr);
}
@@ -180,19 +184,19 @@ static int sceJpegDecodeMJpegSuccessively(u32 jpegAddr, int jpegSize, u32 imageA
return 0;
}
DEBUG_LOG(ME, "sceJpegDecodeMJpegSuccessively(%i, %i, %i, %i)", jpegAddr, jpegSize, imageAddr, dhtMode);
DEBUG_LOG(ME, "sceJpegDecodeMJpegSuccessively(%08x, %i, %08x, %i)", jpegAddr, jpegSize, imageAddr, dhtMode);
return __DecodeJpeg(jpegAddr, jpegSize, imageAddr);
}
static int sceJpegCsc(u32 imageAddr, u32 yCbCrAddr, int widthHeight, int bufferWidth, int colourInfo) {
if (bufferWidth < 0 || widthHeight < 0){
WARN_LOG(ME, "sceJpegCsc(%i, %i, %i, %i, %i)", imageAddr, yCbCrAddr, widthHeight, bufferWidth, colourInfo);
WARN_LOG(ME, "sceJpegCsc(%08x, %08x, %i, %i, %i)", imageAddr, yCbCrAddr, widthHeight, bufferWidth, colourInfo);
return ERROR_JPEG_INVALID_VALUE;
}
__JpegCsc(imageAddr, yCbCrAddr, widthHeight, bufferWidth);
DEBUG_LOG(ME, "sceJpegCsc(%i, %i, %i, %i, %i)", imageAddr, yCbCrAddr, widthHeight, bufferWidth, colourInfo);
DEBUG_LOG(ME, "sceJpegCsc(%08x, %08x, %i, %i, %i)", imageAddr, yCbCrAddr, widthHeight, bufferWidth, colourInfo);
return 0;
}
@@ -257,7 +261,7 @@ static int sceJpegGetOutputInfo(u32 jpegAddr, int jpegSize, u32 colourInfoAddr,
return getYCbCrBufferSize(0, 0);
}
DEBUG_LOG(ME, "sceJpegGetOutputInfo(%i, %i, %i, %i)", jpegAddr, jpegSize, colourInfoAddr, dhtMode);
DEBUG_LOG(ME, "sceJpegGetOutputInfo(%08x, %i, %08x, %i)", jpegAddr, jpegSize, colourInfoAddr, dhtMode);
return __JpegGetOutputInfo(jpegAddr, jpegSize, colourInfoAddr);
}
@@ -345,7 +349,7 @@ static int sceJpegDecodeMJpegYCbCr(u32 jpegAddr, int jpegSize, u32 yCbCrAddr, in
return getWidthHeight(0, 0);
}
DEBUG_LOG(ME, "sceJpegDecodeMJpegYCbCr(%i, %i, %i, %i, %i)", jpegAddr, jpegSize, yCbCrAddr, yCbCrSize, dhtMode);
DEBUG_LOG(ME, "sceJpegDecodeMJpegYCbCr(%08x, %i, %08x, %i, %i)", jpegAddr, jpegSize, yCbCrAddr, yCbCrSize, dhtMode);
return __JpegDecodeMJpegYCbCr(jpegAddr, jpegSize, yCbCrAddr);
}
@@ -355,7 +359,7 @@ static int sceJpegDecodeMJpegYCbCrSuccessively(u32 jpegAddr, int jpegSize, u32 y
return getWidthHeight(0, 0);
}
DEBUG_LOG(ME, "sceJpegDecodeMJpegYCbCrSuccessively(%i, %i, %i, %i, %i)", jpegAddr, jpegSize, yCbCrAddr, yCbCrSize, dhtMode);
DEBUG_LOG(ME, "sceJpegDecodeMJpegYCbCrSuccessively(%08x, %i, %08x, %i, %i)", jpegAddr, jpegSize, yCbCrAddr, yCbCrSize, dhtMode);
// Do as same way as sceJpegDecodeMJpegYCbCr() but with smaller block size
return __JpegDecodeMJpegYCbCr(jpegAddr, jpegSize, yCbCrAddr);
}
+4
View File
@@ -81,6 +81,7 @@
#include "sceHeap.h"
#include "sceDmac.h"
#include "sceMp4.h"
#include "sceUsbCam.h"
#include "../Util/PPGeDraw.h"
@@ -143,6 +144,7 @@ void __KernelInit()
__AudioCodecInit();
__VideoPmpInit();
__UsbGpsInit();
__UsbCamInit();
SaveState::Init(); // Must be after IO, as it may create a directory
Reporting::Init();
@@ -166,6 +168,8 @@ void __KernelShutdown()
hleCurrentThreadName = NULL;
kernelObjects.Clear();
__UsbCamShutdown();
__AudioCodecShutdown();
__VideoPmpShutdown();
__AACShutdown();
+5 -5
View File
@@ -63,13 +63,13 @@ void __UsbDoState(PointerWrap &p)
}
static int sceUsbStart(const char* driverName, u32 argsSize, u32 argsPtr) {
ERROR_LOG(HLE, "UNIMPL sceUsbStart(%s, %i, %08x)", driverName, argsSize, argsPtr);
INFO_LOG(HLE, "sceUsbStart(%s, %i, %08x)", driverName, argsSize, argsPtr);
usbStarted = true;
return 0;
}
static int sceUsbStop(const char* driverName, u32 argsSize, u32 argsPtr) {
ERROR_LOG(HLE, "UNIMPL sceUsbStop(%s, %i, %08x)", driverName, argsSize, argsPtr);
INFO_LOG(HLE, "sceUsbStop(%s, %i, %08x)", driverName, argsSize, argsPtr);
usbStarted = false;
return 0;
}
@@ -83,18 +83,18 @@ static int sceUsbGetState() {
| (usbConnected ? USB_STATUS_CONNECTED : USB_STATUS_DISCONNECTED)
| (usbActivated ? USB_STATUS_ACTIVATED : USB_STATUS_DEACTIVATED);
}
ERROR_LOG(HLE, "UNIMPL sceUsbGetState: 0x%x", state);
INFO_LOG(HLE, "sceUsbGetState: 0x%x", state);
return state;
}
static int sceUsbActivate(u32 pid) {
ERROR_LOG(HLE, "UNIMPL sceUsbActivate(%i)", pid);
INFO_LOG(HLE, "sceUsbActivate(%i)", pid);
usbActivated = true;
return 0;
}
static int sceUsbDeactivate(u32 pid) {
ERROR_LOG(HLE, "UNIMPL sceUsbDeactivate(%i)", pid);
INFO_LOG(HLE, "sceUsbDeactivate(%i)", pid);
usbActivated = false;
return 0;
}
+40 -18
View File
@@ -15,6 +15,7 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <algorithm>
#include <mutex>
#include "base/NativeApp.h"
@@ -29,9 +30,25 @@ PspUsbCamSetupVideoParam videoParam;
unsigned int videoBufferLength = 0;
unsigned int nextVideoFrame = 0;
unsigned char videoBuffer[40 * 1000];
uint8_t *videoBuffer;
std::mutex videoBufferMutex;
enum {
VIDEO_BUFFER_SIZE = 40 * 1000,
};
void __UsbCamInit() {
videoBuffer = new uint8_t[VIDEO_BUFFER_SIZE];
}
void __UsbCamShutdown() {
delete[] videoBuffer;
videoBuffer = nullptr;
}
// TODO: Technically, we should store the videoBuffer into the savestate, if this
// module has been initialized.
static int sceUsbCamSetupMic(u32 paramAddr, u32 workareaAddr, int wasize) {
INFO_LOG(HLE, "UNIMPL sceUsbCamSetupMic");
if (Memory::IsValidRange(paramAddr, sizeof(micParam))) {
@@ -67,13 +84,14 @@ static int sceUsbCamSetupVideo(u32 paramAddr, u32 workareaAddr, int wasize) {
Memory::ReadStruct(paramAddr, &videoParam);
}
std::lock_guard<std::mutex> lock(videoBufferMutex);
videoBufferLength = sizeof(sceUsbCamDummyImage);
memset(videoBuffer, 0, sizeof(videoBuffer));
memcpy(videoBuffer, sceUsbCamDummyImage, sizeof(sceUsbCamDummyImage));
INFO_LOG(HLE, "UNIMPL sceUsbCamSetupVideo - size: %d", videoParam.size);
INFO_LOG(HLE, "UNIMPL sceUsbCamSetupVideo - resolution: %d", videoParam.resolution);
INFO_LOG(HLE, "UNIMPL sceUsbCamSetupVideo - framesize: %d", videoParam.framesize);
std::lock_guard<std::mutex> lock(videoBufferMutex);
videoBufferLength = sizeof(sceUsbCamDummyImage);
memset(videoBuffer, 0, VIDEO_BUFFER_SIZE);
memcpy(videoBuffer, sceUsbCamDummyImage, sizeof(sceUsbCamDummyImage));
return 0;
}
@@ -96,27 +114,26 @@ static int sceUsbCamAutoImageReverseSW(int rev) {
static int sceUsbCamReadVideoFrameBlocking(u32 bufAddr, u32 size) {
std::lock_guard<std::mutex> lock(videoBufferMutex);
for (unsigned int i = 0; i < videoBufferLength && i < size; i++) {
if (Memory::IsValidAddress(bufAddr + i)) {
Memory::Write_U8(videoBuffer[i], bufAddr + i);
}
u32 transferSize = std::min(videoBufferLength, size);
if (Memory::IsValidRange(bufAddr, size)) {
Memory::Memcpy(bufAddr, videoBuffer, transferSize);
}
return videoBufferLength;
}
static int sceUsbCamReadVideoFrame(u32 bufAddr, u32 size) {
std::lock_guard<std::mutex> lock(videoBufferMutex);
for (unsigned int i = 0; i < videoBufferLength && i < size; i++) {
if (Memory::IsValidAddress(bufAddr + i)) {
Memory::Write_U8(videoBuffer[i], bufAddr + i);
}
u32 transferSize = std::min(videoBufferLength, size);
if (Memory::IsValidRange(bufAddr, size)) {
Memory::Memcpy(bufAddr, videoBuffer, transferSize);
}
nextVideoFrame = videoBufferLength;
return 0;
}
static int sceUsbCamPollReadVideoFrameEnd() {
INFO_LOG(HLE, "UNIMPL sceUsbCamPollReadVideoFrameEnd: %d", nextVideoFrame);
VERBOSE_LOG(HLE, "UNIMPL sceUsbCamPollReadVideoFrameEnd: %d", nextVideoFrame);
return nextVideoFrame;
}
@@ -186,7 +203,12 @@ void Register_sceUsbCam()
void Camera::pushCameraImage(long long length, unsigned char* image) {
std::lock_guard<std::mutex> lock(videoBufferMutex);
videoBufferLength = length;
memset (videoBuffer, 0, sizeof(videoBuffer));
memcpy (videoBuffer, image, length);
memset(videoBuffer, 0, VIDEO_BUFFER_SIZE);
if (length > VIDEO_BUFFER_SIZE) {
videoBufferLength = 0;
ERROR_LOG(HLE, "pushCameraImage: length error: %lld > %d", length, VIDEO_BUFFER_SIZE);
} else {
videoBufferLength = length;
memcpy(videoBuffer, image, length);
}
}
+3
View File
@@ -19,6 +19,9 @@
void Register_sceUsbCam();
void __UsbCamInit();
void __UsbCamShutdown();
namespace Camera {
void pushCameraImage(long long length, unsigned char *image);
}
-1
View File
@@ -16,5 +16,4 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
void Register_sceUsbMic();
+3 -1
View File
@@ -413,7 +413,9 @@ int SasInstance::EstimateMixUs() {
}
// Each voice costs extra time, and each byte of grain costs extra time.
return 20 + voicesPlayingCount * 68 + (grainSize * 60) / 100;
int cycles = 20 + voicesPlayingCount * 68 + (grainSize * 60) / 100;
// Cap to 1200 to fix FFT, see issue #9956.
return std::min(cycles, 1200);
}
void SasVoice::ReadSamples(s16 *output, int numSamples) {
+1 -1
View File
@@ -111,7 +111,7 @@ ArmJit::ArmJit(MIPSState *mips) : blocks(mips, this), gpr(mips, &js, &jo), fpr(m
AllocCodeSpace(1024 * 1024 * 16); // 32MB is the absolute max because that's what an ARM branch instruction can reach, backwards and forwards.
GenerateFixedCode();
INFO_LOG(JIT, "ARM JIT initialized: %d MB of code space", GetSpaceLeft() / (1024 * 1024));
INFO_LOG(JIT, "ARM JIT initialized: %lld MB of code space", (long long)(GetSpaceLeft() / (1024 * 1024)));
js.startDefaultPrefix = mips_->HasDefaultPrefix();
+4 -4
View File
@@ -126,11 +126,11 @@ public:
const Gen::OpArg &R(int freg) const {return regs[freg].location;}
const Gen::OpArg &V(int vreg) const {
_dbg_assert_msg_(JIT, vregs[vreg].lane == 0, "SIMD reg %d used as V reg (use VS instead)", vreg);
_dbg_assert_msg_(JIT, vregs[vreg].lane == 0, "SIMD reg %d used as V reg (use VS instead). pc=%08x", vreg, mips->pc);
return vregs[vreg].location;
}
const Gen::OpArg &VS(const u8 *vs) const {
_dbg_assert_msg_(JIT, vregs[vs[0]].lane != 0, "V reg %d used as VS reg (use V instead)", vs[0]);
_dbg_assert_msg_(JIT, vregs[vs[0]].lane != 0, "V reg %d used as VS reg (use V instead). pc=%08x", vs[0], mips->pc);
return vregs[vs[0]].location;
}
@@ -142,7 +142,7 @@ public:
}
Gen::X64Reg VX(int vreg) const {
_dbg_assert_msg_(JIT, vregs[vreg].lane == 0, "SIMD reg %d used as V reg (use VSX instead)", vreg);
_dbg_assert_msg_(JIT, vregs[vreg].lane == 0, "SIMD reg %d used as V reg (use VSX instead). pc=%08x", vreg, mips->pc);
if (vregs[vreg].away && vregs[vreg].location.IsSimpleReg())
return vregs[vreg].location.GetSimpleReg();
PanicAlert("Not so simple - v%i", vreg);
@@ -150,7 +150,7 @@ public:
}
Gen::X64Reg VSX(const u8 *vs) const {
_dbg_assert_msg_(JIT, vregs[vs[0]].lane != 0, "V reg %d used as VS reg (use VX instead)", vs[0]);
_dbg_assert_msg_(JIT, vregs[vs[0]].lane != 0, "V reg %d used as VS reg (use VX instead). pc=%08x", vs[0], mips->pc);
if (vregs[vs[0]].away && vregs[vs[0]].location.IsSimpleReg())
return vregs[vs[0]].location.GetSimpleReg();
PanicAlert("Not so simple - v%i", vs[0]);
+119 -98
View File
@@ -37,7 +37,6 @@ enum class ServerStatus {
STARTING,
RUNNING,
STOPPING,
RESTARTING,
};
static const char *REPORT_HOSTNAME = "report.ppsspp.org";
@@ -53,15 +52,6 @@ static void UpdateStatus(ServerStatus s) {
serverStatus = s;
}
static bool UpdateStatus(ServerStatus s, ServerStatus old) {
std::lock_guard<std::mutex> guard(serverStatusLock);
if (serverStatus == old) {
serverStatus = s;
return true;
}
return false;
}
static ServerStatus RetrieveStatus() {
std::lock_guard<std::mutex> guard(serverStatusLock);
return serverStatus;
@@ -120,81 +110,129 @@ bool RemoteISOFileSupported(const std::string &filename) {
return true;
}
return false;
}
static void RegisterDiscHandlers(http::Server *http, std::unordered_map<std::string, std::string> *paths) {
for (std::string filename : g_Config.recentIsos) {
static std::string RemotePathForRecent(const std::string &filename) {
#ifdef _WIN32
static const std::string sep = "\\/";
static const std::string sep = "\\/";
#else
static const std::string sep = "/";
static const std::string sep = "/";
#endif
size_t basepos = filename.find_last_of(sep);
std::string basename = "/" + (basepos == filename.npos ? filename : filename.substr(basepos + 1));
size_t basepos = filename.find_last_of(sep);
std::string basename = "/" + (basepos == filename.npos ? filename : filename.substr(basepos + 1));
// Let's not serve directories, since they won't work. Only single files.
// Maybe can do PBPs and other files later. Would be neat to stream virtual disc filesystems.
if (RemoteISOFileSupported(basename)) {
(*paths)[ReplaceAll(basename, " ", "%20")] = filename;
if (basename == "/EBOOT.PBP") {
// Go up one more folder.
size_t nextpos = filename.find_last_of(sep, basepos - 1);
basename = "/" + (nextpos == filename.npos ? filename : filename.substr(nextpos + 1));
}
// Let's not serve directories, since they won't work. Only single files.
// Maybe can do PBPs and other files later. Would be neat to stream virtual disc filesystems.
if (RemoteISOFileSupported(basename)) {
return ReplaceAll(basename, " ", "%20");
}
return "";
}
static std::string LocalFromRemotePath(const std::string &path) {
for (const std::string &filename : g_Config.recentIsos) {
std::string basename = RemotePathForRecent(filename);
if (basename == path) {
return filename;
}
}
return "";
}
static void DiscHandler(const http::Request &request, const std::string &filename) {
s64 sz = File::GetFileSize(filename);
std::string range;
if (request.Method() == http::RequestHeader::HEAD) {
request.WriteHttpResponseHeader("1.0", 200, sz, "application/octet-stream", "Accept-Ranges: bytes\r\n");
} else if (request.GetHeader("range", &range)) {
s64 begin = 0, last = 0;
if (sscanf(range.c_str(), "bytes=%lld-%lld", &begin, &last) != 2) {
request.WriteHttpResponseHeader("1.0", 400, -1, "text/plain");
request.Out()->Push("Could not understand range request.");
return;
}
if (begin < 0 || begin > last || last >= sz) {
request.WriteHttpResponseHeader("1.0", 416, -1, "text/plain");
request.Out()->Push("Range goes outside of file.");
return;
}
FILE *fp = File::OpenCFile(filename, "rb");
if (!fp || fseek(fp, begin, SEEK_SET) != 0) {
request.WriteHttpResponseHeader("1.0", 500, -1, "text/plain");
request.Out()->Push("File access failed.");
if (fp) {
fclose(fp);
}
return;
}
s64 len = last - begin + 1;
char contentRange[1024];
sprintf(contentRange, "Content-Range: bytes %lld-%lld/%lld\r\n", begin, last, sz);
request.WriteHttpResponseHeader("1.0", 206, len, "application/octet-stream", contentRange);
const size_t CHUNK_SIZE = 16 * 1024;
char *buf = new char[CHUNK_SIZE];
for (s64 pos = 0; pos < len; pos += CHUNK_SIZE) {
s64 chunklen = std::min(len - pos, (s64)CHUNK_SIZE);
if (fread(buf, chunklen, 1, fp) != 1)
break;
request.Out()->Push(buf, chunklen);
}
fclose(fp);
delete[] buf;
request.Out()->Flush();
} else {
request.WriteHttpResponseHeader("1.0", 418, -1, "text/plain");
request.Out()->Push("This server only supports range requests.");
}
}
static void HandleListing(const http::Request &request) {
request.WriteHttpResponseHeader("1.0", 200, -1, "text/plain");
request.Out()->Printf("/\n");
if (serverFlags & (int)WebServerFlags::DISCS) {
// List the current discs in their recent order.
for (const std::string &filename : g_Config.recentIsos) {
std::string basename = RemotePathForRecent(filename);
if (!basename.empty()) {
request.Out()->Printf("%s\n", basename.c_str());
}
}
}
if (serverFlags & (int)WebServerFlags::DEBUGGER) {
request.Out()->Printf("/debugger\n");
}
}
static void HandleFallback(const http::Request &request) {
if (serverFlags & (int)WebServerFlags::DISCS) {
std::string filename = LocalFromRemotePath(request.resource());
if (!filename.empty()) {
DiscHandler(request, filename);
return;
}
}
auto handler = [paths](const http::Request &request) {
std::string filename = (*paths)[request.resource()];
s64 sz = File::GetFileSize(filename);
static const std::string payload = "404 not found\r\n";
request.WriteHttpResponseHeader("1.0", 404, (int)payload.size(), "text/plain");
request.Out()->Push(payload);
}
std::string range;
if (request.Method() == http::RequestHeader::HEAD) {
request.WriteHttpResponseHeader("1.0", 200, sz, "application/octet-stream", "Accept-Ranges: bytes\r\n");
} else if (request.GetHeader("range", &range)) {
s64 begin = 0, last = 0;
if (sscanf(range.c_str(), "bytes=%lld-%lld", &begin, &last) != 2) {
request.WriteHttpResponseHeader("1.0", 400, -1, "text/plain");
request.Out()->Push("Could not understand range request.");
return;
}
if (begin < 0 || begin > last || last >= sz) {
request.WriteHttpResponseHeader("1.0", 416, -1, "text/plain");
request.Out()->Push("Range goes outside of file.");
return;
}
FILE *fp = File::OpenCFile(filename, "rb");
if (!fp || fseek(fp, begin, SEEK_SET) != 0) {
request.WriteHttpResponseHeader("1.0", 500, -1, "text/plain");
request.Out()->Push("File access failed.");
if (fp) {
fclose(fp);
}
return;
}
s64 len = last - begin + 1;
char contentRange[1024];
sprintf(contentRange, "Content-Range: bytes %lld-%lld/%lld\r\n", begin, last, sz);
request.WriteHttpResponseHeader("1.0", 206, len, "application/octet-stream", contentRange);
const size_t CHUNK_SIZE = 16 * 1024;
char *buf = new char[CHUNK_SIZE];
for (s64 pos = 0; pos < len; pos += CHUNK_SIZE) {
s64 chunklen = std::min(len - pos, (s64)CHUNK_SIZE);
if (fread(buf, chunklen, 1, fp) != 1)
break;
request.Out()->Push(buf, chunklen);
}
fclose(fp);
delete [] buf;
request.Out()->Flush();
} else {
request.WriteHttpResponseHeader("1.0", 418, -1, "text/plain");
request.Out()->Push("This server only supports range requests.");
}
};
for (auto pair : *paths) {
http->RegisterHandler(pair.first.c_str(), handler);
static void ForwardDebuggerRequest(const http::Request &request) {
if (serverFlags & (int)WebServerFlags::DEBUGGER) {
HandleDebuggerRequest(request);
} else {
HandleFallback(request);
}
}
@@ -202,14 +240,10 @@ static void ExecuteWebServer() {
setCurrentThreadName("HTTPServer");
auto http = new http::Server(new threading::NewThreadExecutor());
std::unordered_map<std::string, std::string> discPaths;
if (serverFlags & (int)WebServerFlags::DISCS) {
RegisterDiscHandlers(http, &discPaths);
}
if (serverFlags & (int)WebServerFlags::DEBUGGER) {
http->RegisterHandler("/debugger", &HandleDebuggerRequest);
}
http->RegisterHandler("/", &HandleListing);
// This lists all the (current) recent ISOs.
http->SetFallbackHandler(&HandleFallback);
http->RegisterHandler("/debugger", &ForwardDebuggerRequest);
if (!http->Listen(g_Config.iRemoteISOPort)) {
if (!http->Listen(0)) {
@@ -237,24 +271,16 @@ static void ExecuteWebServer() {
StopAllDebuggers();
delete http;
// Move to STARTING to lock flags/STOPPING.
if (UpdateStatus(ServerStatus::STARTING, ServerStatus::RESTARTING)) {
ExecuteWebServer();
} else {
UpdateStatus(ServerStatus::STOPPED);
}
UpdateStatus(ServerStatus::STOPPED);
}
bool StartWebServer(WebServerFlags flags) {
std::lock_guard<std::mutex> guard(serverStatusLock);
switch (serverStatus) {
case ServerStatus::RUNNING:
case ServerStatus::RESTARTING:
if ((serverFlags & (int)flags) == (int)flags) {
// Already running those flags.
return false;
}
serverStatus = ServerStatus::RESTARTING;
serverFlags |= (int)flags;
return true;
@@ -272,24 +298,19 @@ bool StartWebServer(WebServerFlags flags) {
bool StopWebServer(WebServerFlags flags) {
std::lock_guard<std::mutex> guard(serverStatusLock);
if (serverStatus != ServerStatus::RUNNING && serverStatus != ServerStatus::RESTARTING) {
if (serverStatus != ServerStatus::RUNNING) {
return false;
}
serverFlags &= ~(int)flags;
if (serverFlags == 0) {
serverStatus = ServerStatus::STOPPING;
} else {
serverStatus = ServerStatus::RESTARTING;
}
return true;
}
bool WebServerStopping(WebServerFlags flags) {
std::lock_guard<std::mutex> guard(serverStatusLock);
if (serverStatus == ServerStatus::RESTARTING) {
return (serverFlags & (int)flags) == 0;
}
return serverStatus == ServerStatus::STOPPING;
}
-5
View File
@@ -2085,11 +2085,6 @@ void FramebufferManagerCommon::DownloadFramebufferForClut(u32 fb_address, u32 lo
int w = std::min(pixels % vfb->fb_stride, (int)vfb->width);
int h = std::min((pixels + vfb->fb_stride - 1) / vfb->fb_stride, (int)vfb->height);
if (w == 0 && h > 0) {
// Exactly aligned (means pixels == vfb->fb_stride, so modulus gave zero.)
w = std::min(vfb->fb_stride, (int)vfb->width);
}
// We might still have a pending draw to the fb in question, flush if so.
FlushBeforeCopy();
+7
View File
@@ -44,6 +44,8 @@
// Report the time and throughput for each larger scaling operation in the log
//#define SCALING_MEASURE_TIME
//#define DEBUG_SCALER_OUTPUT
#ifdef SCALING_MEASURE_TIME
#include "base/timeutil.h"
#endif
@@ -460,6 +462,8 @@ void bilinearV(int factor, u32* data, u32* out, int w, int gl, int gu, int l, in
#undef B
#undef A
#ifdef DEBUG_SCALER_OUTPUT
// used for debugging texture scaling (writing textures to files)
static int g_imgCount = 0;
void dbgPPM(int w, int h, u8* pixels, const char* prefix = "dbg") { // 3 component RGB
@@ -490,6 +494,9 @@ void dbgPGM(int w, int h, u32* pixels, const char* prefix = "dbg") { // 1 compon
}
fclose(fp);
}
#endif
}
/////////////////////////////////////// Texture Scaler
+27
View File
@@ -26,6 +26,8 @@
#include "GPU/Vulkan/GPU_Vulkan.h"
#include "GPU/Vulkan/VulkanUtil.h"
#undef DrawText
void DrawAllocatorVis(UIContext *ui, GPUInterface *gpu) {
if (!gpu) {
return;
@@ -94,3 +96,28 @@ void DrawAllocatorVis(UIContext *ui, GPUInterface *gpu) {
for (auto iter : texturesToDelete)
iter->Release();
}
void DrawProfilerVis(UIContext *ui, GPUInterface *gpu) {
if (!gpu) {
return;
}
using namespace Draw;
const int padding = 10;
const int columnWidth = 256;
const int starty = padding * 8;
int x = padding;
int y = starty;
int w = columnWidth; // We will double this when actually drawing to make the pixels visible.
ui->Begin();
GPU_Vulkan *gpuVulkan = static_cast<GPU_Vulkan *>(gpu);
std::string text = gpuVulkan->GetGpuProfileString();
Draw::DrawContext *draw = ui->GetDrawContext();
ui->SetFontScale(0.4f, 0.4f);
ui->DrawTextShadow(text.c_str(), 10, 50, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
ui->SetFontScale(1.0f, 1.0f);
ui->Flush();
}
+1
View File
@@ -24,3 +24,4 @@ class UIContext;
// gpu MUST be an instance of GPU_Vulkan. If not, will definitely crash.
void DrawAllocatorVis(UIContext *ui, GPUInterface *gpu);
void DrawProfilerVis(UIContext *ui, GPUInterface *gpu);
+2 -2
View File
@@ -37,8 +37,8 @@ void main() {
static const VkComponentMapping VULKAN_4444_SWIZZLE = { VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B };
static const VkComponentMapping VULKAN_1555_SWIZZLE = { VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_A };
static const VkComponentMapping VULKAN_565_SWIZZLE = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
static const VkComponentMapping VULKAN_8888_SWIZZLE = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
static const VkComponentMapping VULKAN_565_SWIZZLE = { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY };
static const VkComponentMapping VULKAN_8888_SWIZZLE = { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY };
static VkFormat GetClutDestFormat(GEPaletteFormat format, VkComponentMapping *componentMapping) {
switch (format) {
+8
View File
@@ -475,6 +475,9 @@ void GPU_Vulkan::InitDeviceObjects() {
hacks |= QUEUE_HACK_MGS2_ACID;
if (PSP_CoreParameter().compat.flags().SonicRivalsHack)
hacks |= QUEUE_HACK_SONIC;
if (PSP_CoreParameter().compat.flags().RenderPassMerge)
hacks |= QUEUE_HACK_RENDERPASS_MERGE;
if (hacks) {
rm->GetQueueRunner()->EnableHacks(hacks);
}
@@ -638,3 +641,8 @@ std::string GPU_Vulkan::DebugGetShaderString(std::string id, DebugShaderType typ
return std::string();
}
}
std::string GPU_Vulkan::GetGpuProfileString() {
VulkanRenderManager *rm = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
return rm->GetGpuProfileString();
}
+2
View File
@@ -66,6 +66,8 @@ public:
return textureCacheVulkan_;
}
std::string GetGpuProfileString();
protected:
void FinishDeferred() override;
+10
View File
@@ -439,6 +439,8 @@ void MainUI::initializeGL() {
g_Config.iGPUBackend = (int)GPUBackend::OPENGL;
}
SetGLCoreContext(format().profile() == QGLFormat::CoreProfile);
#ifndef USING_GLES2
// Some core profile drivers elide certain extensions from GL_EXTENSIONS/etc.
// glewExperimental allows us to force GLEW to search for the pointers anyway.
@@ -569,6 +571,14 @@ int main(int argc, char *argv[])
#if defined(Q_OS_LINUX)
QApplication::setAttribute(Qt::AA_X11InitThreads, true);
#endif
// Qt would otherwise default to a 3.0 compatibility profile
// except on Nvidia, where Nvidia gives us the highest supported anyway
QGLFormat format;
format.setVersion(4, 6);
format.setProfile(QGLFormat::CoreProfile);
QGLFormat::setDefaultFormat(format);
QApplication a(argc, argv);
QSize res = QApplication::desktop()->screenGeometry().size();
if (res.width() < res.height())
+81 -21
View File
@@ -17,13 +17,7 @@
class AT3PlusReader {
public:
AT3PlusReader(const std::string &data)
: file_((const uint8_t *)&data[0], (int32_t)data.size()),
raw_data_(0),
raw_data_size_(0),
raw_offset_(0),
buffer_(0),
decoder_(0) {
: file_((const uint8_t *)&data[0], (int32_t)data.size()) {
// Normally 8k but let's be safe.
buffer_ = new short[32 * 1024];
@@ -78,18 +72,64 @@ public:
return;
}
// If we have no loop info, we'll just loop the entire audio.
raw_offset_loop_start_ = 0;
raw_offset_loop_end_ = 0;
skip_next_samples_ = 0;
if (file_.Descend('smpl')) {
std::vector<u8> smplData;
smplData.resize(file_.GetCurrentChunkSize());
file_.ReadData(&smplData[0], (int)smplData.size());
int numLoops = *(int *)&smplData[28];
struct AtracLoopInfo {
int cuePointID;
int type;
int startSample;
int endSample;
int fraction;
int playCount;
};
if (numLoops > 0 && smplData.size() >= 36 + sizeof(AtracLoopInfo) * numLoops) {
AtracLoopInfo *loops = (AtracLoopInfo *)&smplData[36];
int samplesPerFrame = codec == PSP_CODEC_AT3PLUS ? 2048 : 1024;
for (int i = 0; i < numLoops; ++i) {
// Only seen forward loops, so let's ignore others.
if (loops[i].type != 0)
continue;
// We ignore loop interpolation (fraction) and play count for now.
raw_offset_loop_start_ = (loops[i].startSample / samplesPerFrame) * raw_bytes_per_frame_;
loop_start_offset_ = loops[i].startSample % samplesPerFrame;
raw_offset_loop_end_ = (loops[i].endSample / samplesPerFrame) * raw_bytes_per_frame_;
loop_end_offset_ = loops[i].endSample % samplesPerFrame;
if (loops[i].playCount == 0) {
// This was an infinite loop, so ignore the rest.
// In practice, there's usually only one and it's usually infinite.
break;
}
}
}
file_.Ascend();
}
if (file_.Descend('data')) { //enter the data chunk
int numBytes = file_.GetCurrentChunkSize();
numFrames = numBytes / raw_bytes_per_frame_; // numFrames
raw_data_ = (uint8_t *)malloc(numBytes);
raw_data_size_ = numBytes;
if (/*raw_bytes_per_frame_ == 280 && */ num_channels == 1 || num_channels == 2) {
if (num_channels == 1 || num_channels == 2) {
file_.ReadData(raw_data_, numBytes);
} else {
ELOG("Error - bad blockalign or channels");
free(raw_data_);
raw_data_ = 0;
raw_data_ = nullptr;
return;
}
file_.Ascend();
@@ -116,30 +156,45 @@ public:
void Shutdown() {
free(raw_data_);
raw_data_ = 0;
raw_data_ = nullptr;
delete[] buffer_;
buffer_ = 0;
buffer_ = nullptr;
delete decoder_;
decoder_ = 0;
decoder_ = nullptr;
}
bool IsOK() { return raw_data_ != 0; }
bool IsOK() { return raw_data_ != nullptr; }
bool Read(int *buffer, int len) {
if (!raw_data_)
return false;
while (bgQueue.size() < (size_t)(len * 2)) {
int outBytes;
int outBytes = 0;
decoder_->Decode(raw_data_ + raw_offset_, raw_bytes_per_frame_, (uint8_t *)buffer_, &outBytes);
if (!outBytes)
return false;
for (int i = 0; i < outBytes / 2; i++) {
if (raw_offset_loop_end_ != 0 && raw_offset_ == raw_offset_loop_end_) {
// Only take the remaining bytes, but convert to stereo s16.
outBytes = std::min(outBytes, loop_end_offset_ * 4);
}
int start = skip_next_samples_;
skip_next_samples_ = 0;
for (int i = start; i < outBytes / 2; i++) {
bgQueue.push(buffer_[i]);
}
// loop!
if (raw_offset_loop_end_ != 0 && raw_offset_ == raw_offset_loop_end_) {
// Time to loop. Account for the addition below.
raw_offset_ = raw_offset_loop_start_ - raw_bytes_per_frame_;
// This time we're counting each stereo sample.
skip_next_samples_ = loop_start_offset_ * 2;
}
// Handle loops when there's no loop info.
raw_offset_ += raw_bytes_per_frame_;
if (raw_offset_ >= raw_data_size_) {
raw_offset_ = 0;
@@ -154,13 +209,18 @@ public:
private:
RIFFReader file_;
uint8_t *raw_data_;
int raw_data_size_;
int raw_offset_;
uint8_t *raw_data_ = nullptr;
int raw_data_size_ = 0;
int raw_offset_ = 0;
int raw_bytes_per_frame_;
int raw_offset_loop_start_ = 0;
int raw_offset_loop_end_ = 0;
int loop_start_offset_ = 0;
int loop_end_offset_ = 0;
int skip_next_samples_ = 0;
FixedSizeQueue<s16, 128 * 1024> bgQueue;
short *buffer_;
SimpleAudio *decoder_;
short *buffer_ = nullptr;
SimpleAudio *decoder_ = nullptr;
};
static std::mutex bgMutex;
+4 -1
View File
@@ -80,7 +80,10 @@ void DevMenu::CreatePopupContents(UI::ViewGroup *parent) {
items->Add(new Choice(sy->T("Developer Tools")))->OnClick.Handle(this, &DevMenu::OnDeveloperTools);
items->Add(new Choice(dev->T("Jit Compare")))->OnClick.Handle(this, &DevMenu::OnJitCompare);
items->Add(new Choice(dev->T("Shader Viewer")))->OnClick.Handle(this, &DevMenu::OnShaderView);
items->Add(new CheckBox(&g_Config.bShowAllocatorDebug, dev->T("Allocator Viewer")));
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN) {
items->Add(new CheckBox(&g_Config.bShowAllocatorDebug, dev->T("Allocator Viewer")));
items->Add(new CheckBox(&g_Config.bShowGpuProfile, dev->T("GPU Profile")));
}
items->Add(new Choice(dev->T("Toggle Freeze")))->OnClick.Handle(this, &DevMenu::OnFreezeFrame);
items->Add(new Choice(dev->T("Dump Frame GPU Commands")))->OnClick.Handle(this, &DevMenu::OnDumpFrame);
items->Add(new Choice(dev->T("Toggle Audio Debug")))->OnClick.Handle(this, &DevMenu::OnToggleAudioDebug);
+5
View File
@@ -1382,6 +1382,11 @@ void EmuScreen::renderUI() {
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN && g_Config.bShowAllocatorDebug) {
DrawAllocatorVis(ctx, gpu);
}
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN && g_Config.bShowGpuProfile) {
DrawProfilerVis(ctx, gpu);
}
#endif
if ((g_Config.bShowFrameProfiler || g_Config.bSimpleFrameStats) && !invalid_) {
+1
View File
@@ -92,6 +92,7 @@ bool GameInfo::Delete() {
{
const std::string &fileToRemove = filePath_;
File::Delete(fileToRemove);
g_Config.RemoveRecent(filePath_);
return true;
}
+134 -125
View File
@@ -22,6 +22,7 @@
#include "base/colorutil.h"
#include "base/timeutil.h"
#include "math/curves.h"
#include "net/resolve.h"
#include "gfx_es2/gpu_features.h"
#include "gfx_es2/draw_buffer.h"
#include "i18n/i18n.h"
@@ -295,7 +296,7 @@ void GameSettingsScreen::CreateViews() {
}
#if !defined(MOBILE_DEVICE)
graphicsSettings->Add(new CheckBox(&g_Config.bFullScreen, gr->T("FullScreen")))->OnClick.Handle(this, &GameSettingsScreen::OnFullscreenChange);
graphicsSettings->Add(new CheckBox(&g_Config.bFullScreen, gr->T("FullScreen", "Full Screen")))->OnClick.Handle(this, &GameSettingsScreen::OnFullscreenChange);
if (System_GetPropertyInt(SYSPROP_DISPLAY_COUNT) > 1) {
CheckBox *fullscreenMulti = new CheckBox(&g_Config.bFullScreenMulti, gr->T("Use all displays"));
fullscreenMulti->SetEnabledPtr(&g_Config.bFullScreen);
@@ -309,7 +310,8 @@ void GameSettingsScreen::CreateViews() {
#ifdef __ANDROID__
// Hide Immersive Mode on pre-kitkat Android
if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 19) {
graphicsSettings->Add(new CheckBox(&g_Config.bImmersiveMode, gr->T("Immersive Mode")))->OnClick.Handle(this, &GameSettingsScreen::OnImmersiveModeChange);
// Let's reuse the Fullscreen translation string from desktop.
graphicsSettings->Add(new CheckBox(&g_Config.bImmersiveMode, gr->T("FullScreen", "Full Screen")))->OnClick.Handle(this, &GameSettingsScreen::OnImmersiveModeChange);
}
#endif
@@ -669,13 +671,7 @@ void GameSettingsScreen::CreateViews() {
networkingSettings->Add(new CheckBox(&g_Config.bEnableWlan, n->T("Enable networking", "Enable networking/wlan (beta)")));
#if !defined(MOBILE_DEVICE)
networkingSettings->Add(new PopupTextInputChoice(&g_Config.proAdhocServer, n->T("Change proAdhocServer Address"), "", 255, screenManager()));
#elif defined(__ANDROID__)
networkingSettings->Add(new ChoiceWithValueDisplay(&g_Config.proAdhocServer, n->T("Change proAdhocServer Address"), (const char *)nullptr))->OnClick.Handle(this, &GameSettingsScreen::OnChangeproAdhocServerAddress);
#else
networkingSettings->Add(new ChoiceWithValueDisplay(&g_Config.proAdhocServer, n->T("Change proAdhocServer Address"), (const char *)nullptr))->OnClick.Handle(this, &GameSettingsScreen::OnChangeproAdhocServerAddress);
#endif
networkingSettings->Add(new CheckBox(&g_Config.bEnableAdhocServer, n->T("Enable built-in PRO Adhoc Server", "Enable built-in PRO Adhoc Server")));
networkingSettings->Add(new ChoiceWithValueDisplay(&g_Config.sMACAddress, n->T("Change Mac Address"), (const char *)nullptr))->OnClick.Handle(this, &GameSettingsScreen::OnChangeMacAddress);
networkingSettings->Add(new PopupSliderChoice(&g_Config.iPortOffset, 0, 60000, n->T("Port offset", "Port offset(0 = PSP compatibility)"), 100, screenManager()));
@@ -1263,24 +1259,12 @@ UI::EventReturn GameSettingsScreen::OnChangeNickname(UI::EventParams &e) {
}
UI::EventReturn GameSettingsScreen::OnChangeproAdhocServerAddress(UI::EventParams &e) {
#if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI)
if (!g_Config.bFullScreen) {
const size_t name_len = 256;
I18NCategory *sy = GetI18NCategory("System");
char name[name_len];
memset(name, 0, sizeof(name));
if (System_InputBoxGetString("Enter an IP address", g_Config.proAdhocServer.c_str(), name, name_len)) {
std::string stripped = StripSpaces(name);
g_Config.proAdhocServer = stripped;
}
}
else
screenManager()->push(new ProAdhocServerScreen);
#elif defined(__ANDROID__)
#if defined(__ANDROID__)
System_SendMessage("inputbox", ("IP:" + g_Config.proAdhocServer).c_str());
#else
screenManager()->push(new ProAdhocServerScreen);
screenManager()->push(new HostnameSelectScreen(&g_Config.proAdhocServer, sy->T("proAdhocServer Address:")));
#endif
return UI::EVENT_DONE;
@@ -1611,130 +1595,156 @@ void DeveloperToolsScreen::update() {
canAllowDebugger_ = !WebServerStopping(WebServerFlags::DEBUGGER);
}
void ProAdhocServerScreen::CreateViews() {
void HostnameSelectScreen::CreatePopupContents(UI::ViewGroup *parent) {
using namespace UI;
I18NCategory *sy = GetI18NCategory("System");
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *n = GetI18NCategory("Networking");
tempProAdhocServer = g_Config.proAdhocServer;
root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT));
LinearLayout *leftColumn = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT));
LinearLayout *valueRow = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT, Margins(0, 0, 0, 10)));
leftColumn->Add(new ItemHeader(sy->T("proAdhocServer Address:")));
addrView_ = new TextView(tempProAdhocServer, ALIGN_LEFT, false);
leftColumn->Add(addrView_);
LinearLayout *rightColumn = new LinearLayout(ORIENT_HORIZONTAL, new AnchorLayoutParams(0, 120, 10, NONE, NONE,10));
rightColumn->Add(new Button("0"))->OnClick.Handle(this, &ProAdhocServerScreen::On0Click);
rightColumn->Add(new Button("1"))->OnClick.Handle(this, &ProAdhocServerScreen::On1Click);
rightColumn->Add(new Button("2"))->OnClick.Handle(this, &ProAdhocServerScreen::On2Click);
rightColumn->Add(new Button("3"))->OnClick.Handle(this, &ProAdhocServerScreen::On3Click);
rightColumn->Add(new Button("4"))->OnClick.Handle(this, &ProAdhocServerScreen::On4Click);
rightColumn->Add(new Button("5"))->OnClick.Handle(this, &ProAdhocServerScreen::On5Click);
rightColumn->Add(new Button("6"))->OnClick.Handle(this, &ProAdhocServerScreen::On6Click);
rightColumn->Add(new Button("7"))->OnClick.Handle(this, &ProAdhocServerScreen::On7Click);
rightColumn->Add(new Button("8"))->OnClick.Handle(this, &ProAdhocServerScreen::On8Click);
rightColumn->Add(new Button("9"))->OnClick.Handle(this, &ProAdhocServerScreen::On9Click);
rightColumn->Add(new Button("."))->OnClick.Handle(this, &ProAdhocServerScreen::OnPointClick);
rightColumn->Add(new Button(di->T("Delete")))->OnClick.Handle(this, &ProAdhocServerScreen::OnDeleteClick);
rightColumn->Add(new Button(di->T("Delete all")))->OnClick.Handle(this, &ProAdhocServerScreen::OnDeleteAllClick);
rightColumn->Add(new Button(di->T("OK")))->OnClick.Handle(this, &ProAdhocServerScreen::OnOKClick);
rightColumn->Add(new Button(di->T("Cancel")))->OnClick.Handle(this, &ProAdhocServerScreen::OnCancelClick);
root_->Add(leftColumn);
root_->Add(rightColumn);
addrView_ = new TextEdit(*value_, "");
addrView_->SetTextAlign(FLAG_DYNAMIC_ASCII);
valueRow->Add(addrView_);
parent->Add(valueRow);
LinearLayout *buttonsRow1 = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
LinearLayout *buttonsRow2 = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
parent->Add(buttonsRow1);
parent->Add(buttonsRow2);
buttonsRow1->Add(new Spacer(new LinearLayoutParams(1.0, G_LEFT)));
for (char c = '0'; c <= '9'; ++c) {
char label[] = { c, '\0' };
auto button = buttonsRow1->Add(new Button(label));
button->OnClick.Handle(this, &HostnameSelectScreen::OnNumberClick);
button->SetTag(label);
}
buttonsRow1->Add(new Button("."))->OnClick.Handle(this, &HostnameSelectScreen::OnPointClick);
buttonsRow1->Add(new Spacer(new LinearLayoutParams(1.0, G_RIGHT)));
buttonsRow2->Add(new Spacer(new LinearLayoutParams(1.0, G_LEFT)));
buttonsRow2->Add(new Button(di->T("Delete")))->OnClick.Handle(this, &HostnameSelectScreen::OnDeleteClick);
buttonsRow2->Add(new Button(di->T("Delete all")))->OnClick.Handle(this, &HostnameSelectScreen::OnDeleteAllClick);
buttonsRow2->Add(new Spacer(new LinearLayoutParams(1.0, G_RIGHT)));
errorView_ = parent->Add(new TextView(n->T("Invalid IP or hostname"), ALIGN_HCENTER, false, new LinearLayoutParams(Margins(0, 10, 0, 0))));
errorView_->SetTextColor(0xFF3030FF);
errorView_->SetVisibility(V_GONE);
progressView_ = parent->Add(new TextView(n->T("Validating address..."), ALIGN_HCENTER, false, new LinearLayoutParams(Margins(0, 10, 0, 0))));
progressView_->SetVisibility(V_GONE);
}
UI::EventReturn ProAdhocServerScreen::On0Click(UI::EventParams &e) {
if (tempProAdhocServer.length() > 0)
tempProAdhocServer.append("0");
addrView_->SetText(tempProAdhocServer);
void HostnameSelectScreen::SendEditKey(int keyCode, int flags) {
auto oldView = UI::GetFocusedView();
UI::SetFocusedView(addrView_);
KeyInput fakeKey{ DEVICE_ID_KEYBOARD, keyCode, KEY_DOWN | flags };
addrView_->Key(fakeKey);
UI::SetFocusedView(oldView);
}
UI::EventReturn HostnameSelectScreen::OnNumberClick(UI::EventParams &e) {
std::string text = e.v ? e.v->Tag() : "";
if (text.length() == 1 && text[0] >= '0' && text[0] <= '9') {
SendEditKey(text[0], KEY_CHAR);
}
return UI::EVENT_DONE;
}
UI::EventReturn ProAdhocServerScreen::On1Click(UI::EventParams &e) {
tempProAdhocServer.append("1");
addrView_->SetText(tempProAdhocServer);
UI::EventReturn HostnameSelectScreen::OnPointClick(UI::EventParams &e) {
SendEditKey('.', KEY_CHAR);
return UI::EVENT_DONE;
}
UI::EventReturn ProAdhocServerScreen::On2Click(UI::EventParams &e) {
tempProAdhocServer.append("2");
addrView_->SetText(tempProAdhocServer);
UI::EventReturn HostnameSelectScreen::OnDeleteClick(UI::EventParams &e) {
SendEditKey(NKCODE_DEL);
return UI::EVENT_DONE;
}
UI::EventReturn ProAdhocServerScreen::On3Click(UI::EventParams &e) {
tempProAdhocServer.append("3");
addrView_->SetText(tempProAdhocServer);
UI::EventReturn HostnameSelectScreen::OnDeleteAllClick(UI::EventParams &e) {
addrView_->SetText("");
return UI::EVENT_DONE;
}
UI::EventReturn ProAdhocServerScreen::On4Click(UI::EventParams &e) {
tempProAdhocServer.append("4");
addrView_->SetText(tempProAdhocServer);
return UI::EVENT_DONE;
void HostnameSelectScreen::ResolverThread() {
std::unique_lock<std::mutex> guard(resolverLock_);
while (resolverState_ != ResolverState::QUIT) {
resolverCond_.wait(guard);
if (resolverState_ == ResolverState::QUEUED) {
resolverState_ = ResolverState::PROGRESS;
addrinfo *resolved = nullptr;
std::string err;
toResolveResult_ = net::DNSResolve(toResolve_, "80", &resolved, err);
if (resolved)
net::DNSResolveFree(resolved);
resolverState_ = ResolverState::READY;
}
}
}
UI::EventReturn ProAdhocServerScreen::On5Click(UI::EventParams &e) {
tempProAdhocServer.append("5");
addrView_->SetText(tempProAdhocServer);
return UI::EVENT_DONE;
bool HostnameSelectScreen::CanComplete(DialogResult result) {
if (result != DR_OK)
return true;
std::string value = addrView_->GetText();
if (lastResolved_ == value) {
return true;
}
// Currently running.
if (resolverState_ == ResolverState::PROGRESS)
return false;
std::lock_guard<std::mutex> guard(resolverLock_);
switch (resolverState_) {
case ResolverState::PROGRESS:
case ResolverState::QUIT:
return false;
case ResolverState::QUEUED:
case ResolverState::WAITING:
break;
case ResolverState::READY:
if (toResolve_ == value) {
// Reset the state, nothing there now.
resolverState_ = ResolverState::WAITING;
toResolve_.clear();
lastResolved_ = value;
lastResolvedResult_ = toResolveResult_;
if (lastResolvedResult_) {
errorView_->SetVisibility(UI::V_GONE);
} else {
errorView_->SetVisibility(UI::V_VISIBLE);
}
progressView_->SetVisibility(UI::V_GONE);
return true;
}
// Throw away that last result, it was for a different value.
break;
}
resolverState_ = ResolverState::QUEUED;
toResolve_ = value;
resolverCond_.notify_one();
progressView_->SetVisibility(UI::V_VISIBLE);
errorView_->SetVisibility(UI::V_GONE);
return false;
}
UI::EventReturn ProAdhocServerScreen::On6Click(UI::EventParams &e) {
tempProAdhocServer.append("6");
addrView_->SetText(tempProAdhocServer);
return UI::EVENT_DONE;
}
UI::EventReturn ProAdhocServerScreen::On7Click(UI::EventParams &e) {
tempProAdhocServer.append("7");
addrView_->SetText(tempProAdhocServer);
return UI::EVENT_DONE;
}
UI::EventReturn ProAdhocServerScreen::On8Click(UI::EventParams &e) {
tempProAdhocServer.append("8");
addrView_->SetText(tempProAdhocServer);
return UI::EVENT_DONE;
}
UI::EventReturn ProAdhocServerScreen::On9Click(UI::EventParams &e) {
tempProAdhocServer.append("9");
addrView_->SetText(tempProAdhocServer);
return UI::EVENT_DONE;
}
UI::EventReturn ProAdhocServerScreen::OnPointClick(UI::EventParams &e) {
if (tempProAdhocServer.length() > 0 && tempProAdhocServer.at(tempProAdhocServer.length() - 1) != '.')
tempProAdhocServer.append(".");
addrView_->SetText(tempProAdhocServer);
return UI::EVENT_DONE;
}
UI::EventReturn ProAdhocServerScreen::OnDeleteClick(UI::EventParams &e) {
if (tempProAdhocServer.length() > 0)
tempProAdhocServer.erase(tempProAdhocServer.length() -1, 1);
addrView_->SetText(tempProAdhocServer);
return UI::EVENT_DONE;
}
UI::EventReturn ProAdhocServerScreen::OnDeleteAllClick(UI::EventParams &e) {
tempProAdhocServer = "";
addrView_->SetText(tempProAdhocServer);
return UI::EVENT_DONE;
}
UI::EventReturn ProAdhocServerScreen::OnOKClick(UI::EventParams &e) {
g_Config.proAdhocServer = StripSpaces(tempProAdhocServer);
UIScreen::OnBack(e);
return UI::EVENT_DONE;
}
UI::EventReturn ProAdhocServerScreen::OnCancelClick(UI::EventParams &e) {
tempProAdhocServer = g_Config.proAdhocServer;
UIScreen::OnBack(e);
return UI::EVENT_DONE;
void HostnameSelectScreen::OnCompleted(DialogResult result) {
if (result == DR_OK)
*value_ = addrView_->GetText();
}
SettingInfoMessage::SettingInfoMessage(int align, UI::AnchorLayoutParams *lp)
@@ -1743,7 +1753,6 @@ SettingInfoMessage::SettingInfoMessage(int align, UI::AnchorLayoutParams *lp)
SetSpacing(0.0f);
Add(new UI::Spacer(10.0f));
text_ = Add(new UI::TextView("", align, false, new LinearLayoutParams(1.0, Margins(0, 10))));
text_->SetTag("TEST?");
Add(new UI::Spacer(10.0f));
}
+45 -17
View File
@@ -18,6 +18,9 @@
#pragma once
#include "ppsspp_config.h"
#include <condition_variable>
#include <mutex>
#include <thread>
#include "ui/ui_screen.h"
#include "UI/MiscScreens.h"
@@ -190,28 +193,53 @@ private:
};
class ProAdhocServerScreen : public UIDialogScreenWithBackground {
class HostnameSelectScreen : public PopupScreen {
public:
ProAdhocServerScreen() {}
HostnameSelectScreen(std::string *value, const std::string &title)
: PopupScreen(title, "OK", "Cancel"), value_(value) {
resolver_ = std::thread([](HostnameSelectScreen *thiz) {
thiz->ResolverThread();
}, this);
}
~HostnameSelectScreen() {
resolverState_ = ResolverState::QUIT;
resolverCond_.notify_one();
resolver_.join();
}
void CreatePopupContents(UI::ViewGroup *parent) override;
protected:
void CreateViews() override;
void OnCompleted(DialogResult result) override;
bool CanComplete(DialogResult result) override;
private:
std::string tempProAdhocServer;
UI::TextView *addrView_;
UI::EventReturn On0Click(UI::EventParams &e);
UI::EventReturn On1Click(UI::EventParams &e);
UI::EventReturn On2Click(UI::EventParams &e);
UI::EventReturn On3Click(UI::EventParams &e);
UI::EventReturn On4Click(UI::EventParams &e);
UI::EventReturn On5Click(UI::EventParams &e);
UI::EventReturn On6Click(UI::EventParams &e);
UI::EventReturn On7Click(UI::EventParams &e);
UI::EventReturn On8Click(UI::EventParams &e);
UI::EventReturn On9Click(UI::EventParams &e);
private:
void ResolverThread();
void SendEditKey(int keyCode, int flags = 0);
UI::EventReturn OnNumberClick(UI::EventParams &e);
UI::EventReturn OnPointClick(UI::EventParams &e);
UI::EventReturn OnDeleteClick(UI::EventParams &e);
UI::EventReturn OnDeleteAllClick(UI::EventParams &e);
UI::EventReturn OnOKClick(UI::EventParams &e);
UI::EventReturn OnCancelClick(UI::EventParams &e);
enum class ResolverState {
WAITING,
QUEUED,
PROGRESS,
READY,
QUIT,
};
std::string *value_;
UI::TextEdit *addrView_ = nullptr;
UI::TextView *errorView_ = nullptr;
UI::TextView *progressView_ = nullptr;
std::thread resolver_;
ResolverState resolverState_ = ResolverState::WAITING;
std::mutex resolverLock_;
std::condition_variable resolverCond_;
std::string toResolve_ = "";
bool toResolveResult_ = false;
std::string lastResolved_ = "";
bool lastResolvedResult_ = false;
};
+2
View File
@@ -501,6 +501,7 @@
<ClInclude Include="..\..\Core\HLE\sceUsbAcc.h" />
<ClInclude Include="..\..\Core\HLE\sceUsbCam.h" />
<ClInclude Include="..\..\Core\HLE\sceUsbGps.h" />
<ClInclude Include="..\..\Core\HLE\sceUsbMic.h" />
<ClInclude Include="..\..\Core\HLE\sceUtility.h" />
<ClInclude Include="..\..\Core\HLE\sceVaudio.h" />
<ClInclude Include="..\..\Core\HLE\ThreadQueueList.h" />
@@ -712,6 +713,7 @@
<ClCompile Include="..\..\Core\HLE\sceUsbAcc.cpp" />
<ClCompile Include="..\..\Core\HLE\sceUsbCam.cpp" />
<ClCompile Include="..\..\Core\HLE\sceUsbGps.cpp" />
<ClCompile Include="..\..\Core\HLE\sceUsbMic.cpp" />
<ClCompile Include="..\..\Core\HLE\sceUtility.cpp" />
<ClCompile Include="..\..\Core\HLE\sceVaudio.cpp" />
<ClCompile Include="..\..\Core\HLE\__sceAudio.cpp" />
+7 -1
View File
@@ -631,6 +631,9 @@
<ClCompile Include="..\..\Core\HLE\sceUsbAcc.cpp">
<Filter>HLE</Filter>
</ClCompile>
<ClCompile Include="..\..\Core\HLE\sceUsbMic.cpp">
<Filter>HLE</Filter>
</ClCompile>
<ClCompile Include="..\..\Core\Debugger\WebSocket.cpp">
<Filter>Debugger</Filter>
</ClCompile>
@@ -1243,6 +1246,9 @@
<ClInclude Include="..\..\Core\HLE\sceUsbAcc.h">
<Filter>HLE</Filter>
</ClInclude>
<ClInclude Include="..\..\Core\HLE\sceUsbMic.h">
<Filter>HLE</Filter>
</ClInclude>
<ClInclude Include="..\..\Core\Debugger\WebSocket.h">
<Filter>Debugger</Filter>
</ClInclude>
@@ -1292,4 +1298,4 @@
<Filter>MIPS\ARM64</Filter>
</ClInclude>
</ItemGroup>
</Project>
</Project>
+5 -2
View File
@@ -4,6 +4,7 @@
#include <windowsx.h>
#include "..\resource.h"
#include "base/display.h"
#include "util/text/utf8.h"
#include "Core/Debugger/SymbolMap.h"
@@ -218,6 +219,8 @@ void CMemoryDlg::Goto(u32 addr)
void CMemoryDlg::Size()
{
const float fontScale = 1.0f / g_dpi_scale_real_y;
RECT rc;
GetClientRect(m_hDlg,&rc);
int dw=rc.right-rc.left;
@@ -225,8 +228,8 @@ void CMemoryDlg::Size()
HWND memView = GetDlgItem(m_hDlg, IDC_MEMVIEW);
HWND symList = GetDlgItem(m_hDlg, IDC_SYMBOLS);
int wf = slRect.right-slRect.left;
int w = dw-3-wf;
int top = 48;
int w = dw - 3 * fontScale - wf;
int top = 48 * fontScale;
MoveWindow(symList,0,top,wf,dh-top,TRUE);
MoveWindow(memView,wf+4,top,w,dh-top,TRUE);
}
-8
View File
@@ -102,14 +102,6 @@
</intent-filter>
</activity>
<receiver android:name=".PowerSaveModeReceiver">
<intent-filter>
<action android:name="android.os.action.POWER_SAVE_MODE_CHANGED" />
<action android:name="android.intent.action.BATTERY_LOW" />
<action android:name="android.intent.action.BATTERY_OKAY" />
</intent-filter>
</receiver>
<meta-data
android:name="xperiaplayoptimized_content"
android:resource="@drawable/ic_launcher" />
+2
View File
@@ -404,6 +404,8 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init
systemName = GetJavaString(env, jmodel);
langRegion = GetJavaString(env, jlangRegion);
ILOG("NativeApp.init(): device name: '%s'", systemName.c_str());
std::string externalDir = GetJavaString(env, jexternalDir);
std::string user_data_path = GetJavaString(env, jdataDir);
if (user_data_path.size() > 0)
-1
View File
@@ -157,7 +157,6 @@ OpenSLContext::~OpenSLContext() {
bqPlayerObject = nullptr;
bqPlayerPlay = nullptr;
bqPlayerBufferQueue = nullptr;
bqPlayerMuteSolo = nullptr;
bqPlayerVolume = nullptr;
}
-1
View File
@@ -35,7 +35,6 @@ private:
SLObjectItf bqPlayerObject = nullptr;
SLPlayItf bqPlayerPlay = nullptr;
SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue = nullptr;
SLMuteSoloItf bqPlayerMuteSolo = nullptr;
SLVolumeItf bqPlayerVolume = nullptr;
// Double buffering.
+120 -29
View File
@@ -7,7 +7,12 @@ import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.os.SystemClock;
import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.WindowManager;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
@@ -15,67 +20,140 @@ import java.util.List;
@TargetApi(23)
@SuppressWarnings("deprecation")
class CameraHelper {
private static final String TAG = "CameraHelper";
private static final String TAG = CameraHelper.class.getSimpleName();
private Display mDisplay;
private Camera mCamera = null;
private int previewWidth = 0;
private int previewHeight = 0;
private long lastTime = 0;
private boolean mIsCameraRunning = false;
private int mCameraOrientation = 0;
private Camera.Size mPreviewSize = null;
private long mLastFrameTime = 0;
private SurfaceTexture mSurfaceTexture;
private int getCameraRotation() {
int displayRotation = mDisplay.getRotation();
int displayDegrees = 0;
switch (displayRotation) {
case Surface.ROTATION_0: displayDegrees = 0; break;
case Surface.ROTATION_90: displayDegrees = 90; break;
case Surface.ROTATION_180: displayDegrees = 180; break;
case Surface.ROTATION_270: displayDegrees = 270; break;
}
return (mCameraOrientation - displayDegrees + 360) % 360;
}
static byte[] rotateNV21(final byte[] input, final int inWidth, final int inHeight,
final int outWidth, final int outHeight, final int rotation) {
final int inFrameSize = inWidth * inHeight;
final int outFrameSize = outWidth * outHeight;
final byte[] output = new byte[outFrameSize + outFrameSize/2];
if (rotation == 0 || rotation == 180) {
final int crop_left = (inWidth - outWidth) / 2;
final int crop_top = (inHeight - outHeight) / 2;
for (int j = 0; j < outHeight; j++) {
final int yInCol = (crop_top + j) * inWidth + crop_left;
final int uvInCol = inFrameSize + ((crop_top + j) >> 1) * inWidth + crop_left;
final int jOut = rotation == 180 ? outHeight - j - 1 : j;
final int yOutCol = jOut * outWidth;
final int uvOutCol = outFrameSize + (jOut >> 1) * outWidth;
for (int i = 0; i < outWidth; i++) {
final int yIn = yInCol + i;
final int uIn = uvInCol + (i & ~1);
final int vIn = uIn + 1;
final int iOut = rotation == 180 ? outWidth - i - 1 : i;
final int yOut = yOutCol + iOut;
final int uOut = uvOutCol + (iOut & ~1);
final int vOut = uOut + 1;
output[yOut] = input[yIn];
output[uOut] = input[uIn];
output[vOut] = input[vIn];
}
}
} else if (rotation == 90 || rotation == 270) {
int crop_left = (inWidth - outHeight) / 2;
int crop_top = (inHeight - outWidth) / 2;
for (int j = 0; j < outWidth; j++) {
final int yInCol = (crop_top + j) * inWidth + crop_left;
final int uvInCol = inFrameSize + ((crop_top + j) >> 1) * inWidth + crop_left;
final int iOut = rotation == 90 ? outWidth - j - 1 : j;
for (int i = 0; i < outHeight; i++) {
final int yIn = yInCol + i;
final int uIn = uvInCol + (i & ~1);
final int vIn = uIn + 1;
final int jOut = rotation == 270 ? outHeight - i - 1 : i;
final int yOut = jOut * outWidth + iOut;
final int uOut = outFrameSize + (jOut >> 1) * outWidth + (iOut & ~1);
final int vOut = uOut + 1;
output[yOut] = input[yIn];
output[uOut] = input[uIn];
output[vOut] = input[vIn];
}
}
}
return output;
}
private Camera.PreviewCallback mPreviewCallback = new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] previewData, Camera camera) {
// throttle at 100 ms
long currentTime = System.currentTimeMillis();
if (currentTime - lastTime < 100) {
// throttle at 66 ms
long currentTime = SystemClock.elapsedRealtime();
if (currentTime - mLastFrameTime < 66) {
return;
}
lastTime = currentTime;
YuvImage yuvImage = new YuvImage(previewData, ImageFormat.NV21, previewWidth, previewHeight, null);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
mLastFrameTime = currentTime;
// the expected values arrives in sceUsbCamSetupVideo
int targetW = 480;
int targetH = 272;
// crop to expected size and convert to Jpeg
Rect rect = new Rect(
(previewWidth - targetW) / 2,
(previewHeight - targetH) / 2,
previewWidth - (previewWidth - targetW) / 2,
previewHeight - (previewHeight - targetH) / 2
);
yuvImage.compressToJpeg(rect, 80, baos);
int cameraRotation = getCameraRotation();
byte[] newPreviewData = rotateNV21(previewData, mPreviewSize.width, mPreviewSize.height,
targetW, targetH, cameraRotation);
YuvImage yuvImage = new YuvImage(newPreviewData, ImageFormat.NV21, targetW, targetH, null);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// convert to Jpeg
Rect crop = new Rect(0, 0, targetW, targetH);
yuvImage.compressToJpeg(crop, 80, baos);
NativeApp.pushCameraImage(baos.toByteArray());
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
};
@SuppressWarnings("unused")
CameraHelper(Context context) {
CameraHelper(final Context context) {
mDisplay = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
mSurfaceTexture = new SurfaceTexture(10);
}
void startCamera() {
Log.d(TAG, "startCamera");
try {
Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
Camera.getCameraInfo(0, info);
mCameraOrientation = info.orientation;
mCamera = Camera.open();
Camera.Parameters param = mCamera.getParameters();
// Set preview size
List<Camera.Size> previewSizes = param.getSupportedPreviewSizes();
previewWidth = previewSizes.get(0).width;
previewHeight = previewSizes.get(0).height;
mPreviewSize = previewSizes.get(0);
for (int i = 0; i < previewSizes.size(); i++) {
Log.d(TAG, "getSupportedPreviewSizes[" + i + "]: " + previewSizes.get(i).height + " " + previewSizes.get(i).width);
if (previewSizes.get(i).width <= 640 && previewSizes.get(i).height <= 480) {
previewWidth = previewSizes.get(i).width;
previewHeight = previewSizes.get(i).height;
mPreviewSize = previewSizes.get(i);
break;
}
}
Log.d(TAG, "setPreviewSize(" + previewWidth + ", " + previewHeight + ")");
param.setPreviewSize(previewWidth, previewHeight);
Log.d(TAG, "setPreviewSize(" + mPreviewSize.width + ", " + mPreviewSize.height + ")");
param.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
// Set preview FPS
int[] fps;
@@ -94,18 +172,31 @@ class CameraHelper {
mCamera.setPreviewTexture(mSurfaceTexture);
mCamera.setPreviewCallback(mPreviewCallback);
mCamera.startPreview();
mIsCameraRunning = true;
} catch (IOException e) {
Log.e(TAG, "Cannot start camera: " + e.toString());
}
}
void stopCamera() {
Log.d(TAG, "stopCamera");
if (mCamera != null) {
void pause() {
if (mIsCameraRunning && mCamera != null) {
Log.d(TAG, "pause");
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
void resume() {
if (mIsCameraRunning) {
Log.d(TAG, "resume");
startCamera();
}
}
void stopCamera() {
pause();
mIsCameraRunning = false;
}
}
@@ -106,6 +106,8 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
private InputDeviceState inputPlayerC;
private String inputPlayerADesc;
private PowerSaveModeReceiver mPowerSaveModeReceiver = null;
private static LocationHelper mLocationHelper;
private static CameraHelper mCameraHelper;
@@ -311,7 +313,6 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
javaGL = "true".equalsIgnoreCase(NativeApp.queryConfig("androidJavaGL"));
sendInitialGrants();
PowerSaveModeReceiver.initAndSend(this);
// OK, config should be initialized, we can query for screen rotation.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
@@ -489,6 +490,10 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
initialized = true;
}
if (mPowerSaveModeReceiver == null) {
mPowerSaveModeReceiver = new PowerSaveModeReceiver(this);
}
// OK, config should be initialized, we can query for screen rotation.
updateScreenRotation("onCreate");
updateSustainedPerformanceMode();
@@ -703,6 +708,10 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
mSurfaceView.onDestroy();
mSurfaceView = null;
}
if (mPowerSaveModeReceiver != null) {
mPowerSaveModeReceiver.destroy(this);
mPowerSaveModeReceiver = null;
}
// TODO: Can we ensure that the GL thread has stopped rendering here?
// I've seen crashes that seem to indicate that sometimes it hasn't...
NativeApp.audioShutdown();
@@ -731,6 +740,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
Log.e(TAG, "mGLSurfaceView really shouldn't be null in onPause");
}
}
mCameraHelper.pause();
Log.i(TAG, "onPause completed");
}
@@ -770,6 +780,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
mSurfaceView.onResume();
}
}
mCameraHelper.resume();
gainAudioFocus(this.audioManager, this.audioFocusChangeListener);
NativeApp.resume();
@@ -1326,6 +1337,10 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
// Only keep the screen bright ingame.
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
} else if (command.equals("event")) {
if (params.equals("exitgame")) {
mCameraHelper.stopCamera();
}
}
return false;
}
@@ -5,33 +5,42 @@ import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Build;
import android.os.PowerManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
public class PowerSaveModeReceiver extends BroadcastReceiver {
private static final String TAG = PowerSaveModeReceiver.class.getSimpleName();
private static boolean isPowerSaving = false;
private static boolean isBatteryLow = false;
private static final String TAG = "PowerSaveModeReceiver";
@Override
public void onReceive(final Context context, final Intent intent) {
final String action = intent.getAction();
if (action.equals(Intent.ACTION_BATTERY_LOW)) {
if (Intent.ACTION_BATTERY_LOW.equals(action)) {
isBatteryLow = true;
} else if (action.equals(Intent.ACTION_BATTERY_OKAY)) {
} else if (Intent.ACTION_BATTERY_OKAY.equals(action)) {
isBatteryLow = false;
} else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
// sendPowerSaving()
}
sendPowerSaving(context);
}
public static void initAndSend(final Activity activity) {
sendPowerSaving(activity);
public PowerSaveModeReceiver(final Activity activity) {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_LOW);
filter.addAction(Intent.ACTION_BATTERY_OKAY);
if (Build.VERSION.SDK_INT >= 21) {
filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
}
activity.registerReceiver(this, filter);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
activity.getContentResolver().registerContentObserver(Settings.System.CONTENT_URI, true, new ContentObserver(null) {
@@ -46,11 +55,16 @@ public class PowerSaveModeReceiver extends BroadcastReceiver {
}
key = key.substring(key.lastIndexOf("/") + 1, key.length());
if (key.equals("user_powersaver_enable") || key.equals("psm_switch") || key.equals("powersaving_switch")) {
PowerSaveModeReceiver.sendPowerSaving(activity);
sendPowerSaving(activity);
}
}
});
}
sendPowerSaving(activity);
}
public void destroy(final Context context) {
context.unregisterReceiver(this);
}
@TargetApi(21)
@@ -67,7 +81,7 @@ public class PowerSaveModeReceiver extends BroadcastReceiver {
}
// Samsung (Touchwiz)
String s5Value = Settings.System.getString(context.getContentResolver(), "powersaving_switch");
boolean hasS5Value = s5Value != null && !s5Value.equals("");
boolean hasS5Value = !TextUtils.isEmpty(s5Value);
// On newer devices, psm_switch is always set, and powersaving_switch is used instead.
if ((!hasS5Value && getBooleanSetting(context, "psm_switch")) || getBooleanSetting(context, "powersaving_switch")) {
return true;
@@ -80,7 +94,7 @@ public class PowerSaveModeReceiver extends BroadcastReceiver {
return value != null && value.equals("1");
}
private static void sendPowerSaving(final Context context) {
protected void sendPowerSaving(final Context context) {
if (Build.VERSION.SDK_INT >= 21) {
isPowerSaving = getNativePowerSaving(context);
} else {
+36
View File
@@ -760,3 +760,39 @@ NPUH10047 = true
ULAS42214 = true
ULJS19054 = true
NPJH50184 = true
[RenderPassMerge]
UCJS10114 = true
UCKS45084 = true
# GOW : Ghost of Sparta
UCUS98737 = true
UCAS40323 = true
NPHG00092 = true
NPEG00044 = true
NPEG00045 = true
NPJG00120 = true
NPUG80508 = true
UCJS10114 = true
UCES01401 = true
UCES01473 = true
# GOW : Ghost of Sparta Demo
NPEG90035 = true
NPUG70125 = true
NPJG90095 = true
# GOW : Chains Of Olympus
UCAS40198 = true
UCUS98653 = true
UCES00842 = true
ULJM05438 = true
ULJM05348 = true
UCKS45084 = true
NPUG80325 = true
NPEG00023 = true
NPHG00027 = true
NPHG00028 = true
NPJH50170 = true
UCET00844 = true
# GOW: Chains of Olympus Demo
UCUS98705 = true
UCED00971 = true
UCUS98713 = true
+1 -1
View File
@@ -5,7 +5,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.2'
classpath 'com.android.tools.build:gradle:3.5.0'
}
}
+8 -6
View File
@@ -14,15 +14,14 @@
* limitations under the License.
*/
#include "ppsspp_config.h"
#include "../gfx/gl_common.h"
#if defined(USING_GLES2)
#if !defined(IOS)
#if !PPSSPP_PLATFORM(IOS)
#include "EGL/egl.h"
#endif
GLboolean gl3stubInit() {
#if !defined(IOS)
#define FIND_PROC(s) s = (void*)eglGetProcAddress(#s)
FIND_PROC(glReadBuffer);
FIND_PROC(glDrawRangeElements);
@@ -145,7 +144,6 @@ GLboolean gl3stubInit() {
#undef FIND_PROC
#endif // IOS
if (!glReadBuffer ||
!glDrawRangeElements ||
!glTexImage3D ||
@@ -257,8 +255,6 @@ GLboolean gl3stubInit() {
return GL_TRUE;
}
#if !defined(IOS)
/* Function pointer definitions */
GL_APICALL void (* GL_APIENTRY glReadBuffer) (GLenum mode);
GL_APICALL void (* GL_APIENTRY glDrawRangeElements) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices);
@@ -379,6 +375,12 @@ GL_APICALL void (* GL_APIENTRY glBufferStorageEXT) (GLenum target, GLs
/* OES_copy_image, etc. */
GL_APICALL void (* GL_APIENTRY glCopyImageSubDataOES) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);
#else
GLboolean gl3stubInit() {
return GL_TRUE;
}
#endif // IOS
#endif // GLES2
+3 -1
View File
@@ -11,6 +11,8 @@
* - Added gl3stubInit() declaration
*/
#include "ppsspp_config.h"
#if defined(USING_GLES2)
#ifdef __cplusplus
@@ -45,7 +47,7 @@ extern "C" {
* otherwise. */
GLboolean gl3stubInit();
#if !defined(IOS)
#if !PPSSPP_PLATFORM(IOS)
/*-------------------------------------------------------------------------
* Data type definitions
+1 -3
View File
@@ -107,7 +107,6 @@ void GLQueueRunner::RunInitSteps(const std::vector<GLRInitStep> &steps, bool ski
}
case GLRInitStepType::TEXTURE_IMAGE:
{
GLRTexture *tex = step.texture_image.texture;
if (step.texture_image.allocType == GLRAllocType::ALIGNED) {
FreeAlignedMemory(step.texture_image.data);
} else if (step.texture_image.allocType == GLRAllocType::NEW) {
@@ -1317,9 +1316,8 @@ void GLQueueRunner::PerformReadback(const GLRStep &pass) {
}
void GLQueueRunner::PerformReadbackImage(const GLRStep &pass) {
GLRTexture *tex = pass.readback_image.texture;
#ifndef USING_GLES2
GLRTexture *tex = pass.readback_image.texture;
GLRect2D rect = pass.readback_image.srcRect;
if (gl_extensions.VersionGEThan(4, 5)) {
+1 -1
View File
@@ -762,7 +762,7 @@ void GLPushBuffer::Defragment() {
size_ = newSize;
bool res = AddBuffer();
_dbg_assert_msg_(G3D, res, "AddBuffer failed");
_assert_msg_(G3D, res, "AddBuffer failed");
}
size_t GLPushBuffer::GetTotalSize() const {
+143 -19
View File
@@ -1,3 +1,4 @@
#include <map>
#include "DataFormat.h"
#include "VulkanQueueRunner.h"
#include "VulkanRenderManager.h"
@@ -374,12 +375,11 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(const RPKey &key) {
return pass;
}
void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, std::vector<VKRStep *> &steps) {
void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, std::vector<VKRStep *> &steps, VkQueryPool queryPool, std::vector<std::string> *timestampDescriptions) {
// Optimizes renderpasses, then sequences them.
// Planned optimizations:
// * Create copies of render target that are rendered to multiple times and textured from in sequence, and push those render passes
// as early as possible in the frame (Wipeout billboards).
// * Merge subsequent render passes to the same target that are interspersed with unrelated draws to other render targets (God of War).
for (int j = 0; j < (int)steps.size(); j++) {
if (steps[j]->stepType == VKRStepType::RENDER &&
@@ -392,7 +392,6 @@ void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, std::vector<VKRStep *> &st
for (int j = 0; j < (int)steps.size() - 1; j++) {
// Push down empty "Clear/Store" renderpasses, and merge them with the first "Load/Store" to the same framebuffer.
// Actually let's just bother with the first one for now. This affects Wipeout Pure.
if (steps.size() > 1 && steps[j]->stepType == VKRStepType::RENDER &&
steps[j]->render.numDraws == 0 &&
steps[j]->render.numReads == 0 &&
@@ -400,8 +399,8 @@ void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, std::vector<VKRStep *> &st
steps[j]->render.stencil == VKRRenderPassAction::CLEAR &&
steps[j]->render.depth == VKRRenderPassAction::CLEAR) {
// Drop the first step, and merge it into the next step that touches the same framebuffer.
for (size_t i = j + 1; i < steps.size(); i++) {
// Drop the clear step, and merge it into the next step that touches the same framebuffer.
for (int i = j + 1; i < (int)steps.size(); i++) {
if (steps[i]->stepType == VKRStepType::RENDER &&
steps[i]->render.framebuffer == steps[j]->render.framebuffer) {
if (steps[i]->render.color != VKRRenderPassAction::CLEAR) {
@@ -439,6 +438,9 @@ void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, std::vector<VKRStep *> &st
if (hacksEnabled_ & QUEUE_HACK_SONIC) {
ApplySonicHack(steps);
}
if (hacksEnabled_ & QUEUE_HACK_RENDERPASS_MERGE) {
ApplyRenderPassMerge(steps);
}
}
for (size_t i = 0; i < steps.size(); i++) {
@@ -462,6 +464,11 @@ void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, std::vector<VKRStep *> &st
case VKRStepType::RENDER_SKIP:
break;
}
if (queryPool) {
vkCmdWriteTimestamp(cmd, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, (uint32_t)timestampDescriptions->size());
timestampDescriptions->push_back(StepToString(step));
}
}
// Deleting all in one go should be easier on the instruction cache than deleting
@@ -696,10 +703,111 @@ void VulkanQueueRunner::ApplySonicHack(std::vector<VKRStep *> &steps) {
}
}
std::string VulkanQueueRunner::StepToString(const VKRStep &step) const {
char buffer[256];
switch (step.stepType) {
case VKRStepType::RENDER:
{
int w = step.render.framebuffer ? step.render.framebuffer->width : vulkan_->GetBackbufferWidth();
int h = step.render.framebuffer ? step.render.framebuffer->height : vulkan_->GetBackbufferHeight();
snprintf(buffer, sizeof(buffer), "RenderPass (draws: %d, %dx%d, fb: %p, )", step.render.numDraws, w, h, step.render.framebuffer);
break;
}
case VKRStepType::COPY:
snprintf(buffer, sizeof(buffer), "Copy (%dx%d)", step.copy.srcRect.extent.width, step.copy.srcRect.extent.height);
break;
case VKRStepType::BLIT:
snprintf(buffer, sizeof(buffer), "Blit (%dx%d->%dx%d)", step.blit.srcRect.extent.width, step.blit.srcRect.extent.height, step.blit.dstRect.extent.width, step.blit.dstRect.extent.height);
break;
case VKRStepType::READBACK:
snprintf(buffer, sizeof(buffer), "Readback (%dx%d, fb: %p)", step.readback.srcRect.extent.width, step.readback.srcRect.extent.height, step.readback.src);
break;
case VKRStepType::READBACK_IMAGE:
snprintf(buffer, sizeof(buffer), "ReadbackImage (%dx%d)", step.readback_image.srcRect.extent.width, step.readback_image.srcRect.extent.height);
break;
case VKRStepType::RENDER_SKIP:
snprintf(buffer, sizeof(buffer), "(SKIPPED RenderPass)");
break;
default:
buffer[0] = 0;
break;
}
return std::string(buffer);
}
// Ideally, this should be cheap enough to be applied to all games. At least on mobile, it's pretty
// much a guaranteed neutral or win in terms of GPU power. However, dependency calculation really
// must be perfect!
void VulkanQueueRunner::ApplyRenderPassMerge(std::vector<VKRStep *> &steps) {
// First let's count how many times each framebuffer is rendered to.
// If it's more than one, let's do our best to merge them. This can help God of War quite a bit.
std::map<VKRFramebuffer *, int> counts;
for (int i = 0; i < (int)steps.size(); i++) {
if (steps[i]->stepType == VKRStepType::RENDER) {
counts[steps[i]->render.framebuffer]++;
}
}
// Now, let's go through the steps. If we find one that is rendered to more than once,
// we'll scan forward and slurp up any rendering that can be merged across.
for (int i = 0; i < (int)steps.size(); i++) {
if (steps[i]->stepType == VKRStepType::RENDER && counts[steps[i]->render.framebuffer] > 1) {
auto fb = steps[i]->render.framebuffer;
TinySet<VKRFramebuffer *, 8> touchedFramebuffers; // must be the same fast-size as the dependencies TinySet for annoying reasons.
for (int j = i + 1; j < (int)steps.size(); j++) {
// If any other passes are reading from this framebuffer as-is, we cancel the scan.
switch (steps[j]->stepType) {
case VKRStepType::RENDER:
if (steps[j]->dependencies.contains(fb)) {
goto done_fb;
}
// Prevent Unknown's example case from https://github.com/hrydgard/ppsspp/pull/12242
if (steps[j]->dependencies.contains(touchedFramebuffers)) {
goto done_fb;
}
if (steps[j]->render.framebuffer == fb) {
// ok. Now, if it's a render, slurp up all the commands
// and kill the step.
// Also slurp up any pretransitions.
steps[i]->preTransitions.insert(steps[i]->preTransitions.end(), steps[j]->preTransitions.begin(), steps[j]->preTransitions.end());
steps[i]->commands.insert(steps[i]->commands.end(), steps[j]->commands.begin(), steps[j]->commands.end());
steps[j]->stepType = VKRStepType::RENDER_SKIP;
}
// Remember the framebuffer this wrote to. We can't merge with later passes that depend on these.
if (steps[j]->render.framebuffer != fb) {
touchedFramebuffers.insert(steps[j]->render.framebuffer);
}
break;
case VKRStepType::COPY:
if (steps[j]->copy.src == fb || steps[j]->copy.dst == fb) {
goto done_fb;
}
break;
case VKRStepType::BLIT:
if (steps[j]->blit.src == fb || steps[j]->blit.dst == fb) {
goto done_fb;
}
break;
case VKRStepType::READBACK:
// Not sure this has much effect, when executed READBACK is always the last step
// since we stall the GPU and wait immediately after.
if (steps[j]->readback.src == fb) {
goto done_fb;
}
break;
}
}
done_fb:
;
}
}
}
void VulkanQueueRunner::LogSteps(const std::vector<VKRStep *> &steps) {
ILOG("=======================================");
for (size_t i = 0; i < steps.size(); i++) {
const VKRStep &step = *steps[i];
ILOG("%s", StepToString(step).c_str());
switch (step.stepType) {
case VKRStepType::RENDER:
LogRenderPass(step);
@@ -767,20 +875,20 @@ void VulkanQueueRunner::LogRenderPass(const VKRStep &pass) {
ILOG("RenderPass End(%x)", fb);
}
void VulkanQueueRunner::LogCopy(const VKRStep &pass) {
ILOG("Copy()");
void VulkanQueueRunner::LogCopy(const VKRStep &step) {
ILOG("%s", StepToString(step).c_str());
}
void VulkanQueueRunner::LogBlit(const VKRStep &pass) {
ILOG("Blit()");
void VulkanQueueRunner::LogBlit(const VKRStep &step) {
ILOG("%s", StepToString(step).c_str());
}
void VulkanQueueRunner::LogReadback(const VKRStep &pass) {
ILOG("Readback");
void VulkanQueueRunner::LogReadback(const VKRStep &step) {
ILOG("%s", StepToString(step).c_str());
}
void VulkanQueueRunner::LogReadbackImage(const VKRStep &pass) {
ILOG("ReadbackImage");
void VulkanQueueRunner::LogReadbackImage(const VKRStep &step) {
ILOG("%s", StepToString(step).c_str());
}
void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer cmd) {
@@ -869,9 +977,11 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c
auto &commands = step.commands;
// TODO: Dynamic state commands (SetViewport, SetScissor, SetBlendConstants, SetStencil*) are only
// valid when a pipeline is bound with those as dynamic state. So we need to add some state tracking here
// for this to be correct. This is a bit of a pain but also will let us eliminate redundant calls.
// We can do a little bit of state tracking here to eliminate some calls into the driver.
// The stencil ones are very commonly mostly redundant so let's eliminate them where possible.
int lastStencilWriteMask = -1;
int lastStencilCompareMask = -1;
int lastStencilReference = -1;
for (const auto &c : commands) {
switch (c.cmd) {
@@ -882,6 +992,10 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c
if (c.pipeline.pipeline != lastPipeline) {
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, c.pipeline.pipeline);
lastPipeline = c.pipeline.pipeline;
// Reset dynamic state so it gets refreshed with the new pipeline.
lastStencilWriteMask = -1;
lastStencilCompareMask = -1;
lastStencilReference = -1;
}
break;
@@ -902,9 +1016,18 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c
break;
case VKRRenderCommand::STENCIL:
vkCmdSetStencilWriteMask(cmd, VK_STENCIL_FRONT_AND_BACK, c.stencil.stencilWriteMask);
vkCmdSetStencilCompareMask(cmd, VK_STENCIL_FRONT_AND_BACK, c.stencil.stencilCompareMask);
vkCmdSetStencilReference(cmd, VK_STENCIL_FRONT_AND_BACK, c.stencil.stencilRef);
if (lastStencilWriteMask != c.stencil.stencilWriteMask) {
lastStencilWriteMask = (int)c.stencil.stencilWriteMask;
vkCmdSetStencilWriteMask(cmd, VK_STENCIL_FRONT_AND_BACK, c.stencil.stencilWriteMask);
}
if (lastStencilCompareMask != c.stencil.stencilCompareMask) {
lastStencilCompareMask = c.stencil.stencilCompareMask;
vkCmdSetStencilCompareMask(cmd, VK_STENCIL_FRONT_AND_BACK, c.stencil.stencilCompareMask);
}
if (lastStencilReference != c.stencil.stencilRef) {
lastStencilReference = c.stencil.stencilRef;
vkCmdSetStencilReference(cmd, VK_STENCIL_FRONT_AND_BACK, c.stencil.stencilRef);
}
break;
case VKRRenderCommand::DRAW_INDEXED:
@@ -924,6 +1047,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c
case VKRRenderCommand::CLEAR:
{
// If we get here, we failed to merge a clear into a render pass load op. This is bad for perf.
int numAttachments = 0;
VkClearRect rc{};
rc.baseArrayLayer = 0;
+73 -1
View File
@@ -13,6 +13,72 @@ struct VKRImage;
enum {
QUEUE_HACK_MGS2_ACID = 1,
QUEUE_HACK_SONIC = 2,
// Killzone PR = 4.
QUEUE_HACK_RENDERPASS_MERGE = 8,
};
// Insert-only small-set implementation. Performs no allocation unless MaxFastSize is exceeded.
template <class T, int MaxFastSize>
struct TinySet {
~TinySet() { delete slowLookup_; }
inline void insert(T t) {
// Fast linear scan.
for (int i = 0; i < fastCount; i++) {
if (fastLookup_[i] == t)
return; // We already have it.
}
// Fast insertion
if (fastCount < MaxFastSize) {
fastLookup_[fastCount++] = t;
return;
}
// Fall back to slow path.
insertSlow(t);
}
bool contains(T t) const {
for (int i = 0; i < fastCount; i++) {
if (fastLookup_[i] == t)
return true;
}
if (slowLookup_) {
for (auto x : *slowLookup_) {
if (x == t)
return true;
}
}
return false;
}
bool contains(const TinySet<T, MaxFastSize> &otherSet) {
// Awkward, kind of ruins the fun.
for (int i = 0; i < fastCount; i++) {
if (otherSet.contains(fastLookup_[i]))
return true;
}
if (slowLookup_) {
for (auto x : *slowLookup_) {
if (otherSet.contains(x))
return true;
}
}
return false;
}
private:
void insertSlow(T t) {
if (!slowLookup_) {
slowLookup_ = new std::vector<T>();
} else {
for (size_t i = 0; i < slowLookup_->size(); i++) {
if ((*slowLookup_)[i] == t)
return;
}
}
slowLookup_->push_back(t);
}
T fastLookup_[MaxFastSize];
int fastCount = 0;
int slowCount = 0;
std::vector<T> *slowLookup_ = nullptr;
};
enum class VKRRenderCommand : uint8_t {
@@ -109,9 +175,12 @@ struct TransitionRequest {
struct VKRStep {
VKRStep(VKRStepType _type) : stepType(_type) {}
~VKRStep() {}
VKRStepType stepType;
std::vector<VkRenderData> commands;
std::vector<TransitionRequest> preTransitions;
TinySet<VKRFramebuffer *, 8> dependencies;
union {
struct {
VKRFramebuffer *framebuffer;
@@ -163,9 +232,11 @@ public:
}
// RunSteps can modify steps but will leave it in a valid state.
void RunSteps(VkCommandBuffer cmd, std::vector<VKRStep *> &steps);
void RunSteps(VkCommandBuffer cmd, std::vector<VKRStep *> &steps, VkQueryPool queryPool, std::vector<std::string> *timestampDescriptions);
void LogSteps(const std::vector<VKRStep *> &steps);
std::string StepToString(const VKRStep &step) const;
void CreateDeviceObjects();
void DestroyDeviceObjects();
@@ -240,6 +311,7 @@ private:
void ApplyMGSHack(std::vector<VKRStep *> &steps);
void ApplySonicHack(std::vector<VKRStep *> &steps);
void ApplyRenderPassMerge(std::vector<VKRStep *> &steps);
static void SetupTransitionToTransferSrc(VKRImage &img, VkImageMemoryBarrier &barrier, VkPipelineStageFlags &stage, VkImageAspectFlags aspect);
static void SetupTransitionToTransferDst(VKRImage &img, VkImageMemoryBarrier &barrier, VkPipelineStageFlags &stage, VkImageAspectFlags aspect);
+84 -15
View File
@@ -1,6 +1,8 @@
#include <algorithm>
#include <cstdint>
#include <sstream>
#include "Common/Log.h"
#include "base/logging.h"
@@ -65,7 +67,7 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int
VkImageAspectFlags aspects = color ? VK_IMAGE_ASPECT_COLOR_BIT : (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
VkImageViewCreateInfo ivci{ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
ivci.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
ivci.components = { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY };
ivci.format = ici.format;
ivci.image = img.image;
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
@@ -132,6 +134,11 @@ VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan) : vulkan_(vulkan
res = vkAllocateCommandBuffers(vulkan_->GetDevice(), &cmd_alloc, &frameData_[i].mainCmd);
assert(res == VK_SUCCESS);
frameData_[i].fence = vulkan_->CreateFence(true); // So it can be instantly waited on
VkQueryPoolCreateInfo query_ci{ VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO };
query_ci.queryCount = MAX_TIMESTAMP_QUERIES;
query_ci.queryType = VK_QUERY_TYPE_TIMESTAMP;
res = vkCreateQueryPool(vulkan_->GetDevice(), &query_ci, nullptr, &frameData_[i].timestampQueryPool_);
}
queueRunner_.CreateDeviceObjects();
@@ -164,10 +171,10 @@ void VulkanRenderManager::CreateBackbuffers() {
VkImageViewCreateInfo color_image_view = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
color_image_view.format = vulkan_->GetSwapchainFormat();
color_image_view.components.r = VK_COMPONENT_SWIZZLE_R;
color_image_view.components.g = VK_COMPONENT_SWIZZLE_G;
color_image_view.components.b = VK_COMPONENT_SWIZZLE_B;
color_image_view.components.a = VK_COMPONENT_SWIZZLE_A;
color_image_view.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
color_image_view.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
color_image_view.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
color_image_view.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
color_image_view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
color_image_view.subresourceRange.baseMipLevel = 0;
color_image_view.subresourceRange.levelCount = 1;
@@ -222,6 +229,8 @@ void VulkanRenderManager::StopThread() {
std::unique_lock<std::mutex> lock(frameData.pull_mutex);
frameData.pull_condVar.notify_all();
}
// Zero the queries so we don't try to pull them later.
frameData.timestampDescriptions.clear();
}
thread_.join();
ILOG("Vulkan submission thread joined. Frame=%d", vulkan_->GetCurFrame());
@@ -292,6 +301,7 @@ VulkanRenderManager::~VulkanRenderManager() {
vkDestroyCommandPool(device, frameData_[i].cmdPoolInit, nullptr);
vkDestroyCommandPool(device, frameData_[i].cmdPoolMain, nullptr);
vkDestroyFence(device, frameData_[i].fence, nullptr);
vkDestroyQueryPool(device, frameData_[i].timestampQueryPool_, nullptr);
}
queueRunner_.DestroyDeviceObjects();
}
@@ -342,12 +352,13 @@ void VulkanRenderManager::ThreadFunc() {
VLOG("PULL: Quitting");
}
void VulkanRenderManager::BeginFrame() {
void VulkanRenderManager::BeginFrame(bool enableProfiling) {
VLOG("BeginFrame");
VkDevice device = vulkan_->GetDevice();
int curFrame = vulkan_->GetCurFrame();
FrameData &frameData = frameData_[curFrame];
frameData.profilingEnabled_ = enableProfiling;
// Make sure the very last command buffer from the frame before the previous has been fully executed.
if (useThread_) {
@@ -363,6 +374,41 @@ void VulkanRenderManager::BeginFrame() {
vkWaitForFences(device, 1, &frameData.fence, true, UINT64_MAX);
vkResetFences(device, 1, &frameData.fence);
uint64_t queryResults[MAX_TIMESTAMP_QUERIES];
if (frameData.profilingEnabled_) {
// Pull the profiling results from last time and produce a summary!
if (!frameData.timestampDescriptions.empty()) {
int numQueries = (int)frameData.timestampDescriptions.size();
VkResult res = vkGetQueryPoolResults(
vulkan_->GetDevice(),
frameData.timestampQueryPool_, 0, numQueries, sizeof(uint64_t) * numQueries, &queryResults[0], sizeof(uint64_t),
VK_QUERY_RESULT_64_BIT);
if (res == VK_SUCCESS) {
double timestampConversionFactor = (double)vulkan_->GetPhysicalDeviceProperties().properties.limits.timestampPeriod * (1.0 / 1000000.0);
int validBits = vulkan_->GetQueueFamilyProperties(vulkan_->GetGraphicsQueueFamilyIndex()).timestampValidBits;
uint64_t timestampDiffMask = validBits == 64 ? 0xFFFFFFFFFFFFFFFFULL : ((1ULL << validBits) - 1);
std::stringstream str;
char line[256];
snprintf(line, sizeof(line), "Total GPU time: %0.3f ms\n", ((double)((queryResults[numQueries - 1] - queryResults[0]) & timestampDiffMask) * timestampConversionFactor));
str << line;
for (int i = 0; i < numQueries - 1; i++) {
uint64_t diff = (queryResults[i + 1] - queryResults[i]) & timestampDiffMask;
double milliseconds = (double)diff * timestampConversionFactor;
snprintf(line, sizeof(line), "%s: %0.3f ms\n", frameData.timestampDescriptions[i + 1].c_str(), milliseconds);
str << line;
}
frameData.profileSummary = str.str();
} else {
frameData.profileSummary = "(error getting GPU profile - not ready?)";
}
}
else {
frameData.profileSummary = "(no GPU profile data collected)";
}
}
// Must be after the fence - this performs deletes.
VLOG("PUSH: BeginFrame %d", curFrame);
if (!run_) {
@@ -371,6 +417,18 @@ void VulkanRenderManager::BeginFrame() {
vulkan_->BeginFrame();
insideFrame_ = true;
frameData.timestampDescriptions.clear();
if (frameData_->profilingEnabled_) {
// For various reasons, we need to always use an init cmd buffer in this case to perform the vkCmdResetQueryPool,
// unless we want to limit ourselves to only measure the main cmd buffer.
// Reserve the first two queries for initCmd.
frameData.timestampDescriptions.push_back("initCmd Begin");
frameData.timestampDescriptions.push_back("initCmd");
VkCommandBuffer initCmd = GetInitCmd();
vkCmdResetQueryPool(initCmd, frameData.timestampQueryPool_, 0, MAX_TIMESTAMP_QUERIES);
vkCmdWriteTimestamp(initCmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, frameData.timestampQueryPool_, 0);
}
}
VkCommandBuffer VulkanRenderManager::GetInitCmd() {
@@ -397,6 +455,7 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR
if (steps_.size() && steps_.back()->render.framebuffer == fb && steps_.back()->stepType == VKRStepType::RENDER) {
if (color != VKRRenderPassAction::CLEAR && depth != VKRRenderPassAction::CLEAR && stencil != VKRRenderPassAction::CLEAR) {
// We don't move to a new step, this bind was unnecessary and we can safely skip it.
// Not sure how much this is still happening but probably worth checking for nevertheless.
return;
}
}
@@ -561,7 +620,6 @@ bool VulkanRenderManager::InitDepthStencilBuffer(VkCommandBuffer cmd) {
image_info.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
image_info.flags = 0;
depth_.format = depth_format;
VkDevice device = vulkan_->GetDevice();
@@ -611,10 +669,10 @@ bool VulkanRenderManager::InitDepthStencilBuffer(VkCommandBuffer cmd) {
VkImageViewCreateInfo depth_view_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
depth_view_info.image = depth_.image;
depth_view_info.format = depth_format;
depth_view_info.components.r = VK_COMPONENT_SWIZZLE_R;
depth_view_info.components.g = VK_COMPONENT_SWIZZLE_G;
depth_view_info.components.b = VK_COMPONENT_SWIZZLE_B;
depth_view_info.components.a = VK_COMPONENT_SWIZZLE_A;
depth_view_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
depth_view_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
depth_view_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
depth_view_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
depth_view_info.subresourceRange.aspectMask = aspectMask;
depth_view_info.subresourceRange.baseMipLevel = 0;
depth_view_info.subresourceRange.levelCount = 1;
@@ -803,7 +861,9 @@ void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect,
}
VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, int aspectBit, int attachment) {
// Should just mark the dependency and return the image.
_dbg_assert_(G3D, curRenderStep_ != nullptr);
// Mark the dependency, check for required transitions, and return the image.
for (int i = (int)steps_.size() - 1; i >= 0; i--) {
if (steps_[i]->stepType == VKRStepType::RENDER && steps_[i]->render.framebuffer == fb) {
// If this framebuffer was rendered to earlier in this frame, make sure to pre-transition it to the correct layout.
@@ -815,14 +875,18 @@ VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, in
}
}
// Track dependencies fully.
curRenderStep_->dependencies.insert(fb);
if (!curRenderStep_->preTransitions.empty() &&
curRenderStep_->preTransitions.back().fb == fb &&
curRenderStep_->preTransitions.back().targetLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
// We're done.
return fb->color.imageView;
} else {
curRenderStep_->preTransitions.push_back({ fb, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL });
return fb->color.imageView;
}
curRenderStep_->preTransitions.push_back({ fb, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL });
return fb->color.imageView;
}
void VulkanRenderManager::Finish() {
@@ -885,6 +949,7 @@ void VulkanRenderManager::BeginSubmitFrame(int frame) {
VkCommandBufferBeginInfo begin{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
res = vkBeginCommandBuffer(frameData.mainCmd, &begin);
_assert_msg_(G3D, res == VK_SUCCESS, "vkBeginCommandBuffer failed! result=%s", VulkanResultToString(res));
queueRunner_.SetBackbuffer(framebuffers_[frameData.curSwapchainImage], swapchainImages_[frameData.curSwapchainImage].image);
@@ -896,6 +961,10 @@ void VulkanRenderManager::BeginSubmitFrame(int frame) {
void VulkanRenderManager::Submit(int frame, bool triggerFence) {
FrameData &frameData = frameData_[frame];
if (frameData.hasInitCommands) {
if (frameData.profilingEnabled_ && triggerFence) {
// Pre-allocated query ID 1.
vkCmdWriteTimestamp(frameData.initCmd, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, frameData.timestampQueryPool_, 1);
}
VkResult res = vkEndCommandBuffer(frameData.initCmd);
_assert_msg_(G3D, res == VK_SUCCESS, "vkEndCommandBuffer failed (init)! result=%s", VulkanResultToString(res));
}
@@ -995,7 +1064,7 @@ void VulkanRenderManager::Run(int frame) {
auto &stepsOnThread = frameData_[frame].steps;
VkCommandBuffer cmd = frameData.mainCmd;
// queueRunner_.LogSteps(stepsOnThread);
queueRunner_.RunSteps(cmd, stepsOnThread);
queueRunner_.RunSteps(cmd, stepsOnThread, frameData.profilingEnabled_ ? frameData.timestampQueryPool_ : VK_NULL_HANDLE, &frameData.timestampDescriptions);
stepsOnThread.clear();
switch (frameData.type) {
+16 -1
View File
@@ -92,7 +92,7 @@ public:
void ThreadFunc();
// Makes sure that the GPU has caught up enough that we can start writing buffers of this frame again.
void BeginFrame();
void BeginFrame(bool enableProfiling);
// Can run on a different thread!
void Finish();
void Run(int frame);
@@ -242,6 +242,10 @@ public:
return &queueRunner_;
}
std::string GetGpuProfileString() const {
return frameData_[vulkan_->GetCurFrame()].profileSummary;
}
private:
bool InitBackbufferFramebuffers(int width, int height);
bool InitDepthStencilBuffer(VkCommandBuffer cmd); // Used for non-buffered rendering.
@@ -284,9 +288,20 @@ private:
// Swapchain.
bool hasBegun = false;
uint32_t curSwapchainImage = -1;
// Profiling.
VkQueryPool timestampQueryPool_ = VK_NULL_HANDLE;
bool profilingEnabled_;
std::vector<std::string> timestampDescriptions;
std::string profileSummary;
};
FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES];
enum {
MAX_TIMESTAMP_QUERIES = 256,
};
// Submission time state
int curWidth_ = -1;
int curHeight_ = -1;
+1 -1
View File
@@ -879,7 +879,7 @@ VKContext::~VKContext() {
}
void VKContext::BeginFrame() {
renderManager_.BeginFrame();
renderManager_.BeginFrame(g_Config.bShowGpuProfile);
FrameData &frame = frame_[vulkan_->GetCurFrame()];
push_ = frame.pushBuffer;
+8 -3
View File
@@ -268,6 +268,9 @@ bool PopupScreen::key(const KeyInput &key) {
void PopupScreen::update() {
UIDialogScreen::update();
if (defaultButton_)
defaultButton_->SetEnabled(CanComplete(DR_OK));
float animatePos = 1.0f;
++frames_;
@@ -314,10 +317,12 @@ void PopupScreen::SetPopupOrigin(const UI::View *view) {
}
void PopupScreen::TriggerFinish(DialogResult result) {
finishFrame_ = frames_;
finishResult_ = result;
if (CanComplete(result)) {
finishFrame_ = frames_;
finishResult_ = result;
OnCompleted(result);
OnCompleted(result);
}
}
void PopupScreen::resized() {
+2 -1
View File
@@ -84,6 +84,7 @@ protected:
virtual bool FillVertical() const { return false; }
virtual UI::Size PopupWidth() const { return 550; }
virtual bool ShowButtons() const { return true; }
virtual bool CanComplete(DialogResult result) { return true; }
virtual void OnCompleted(DialogResult result) {}
virtual void update() override;
@@ -225,7 +226,7 @@ private:
class TextEditPopupScreen : public PopupScreen {
public:
TextEditPopupScreen(std::string *value, std::string &placeholder, const std::string &title, int maxLen)
TextEditPopupScreen(std::string *value, const std::string &placeholder, const std::string &title, int maxLen)
: PopupScreen(title, "OK", "Cancel"), value_(value), placeholder_(placeholder), maxLen_(maxLen) {}
virtual void CreatePopupContents(ViewGroup *parent) override;
+2 -2
View File
@@ -1,6 +1,6 @@
#Fri Apr 19 22:49:10 CEST 2019
#Fri Aug 23 16:10:47 CEST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip