mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-15 02:29:51 +01:00
Merge branch 'master' into TemporaryHackishBranch
This commit is contained in:
commit
36a8b5b8c8
53 files changed
+1191
-1300
No files matched your search
@@ -36,4 +36,4 @@ public:
|
||||
void Resize() override {}
|
||||
|
||||
Draw::DrawContext *GetDrawContext() override { return nullptr; }
|
||||
};
|
||||
};
|
||||
+4
-4
@@ -399,7 +399,7 @@ void SetDefaultKeyMap(DefaultMaps dmap, bool replace) {
|
||||
UpdateNativeMenuKeys();
|
||||
}
|
||||
|
||||
const KeyMap_IntStrPair key_names[] = {
|
||||
static const KeyMap_IntStrPair key_names[] = {
|
||||
{NKCODE_A, "A"},
|
||||
{NKCODE_B, "B"},
|
||||
{NKCODE_C, "C"},
|
||||
@@ -590,7 +590,7 @@ const KeyMap_IntStrPair key_names[] = {
|
||||
{NKCODE_RIGHTBRACE, "}"},
|
||||
};
|
||||
|
||||
const KeyMap_IntStrPair axis_names[] = {
|
||||
static const KeyMap_IntStrPair axis_names[] = {
|
||||
{JOYSTICK_AXIS_X, "X Axis"},
|
||||
{JOYSTICK_AXIS_Y, "Y Axis"},
|
||||
{JOYSTICK_AXIS_PRESSURE, "Pressure"},
|
||||
@@ -878,7 +878,7 @@ void LoadFromIni(IniFile &file) {
|
||||
IniFile::Section *controls = file.GetOrCreateSection("ControlMapping");
|
||||
for (size_t i = 0; i < ARRAY_SIZE(psp_button_names); i++) {
|
||||
std::string value;
|
||||
controls->Get(psp_button_names[i].name.c_str(), &value, "");
|
||||
controls->Get(psp_button_names[i].name, &value, "");
|
||||
|
||||
// Erase default mapping
|
||||
g_controllerMap.erase(psp_button_names[i].key);
|
||||
@@ -917,7 +917,7 @@ void SaveToIni(IniFile &file) {
|
||||
value += ",";
|
||||
}
|
||||
|
||||
controls->Set(psp_button_names[i].name.c_str(), value, "");
|
||||
controls->Set(psp_button_names[i].name, value, "");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -86,7 +86,7 @@ namespace KeyMap {
|
||||
// Key & Button names
|
||||
struct KeyMap_IntStrPair {
|
||||
int key;
|
||||
std::string name;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
// Use if you need to display the textual name
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "base/basictypes.h"
|
||||
#include "VulkanContext.h"
|
||||
#include "GPU/Common/ShaderCommon.h"
|
||||
#include "Common/StringUtils.h"
|
||||
|
||||
#ifdef USE_CRT_DBG
|
||||
#undef new
|
||||
@@ -50,6 +51,20 @@ static const char *validationLayers[] = {
|
||||
*/
|
||||
};
|
||||
|
||||
std::string VulkanVendorString(uint32_t vendorId) {
|
||||
switch (vendorId) {
|
||||
case VULKAN_VENDOR_INTEL: return "Intel";
|
||||
case VULKAN_VENDOR_NVIDIA: return "nVidia";
|
||||
case VULKAN_VENDOR_AMD: return "AMD";
|
||||
case VULKAN_VENDOR_ARM: return "ARM";
|
||||
case VULKAN_VENDOR_QUALCOMM: return "Qualcomm";
|
||||
case VULKAN_VENDOR_IMGTEC: return "Imagination";
|
||||
|
||||
default:
|
||||
return StringFromFormat("%08x", vendorId);
|
||||
}
|
||||
}
|
||||
|
||||
VulkanContext::VulkanContext() {
|
||||
if (!VulkanLoad()) {
|
||||
init_error_ = "Failed to load Vulkan driver library";
|
||||
@@ -120,6 +135,11 @@ VkResult VulkanContext::CreateInstance(const char *app_name, int app_ver, uint32
|
||||
}
|
||||
|
||||
VulkanLoadInstanceFunctions(instance_);
|
||||
if (!CheckLayers(instance_layer_properties_, instance_layer_names_)) {
|
||||
WLOG("CheckLayers for instance failed");
|
||||
// init_error_ = "Failed to validate instance layers";
|
||||
// return;
|
||||
}
|
||||
|
||||
uint32_t gpu_count = 1;
|
||||
res = vkEnumeratePhysicalDevices(instance_, &gpu_count, nullptr);
|
||||
@@ -141,11 +161,6 @@ VkResult VulkanContext::CreateInstance(const char *app_name, int app_ver, uint32
|
||||
return res;
|
||||
}
|
||||
|
||||
if (!CheckLayers(instance_layer_properties_, instance_layer_names_)) {
|
||||
WLOG("CheckLayers failed");
|
||||
// init_error_ = "Failed to validate instance layers";
|
||||
// return;
|
||||
}
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -333,14 +348,47 @@ bool VulkanContext::CheckLayers(const std::vector<LayerProperties> &layer_props,
|
||||
return true;
|
||||
}
|
||||
|
||||
int VulkanContext::GetBestPhysicalDevice() {
|
||||
// Rules: Prefer discrete over embedded.
|
||||
// Prefer nVidia over Intel.
|
||||
|
||||
int maxScore = -1;
|
||||
int best = -1;
|
||||
|
||||
for (size_t i = 0; i < physical_devices_.size(); i++) {
|
||||
int score = 0;
|
||||
VkPhysicalDeviceProperties props;
|
||||
vkGetPhysicalDeviceProperties(physical_devices_[i], &props);
|
||||
switch (props.deviceType) {
|
||||
case VK_PHYSICAL_DEVICE_TYPE_CPU:
|
||||
score += 1;
|
||||
break;
|
||||
case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
|
||||
score += 20;
|
||||
break;
|
||||
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
|
||||
score += 10;
|
||||
break;
|
||||
}
|
||||
if (props.vendorID == VULKAN_VENDOR_AMD) {
|
||||
score += 5;
|
||||
} else if (props.vendorID == VULKAN_VENDOR_NVIDIA) {
|
||||
score += 5;
|
||||
}
|
||||
if (score > maxScore) {
|
||||
best = (int)i;
|
||||
maxScore = score;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
void VulkanContext::ChooseDevice(int physical_device) {
|
||||
physical_device_ = physical_device;
|
||||
|
||||
GetDeviceLayerProperties();
|
||||
if (!CheckLayers(device_layer_properties_, device_layer_names_)) {
|
||||
WLOG("CheckLayers failed (2)");
|
||||
// init_error_ = "Failed to validate device layers";
|
||||
// return;
|
||||
WLOG("CheckLayers for device %d failed", physical_device);
|
||||
}
|
||||
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(physical_devices_[physical_device_], &queue_count, nullptr);
|
||||
@@ -786,7 +834,8 @@ bool VulkanContext::CreateShaderModule(const std::vector<uint32_t> &spirv, VkSha
|
||||
void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, VkImageAspectFlags aspectMask,
|
||||
VkImageLayout oldImageLayout, VkImageLayout newImageLayout,
|
||||
VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
|
||||
VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask) {
|
||||
VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask,
|
||||
int numMipLevels) {
|
||||
VkImageMemoryBarrier image_memory_barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
|
||||
image_memory_barrier.srcAccessMask = srcAccessMask;
|
||||
image_memory_barrier.dstAccessMask = dstAccessMask;
|
||||
@@ -795,8 +844,8 @@ void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, VkImageAspectFla
|
||||
image_memory_barrier.image = image;
|
||||
image_memory_barrier.subresourceRange.aspectMask = aspectMask;
|
||||
image_memory_barrier.subresourceRange.baseMipLevel = 0;
|
||||
image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
|
||||
image_memory_barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
|
||||
image_memory_barrier.subresourceRange.levelCount = numMipLevels;
|
||||
image_memory_barrier.subresourceRange.layerCount = 1; // We never use more than one layer, and old Mali drivers have problems with VK_REMAINING_ARRAY_LAYERS/VK_REMAINING_MIP_LEVELS.
|
||||
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
vkCmdPipelineBarrier(cmd, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
|
||||
@@ -906,11 +955,10 @@ const char *VulkanResultToString(VkResult res) {
|
||||
case VK_ERROR_OUT_OF_DATE_KHR: return "VK_ERROR_OUT_OF_DATE_KHR";
|
||||
case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR";
|
||||
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR";
|
||||
case VK_ERROR_OUT_OF_POOL_MEMORY_KHR: return "VK_ERROR_OUT_OF_POOL_MEMORY_KHR";
|
||||
case VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX: return "VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX";
|
||||
|
||||
default:
|
||||
return "Unknown";
|
||||
return "VK_ERROR_...(unknown)";
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanAssertImpl(VkResult check, const char *function, const char *file, int line) {
|
||||
const char *error = "(none)";
|
||||
}
|
||||
@@ -43,6 +43,18 @@ enum {
|
||||
VULKAN_FLAG_PRESENT_FIFO_RELAXED = 8,
|
||||
};
|
||||
|
||||
enum {
|
||||
VULKAN_VENDOR_NVIDIA = 0x000010de,
|
||||
VULKAN_VENDOR_INTEL = 0x00008086, // Haha!
|
||||
VULKAN_VENDOR_AMD = 0x00001002,
|
||||
VULKAN_VENDOR_ARM = 0x000013B5, // Mali
|
||||
VULKAN_VENDOR_QUALCOMM = 0x00005143,
|
||||
VULKAN_VENDOR_IMGTEC = 0x00001010, // PowerVR
|
||||
};
|
||||
|
||||
std::string VulkanVendorString(uint32_t vendorId);
|
||||
|
||||
|
||||
struct VulkanPhysicalDeviceInfo {
|
||||
VkFormat preferredDepthStencilFormat;
|
||||
};
|
||||
@@ -203,8 +215,7 @@ public:
|
||||
|
||||
VkResult CreateInstance(const char *app_name, int app_ver, uint32_t flags);
|
||||
|
||||
// TODO: Actually do some checks?
|
||||
int GetBestPhysicalDevice() const { return 0; }
|
||||
int GetBestPhysicalDevice();
|
||||
void ChooseDevice(int physical_device);
|
||||
bool EnableDeviceExtension(const char *extension);
|
||||
VkResult CreateDevice();
|
||||
@@ -393,12 +404,14 @@ private:
|
||||
void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, VkImageAspectFlags aspectMask,
|
||||
VkImageLayout oldImageLayout, VkImageLayout newImageLayout,
|
||||
VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
|
||||
VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask);
|
||||
VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, int mipLevels = VK_REMAINING_MIP_LEVELS);
|
||||
|
||||
// GLSL compiler
|
||||
void init_glslang();
|
||||
void finalize_glslang();
|
||||
bool GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *pshader, std::vector<uint32_t> &spirv, std::string *errorMessage = nullptr);
|
||||
|
||||
const char *VulkanResultToString(VkResult res);
|
||||
|
||||
#endif // UTIL_INIT
|
||||
|
||||
@@ -407,7 +407,6 @@ static bool DefaultSasThread() {
|
||||
|
||||
static ConfigSetting cpuSettings[] = {
|
||||
ReportedConfigSetting("CPUCore", &g_Config.iCpuCore, &DefaultCpuCore, true, true),
|
||||
ReportedConfigSetting("SeparateCPUThread", &g_Config.bSeparateCPUThread, false, true, true),
|
||||
ReportedConfigSetting("SeparateSASThread", &g_Config.bSeparateSASThread, &DefaultSasThread, true, true),
|
||||
ReportedConfigSetting("SeparateIOThread", &g_Config.bSeparateIOThread, true, true, true),
|
||||
ReportedConfigSetting("IOTimingMethod", &g_Config.iIOTimingMethod, IOTIMING_REALISTIC, true, true),
|
||||
|
||||
@@ -133,8 +133,6 @@ public:
|
||||
bool bFuncReplacements;
|
||||
bool bHideSlowWarnings;
|
||||
|
||||
// Definitely cannot be changed while game is running.
|
||||
bool bSeparateCPUThread;
|
||||
bool bSeparateSASThread;
|
||||
bool bSeparateIOThread;
|
||||
int iIOTimingMethod;
|
||||
|
||||
+851
-595
File diff suppressed because it is too large.
Load diff
+30
-10
@@ -18,25 +18,45 @@ void __CheatDoState(PointerWrap &p);
|
||||
// Return whether cheats are enabled and in effect.
|
||||
bool CheatsInEffect();
|
||||
|
||||
struct CheatLine {
|
||||
uint32_t part1;
|
||||
uint32_t part2;
|
||||
};
|
||||
|
||||
enum class CheatCodeFormat {
|
||||
UNDEFINED,
|
||||
CWCHEAT,
|
||||
TEMPAR,
|
||||
};
|
||||
|
||||
struct CheatCode {
|
||||
CheatCodeFormat fmt;
|
||||
std::vector<CheatLine> lines;
|
||||
};
|
||||
|
||||
struct CheatOperation;
|
||||
|
||||
class CWCheatEngine {
|
||||
public:
|
||||
CWCheatEngine();
|
||||
std::vector<std::string> GetCodesList();
|
||||
void CreateCodeList();
|
||||
void ParseCheats();
|
||||
void CreateCheatFile();
|
||||
void Exit();
|
||||
void Run();
|
||||
std::vector<int> GetNextCode();
|
||||
bool HasCheats();
|
||||
|
||||
private:
|
||||
void InvalidateICache(u32 addr, int size);
|
||||
void SkipCodes(int count);
|
||||
void SkipAllCodes();
|
||||
bool exit2, cheatEnabled;
|
||||
int GetAddress(int value);
|
||||
std::vector<std::string> codeNameList;
|
||||
u32 GetAddress(u32 value);
|
||||
|
||||
std::vector<std::string> codes, initialCodesList, parts;
|
||||
size_t currentCode;
|
||||
CheatOperation InterpretNextOp(const CheatCode &cheat, size_t &i);
|
||||
CheatOperation InterpretNextCwCheat(const CheatCode &cheat, size_t &i);
|
||||
CheatOperation InterpretNextTempAR(const CheatCode &cheat, size_t &i);
|
||||
|
||||
void ExecuteOp(const CheatOperation &op, const CheatCode &cheat, size_t &i);
|
||||
void ApplyMemoryOperator(const CheatOperation &op, uint32_t(*oper)(uint32_t, uint32_t));
|
||||
bool TestIf(const CheatOperation &op, bool(*oper)(int a, int b));
|
||||
bool TestIfAddr(const CheatOperation &op, bool(*oper)(int a, int b));
|
||||
|
||||
std::vector<CheatCode> cheats_;
|
||||
};
|
||||
+6
-29
@@ -57,10 +57,6 @@ static int geSyncEvent;
|
||||
static int geInterruptEvent;
|
||||
static int geCycleEvent;
|
||||
|
||||
// Let's try updating 10 times per vblank - this is the interval for geCycleEvent.
|
||||
const int geIntervalUs = 1000000 / (60 * 10);
|
||||
const int geBehindThresholdUs = 1000000 / (60 * 10);
|
||||
|
||||
class GeIntrHandler : public IntrHandler {
|
||||
public:
|
||||
GeIntrHandler() : IntrHandler(PSP_GE_INTR) {}
|
||||
@@ -194,19 +190,7 @@ static void __GeExecuteInterrupt(u64 userdata, int cyclesLate) {
|
||||
}
|
||||
|
||||
static void __GeCheckCycles(u64 userdata, int cyclesLate) {
|
||||
u64 geTicks = gpu->GetTickEstimate();
|
||||
if (geTicks != 0) {
|
||||
if (CoreTiming::GetTicks() > geTicks + usToCycles(geBehindThresholdUs)) {
|
||||
u64 diff = CoreTiming::GetTicks() - geTicks;
|
||||
// Let the GPU thread catch up.
|
||||
gpu->SyncThread();
|
||||
CoreTiming::Advance();
|
||||
}
|
||||
}
|
||||
|
||||
// This may get out of step if we synced (because we don't correct for cyclesLate),
|
||||
// but that's okay - __GeCheckCycles is a very rough way to synchronize anyway.
|
||||
CoreTiming::ScheduleEvent(usToCycles(geIntervalUs), geCycleEvent, 0);
|
||||
// Deprecated
|
||||
}
|
||||
|
||||
void __GeInit() {
|
||||
@@ -217,15 +201,12 @@ void __GeInit() {
|
||||
|
||||
geSyncEvent = CoreTiming::RegisterEvent("GeSyncEvent", &__GeExecuteSync);
|
||||
geInterruptEvent = CoreTiming::RegisterEvent("GeInterruptEvent", &__GeExecuteInterrupt);
|
||||
|
||||
// Deprecated
|
||||
geCycleEvent = CoreTiming::RegisterEvent("GeCycleEvent", &__GeCheckCycles);
|
||||
|
||||
listWaitingThreads.clear();
|
||||
drawWaitingThreads.clear();
|
||||
|
||||
// When we're using separate CPU/GPU threads, we need to keep them in sync.
|
||||
if (IsOnSeparateCPUThread()) {
|
||||
CoreTiming::ScheduleEvent(usToCycles(geIntervalUs), geCycleEvent, 0);
|
||||
}
|
||||
}
|
||||
|
||||
struct GeInterruptData_v1 {
|
||||
@@ -270,20 +251,18 @@ void __GeDoState(PointerWrap &p) {
|
||||
void __GeShutdown() {
|
||||
}
|
||||
|
||||
// Warning: may be called from the GPU thread, if there is a separate one (multithread mode).
|
||||
bool __GeTriggerSync(GPUSyncType type, int id, u64 atTicks) {
|
||||
u64 userdata = (u64)id << 32 | (u64)type;
|
||||
s64 future = atTicks - CoreTiming::GetTicks();
|
||||
if (type == GPU_SYNC_DRAW) {
|
||||
s64 left = CoreTiming::UnscheduleThreadsafeEvent(geSyncEvent, userdata);
|
||||
s64 left = CoreTiming::UnscheduleEvent(geSyncEvent, userdata);
|
||||
if (left > future)
|
||||
future = left;
|
||||
}
|
||||
CoreTiming::ScheduleEvent_Threadsafe(future, geSyncEvent, userdata);
|
||||
CoreTiming::ScheduleEvent(future, geSyncEvent, userdata);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Warning: may be called from the GPU thread, if there is a separate one (multithread mode).
|
||||
bool __GeTriggerInterrupt(int listid, u32 pc, u64 atTicks) {
|
||||
GeInterruptData intrdata;
|
||||
intrdata.listid = listid;
|
||||
@@ -293,7 +272,7 @@ bool __GeTriggerInterrupt(int listid, u32 pc, u64 atTicks) {
|
||||
ge_pending_cb.push_back(intrdata);
|
||||
|
||||
u64 userdata = (u64)listid << 32 | (u64) pc;
|
||||
CoreTiming::ScheduleEvent_Threadsafe(atTicks - CoreTiming::GetTicks(), geInterruptEvent, userdata);
|
||||
CoreTiming::ScheduleEvent(atTicks - CoreTiming::GetTicks(), geInterruptEvent, userdata);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -504,7 +483,6 @@ static int sceGeUnsetCallback(u32 cbID) {
|
||||
// unless some insane game pokes it and relies on it...
|
||||
u32 sceGeSaveContext(u32 ctxAddr) {
|
||||
DEBUG_LOG(SCEGE, "sceGeSaveContext(%08x)", ctxAddr);
|
||||
gpu->SyncThread();
|
||||
|
||||
if (gpu->BusyDrawing()) {
|
||||
WARN_LOG(SCEGE, "sceGeSaveContext(%08x): lists in process, aborting", ctxAddr);
|
||||
@@ -524,7 +502,6 @@ u32 sceGeSaveContext(u32 ctxAddr) {
|
||||
|
||||
u32 sceGeRestoreContext(u32 ctxAddr) {
|
||||
DEBUG_LOG(SCEGE, "sceGeRestoreContext(%08x)", ctxAddr);
|
||||
gpu->SyncThread();
|
||||
|
||||
if (gpu->BusyDrawing()) {
|
||||
WARN_LOG(SCEGE, "sceGeRestoreContext(%08x): lists in process, aborting", ctxAddr);
|
||||
|
||||
@@ -46,8 +46,7 @@ typedef struct PspUsbCamSetupVideoParam {
|
||||
int evlevel;
|
||||
} PspUsbCamSetupVideoParam;
|
||||
|
||||
|
||||
static unsigned char sceUsbCamDummyImage[] = {
|
||||
static const unsigned char sceUsbCamDummyImage[] = {
|
||||
0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x01, 0x00, 0x60,
|
||||
0x00, 0x60, 0x00, 0x00, 0xFF, 0xE1, 0x00, 0x68, 0x45, 0x78, 0x69, 0x66, 0x00, 0x00, 0x4D, 0x4D,
|
||||
0x00, 0x2A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x01, 0x1A, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01,
|
||||
|
||||
@@ -129,6 +129,8 @@ namespace MIPSComp {
|
||||
}
|
||||
}
|
||||
|
||||
DISABLE;
|
||||
|
||||
u32 iaddr = gpr.IsImm(rs) ? offset + gpr.GetImm(rs) : 0xFFFFFFFF;
|
||||
std::vector<FixupBranch> skips;
|
||||
|
||||
|
||||
+21
-36
@@ -328,7 +328,6 @@ void CPU_RunLoop() {
|
||||
switch (cpuThreadState) {
|
||||
case CPU_THREAD_EXECUTE:
|
||||
mipsr4k.RunLoopUntil(cpuThreadUntil);
|
||||
gpu->FinishEventLoop();
|
||||
CPU_NextState(CPU_THREAD_EXECUTE, CPU_THREAD_RUNNING);
|
||||
break;
|
||||
|
||||
@@ -354,12 +353,6 @@ void CPU_RunLoop() {
|
||||
coreState = CORE_POWERDOWN;
|
||||
}
|
||||
|
||||
// Let's make sure the gpu has already cleaned up before we start freeing memory.
|
||||
if (gpu) {
|
||||
gpu->FinishEventLoop();
|
||||
gpu->SyncThread(true);
|
||||
}
|
||||
|
||||
CPU_Shutdown();
|
||||
CPU_SetState(CPU_THREAD_NOT_RUNNING);
|
||||
}
|
||||
@@ -371,9 +364,9 @@ void Core_UpdateState(CoreState newState) {
|
||||
Core_UpdateSingleStep();
|
||||
}
|
||||
|
||||
static void Core_UpdateDebugStats(bool flag) {
|
||||
if (coreCollectDebugStats != flag) {
|
||||
coreCollectDebugStats = flag;
|
||||
void Core_UpdateDebugStats(bool collectStats) {
|
||||
if (coreCollectDebugStats != collectStats) {
|
||||
coreCollectDebugStats = collectStats;
|
||||
mipsr4k.ClearJitCache();
|
||||
}
|
||||
|
||||
@@ -384,18 +377,15 @@ static void Core_UpdateDebugStats(bool flag) {
|
||||
void System_Wake() {
|
||||
// Ping the threads so they check coreState.
|
||||
CPU_NextStateNot(CPU_THREAD_NOT_RUNNING, CPU_THREAD_SHUTDOWN);
|
||||
if (gpu) {
|
||||
gpu->FinishEventLoop();
|
||||
}
|
||||
}
|
||||
|
||||
// Ugly!
|
||||
static bool pspIsInited = false;
|
||||
static bool pspIsIniting = false;
|
||||
static bool pspIsQuiting = false;
|
||||
static bool pspIsQuitting = false;
|
||||
|
||||
bool PSP_InitStart(const CoreParameter &coreParam, std::string *error_string) {
|
||||
if (pspIsIniting || pspIsQuiting) {
|
||||
if (pspIsIniting || pspIsQuitting) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -415,7 +405,9 @@ bool PSP_InitStart(const CoreParameter &coreParam, std::string *error_string) {
|
||||
coreParameter.errorString = "";
|
||||
pspIsIniting = true;
|
||||
|
||||
if (g_Config.bSeparateCPUThread) {
|
||||
// Keeping this around because we might need it in the future.
|
||||
const bool separateCPUThread = false;
|
||||
if (separateCPUThread) {
|
||||
Core_ListenShutdown(System_Wake);
|
||||
CPU_SetState(CPU_THREAD_PENDING);
|
||||
cpuThread = new std::thread(&CPU_RunLoop);
|
||||
@@ -438,7 +430,7 @@ bool PSP_InitUpdate(std::string *error_string) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (g_Config.bSeparateCPUThread && !CPU_IsReady()) {
|
||||
if (!CPU_IsReady()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -459,7 +451,8 @@ bool PSP_InitUpdate(std::string *error_string) {
|
||||
bool PSP_Init(const CoreParameter &coreParam, std::string *error_string) {
|
||||
PSP_InitStart(coreParam, error_string);
|
||||
|
||||
if (g_Config.bSeparateCPUThread) {
|
||||
// For a potential resurrection of separate CPU thread later.
|
||||
if (false) {
|
||||
CPU_WaitStatus(cpuThreadReplyCond, &CPU_IsReady);
|
||||
}
|
||||
|
||||
@@ -472,12 +465,12 @@ bool PSP_IsIniting() {
|
||||
}
|
||||
|
||||
bool PSP_IsInited() {
|
||||
return pspIsInited && !pspIsQuiting;
|
||||
return pspIsInited && !pspIsQuitting;
|
||||
}
|
||||
|
||||
void PSP_Shutdown() {
|
||||
// Do nothing if we never inited.
|
||||
if (!pspIsInited && !pspIsIniting && !pspIsQuiting) {
|
||||
if (!pspIsInited && !pspIsIniting && !pspIsQuitting) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -488,7 +481,7 @@ void PSP_Shutdown() {
|
||||
#endif
|
||||
|
||||
// Make sure things know right away that PSP memory, etc. is going away.
|
||||
pspIsQuiting = true;
|
||||
pspIsQuitting = true;
|
||||
if (coreState == CORE_RUNNING)
|
||||
Core_UpdateState(CORE_ERROR);
|
||||
Core_NotifyShutdown();
|
||||
@@ -507,7 +500,7 @@ void PSP_Shutdown() {
|
||||
currentMIPS = 0;
|
||||
pspIsInited = false;
|
||||
pspIsIniting = false;
|
||||
pspIsQuiting = false;
|
||||
pspIsQuitting = false;
|
||||
g_Config.unloadGameConfig();
|
||||
}
|
||||
|
||||
@@ -525,15 +518,14 @@ void PSP_EndHostFrame() {
|
||||
}
|
||||
|
||||
void PSP_RunLoopUntil(u64 globalticks) {
|
||||
Core_UpdateDebugStats(g_Config.bShowDebugStats || g_Config.bLogFrameDrops);
|
||||
|
||||
SaveState::Process();
|
||||
if (coreState == CORE_POWERDOWN || coreState == CORE_ERROR) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Switch the CPU thread on or off, as the case may be.
|
||||
bool useCPUThread = g_Config.bSeparateCPUThread;
|
||||
// We no longer allow a separate CPU thread but if we add a render queue
|
||||
// to GL we're gonna need it.
|
||||
bool useCPUThread = false;
|
||||
if (useCPUThread && cpuThread == nullptr) {
|
||||
// Need to start the cpu thread.
|
||||
Core_ListenShutdown(System_Wake);
|
||||
@@ -541,9 +533,8 @@ void PSP_RunLoopUntil(u64 globalticks) {
|
||||
cpuThread = new std::thread(&CPU_RunLoop);
|
||||
cpuThreadID = cpuThread->get_id();
|
||||
cpuThread->detach();
|
||||
if (gpu) {
|
||||
gpu->SetThreadEnabled(true);
|
||||
}
|
||||
// Probably needs to tell the gpu that it will need to queue up its output
|
||||
// on another thread.
|
||||
CPU_WaitStatus(cpuThreadReplyCond, &CPU_IsReady);
|
||||
} else if (!useCPUThread && cpuThread != nullptr) {
|
||||
CPU_SetState(CPU_THREAD_QUIT);
|
||||
@@ -551,21 +542,15 @@ void PSP_RunLoopUntil(u64 globalticks) {
|
||||
delete cpuThread;
|
||||
cpuThread = nullptr;
|
||||
cpuThreadID = std::thread::id();
|
||||
if (gpu) {
|
||||
gpu->SetThreadEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (cpuThread != nullptr) {
|
||||
// Tell the gpu a new frame is about to begin, before we start the CPU.
|
||||
gpu->SyncBeginFrame();
|
||||
|
||||
cpuThreadUntil = globalticks;
|
||||
if (CPU_NextState(CPU_THREAD_RUNNING, CPU_THREAD_EXECUTE)) {
|
||||
// The CPU doesn't actually respect cpuThreadUntil well, especially when skipping frames.
|
||||
// TODO: Something smarter? Or force CPU to bail periodically?
|
||||
while (!CPU_IsReady()) {
|
||||
gpu->RunEventsUntil(CoreTiming::GetTicks() + msToCycles(1000));
|
||||
// Have the GPU do stuff here.
|
||||
if (coreState != CORE_RUNNING) {
|
||||
CPU_WaitStatus(cpuThreadReplyCond, &CPU_IsReady);
|
||||
}
|
||||
|
||||
@@ -73,6 +73,9 @@ void PSP_EndHostFrame();
|
||||
void PSP_RunLoopUntil(u64 globalticks);
|
||||
void PSP_RunLoopFor(int cycles);
|
||||
|
||||
// Call before PSP_BeginHostFrame() in order to not miss any GPU stats.
|
||||
void Core_UpdateDebugStats(bool collectStats);
|
||||
|
||||
void Audio_Init();
|
||||
|
||||
bool IsOnSeparateCPUThread();
|
||||
|
||||
@@ -1932,6 +1932,7 @@ bool FramebufferManagerCommon::GetFramebuffer(u32 fb_address, int fb_stride, GEB
|
||||
bool flipY = (g_Config.iGPUBackend == GPU_BACKEND_OPENGL && !useBufferedRendering_) ? true : false;
|
||||
buffer.Allocate(w, h, GE_FORMAT_8888, flipY, true);
|
||||
bool retval = draw_->CopyFramebufferToMemorySync(bound, Draw::FB_COLOR_BIT, 0, 0, w, h, Draw::DataFormat::R8G8B8A8_UNORM, buffer.GetData(), w);
|
||||
gpuStats.numReadbacks++;
|
||||
// Vulkan requires us to re-apply all dynamic state for each command buffer, and the above will cause us to start a new cmdbuf.
|
||||
// So let's dirty the things that are involved in Vulkan dynamic state. Readbacks are not frequent so this won't hurt other backends.
|
||||
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE);
|
||||
@@ -2034,6 +2035,7 @@ void FramebufferManagerCommon::PackFramebufferSync_(VirtualFramebuffer *vfb, int
|
||||
DEBUG_LOG(G3D, "Reading framebuffer to mem, fb_address = %08x", fb_address);
|
||||
|
||||
draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_COLOR_BIT, x, y, w, h, destFormat, destPtr, vfb->fb_stride);
|
||||
gpuStats.numReadbacks++;
|
||||
}
|
||||
|
||||
void FramebufferManagerCommon::ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync, int x, int y, int w, int h) {
|
||||
@@ -2084,7 +2086,7 @@ void FramebufferManagerCommon::DownloadFramebufferForClut(u32 fb_address, u32 lo
|
||||
FlushBeforeCopy();
|
||||
|
||||
// No need to download if we already have it.
|
||||
if (!vfb->memoryUpdated && vfb->clutUpdatedBytes < loadBytes) {
|
||||
if (w > 0 && h > 0 && !vfb->memoryUpdated && vfb->clutUpdatedBytes < loadBytes) {
|
||||
// We intentionally don't call OptimizeDownloadRange() here - we don't want to over download.
|
||||
// CLUT framebuffers are often incorrectly estimated in size.
|
||||
if (x == 0 && y == 0 && w == vfb->width && h == vfb->height) {
|
||||
|
||||
@@ -400,6 +400,7 @@ void SoftwareTransform(
|
||||
// rectangle out of many. Quite a small optimization though.
|
||||
// Experiment: Disable on PowerVR (see issue #6290)
|
||||
// TODO: This bleeds outside the play area in non-buffered mode. Big deal? Probably not.
|
||||
// TODO: Allow creating a depth clear and a color draw.
|
||||
bool reallyAClear = false;
|
||||
if (maxIndex > 1 && prim == GE_PRIM_RECTANGLES && gstate.isModeClear()) {
|
||||
int scissorX2 = gstate.getScissorX2() + 1;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <d3d11.h>
|
||||
#include <d3d11_1.h>
|
||||
|
||||
@@ -190,7 +191,8 @@ private:
|
||||
PushBufferD3D11 *pushVerts_;
|
||||
PushBufferD3D11 *pushInds_;
|
||||
|
||||
// D3D11 state object caches
|
||||
// D3D11 state object caches.
|
||||
// TODO: Change them to DenseHashMaps.
|
||||
std::map<uint64_t, ID3D11BlendState *> blendCache_;
|
||||
std::map<uint64_t, ID3D11BlendState1 *> blendCache1_;
|
||||
std::map<uint64_t, ID3D11DepthStencilState *> depthStencilCache_;
|
||||
|
||||
+9
-21
@@ -286,7 +286,7 @@ void GPU_D3D11::DeviceRestore() {
|
||||
// Nothing needed.
|
||||
}
|
||||
|
||||
void GPU_D3D11::InitClearInternal() {
|
||||
void GPU_D3D11::InitClear() {
|
||||
bool useNonBufferedRendering = g_Config.iRenderingMode == FB_NON_BUFFERED_MODE;
|
||||
if (useNonBufferedRendering) {
|
||||
// device_->Clear(0, NULL, D3DCLEAR_STENCIL | D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.f, 0);
|
||||
@@ -305,8 +305,8 @@ void GPU_D3D11::BeginHostFrame() {
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_D3D11::ReapplyGfxStateInternal() {
|
||||
GPUCommon::ReapplyGfxStateInternal();
|
||||
void GPU_D3D11::ReapplyGfxState() {
|
||||
GPUCommon::ReapplyGfxState();
|
||||
|
||||
// TODO: Dirty our caches for depth states etc
|
||||
}
|
||||
@@ -316,8 +316,8 @@ void GPU_D3D11::EndHostFrame() {
|
||||
draw_->BindPipeline(nullptr);
|
||||
}
|
||||
|
||||
void GPU_D3D11::BeginFrameInternal() {
|
||||
GPUCommon::BeginFrameInternal();
|
||||
void GPU_D3D11::BeginFrame() {
|
||||
GPUCommon::BeginFrame();
|
||||
|
||||
textureCacheD3D11_->StartFrame();
|
||||
drawEngine_.BeginFrame();
|
||||
@@ -338,13 +338,6 @@ void GPU_D3D11::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat f
|
||||
}
|
||||
|
||||
bool GPU_D3D11::FramebufferDirty() {
|
||||
// FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause.
|
||||
if (ThreadEnabled()) {
|
||||
// FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause.
|
||||
ScheduleEvent(GPU_EVENT_PROCESS_QUEUE);
|
||||
// Allow it to process fully before deciding if it's dirty.
|
||||
SyncThread();
|
||||
}
|
||||
VirtualFramebuffer *vfb = framebufferManager_->GetDisplayVFB();
|
||||
if (vfb) {
|
||||
bool dirty = vfb->dirtyAfterDisplay;
|
||||
@@ -353,15 +346,8 @@ bool GPU_D3D11::FramebufferDirty() {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool GPU_D3D11::FramebufferReallyDirty() {
|
||||
// FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause.
|
||||
if (ThreadEnabled()) {
|
||||
// FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause.
|
||||
ScheduleEvent(GPU_EVENT_PROCESS_QUEUE);
|
||||
// Allow it to process fully before deciding if it's dirty.
|
||||
SyncThread();
|
||||
}
|
||||
|
||||
bool GPU_D3D11::FramebufferReallyDirty() {
|
||||
VirtualFramebuffer *vfb = framebufferManager_->GetDisplayVFB();
|
||||
if (vfb) {
|
||||
bool dirty = vfb->reallyDirtyAfterDisplay;
|
||||
@@ -371,7 +357,7 @@ bool GPU_D3D11::FramebufferReallyDirty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void GPU_D3D11::CopyDisplayToOutputInternal() {
|
||||
void GPU_D3D11::CopyDisplayToOutput() {
|
||||
float blendColor[4]{};
|
||||
context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0xF], blendColor, 0xFFFFFFFF);
|
||||
|
||||
@@ -727,6 +713,7 @@ void GPU_D3D11::GetStats(char *buffer, size_t bufsize) {
|
||||
"Cached, Uncached Vertices Drawn: %i, %i\n"
|
||||
"FBOs active: %i\n"
|
||||
"Textures active: %i, decoded: %i invalidated: %i\n"
|
||||
"Readbacks: %d\n"
|
||||
"Vertex, Fragment shaders loaded: %i, %i\n",
|
||||
gpuStats.msProcessingDisplayLists * 1000.0f,
|
||||
gpuStats.numDrawCalls,
|
||||
@@ -743,6 +730,7 @@ void GPU_D3D11::GetStats(char *buffer, size_t bufsize) {
|
||||
(int)textureCacheD3D11_->NumLoadedTextures(),
|
||||
gpuStats.numTexturesDecoded,
|
||||
gpuStats.numTextureInvalidations,
|
||||
gpuStats.numReadbacks,
|
||||
shaderManagerD3D11_->GetNumVertexShaders(),
|
||||
shaderManagerD3D11_->GetNumFragmentShaders()
|
||||
);
|
||||
|
||||
@@ -40,7 +40,7 @@ public:
|
||||
void PreExecuteOp(u32 op, u32 diff) override;
|
||||
void ExecuteOp(u32 op, u32 diff) override;
|
||||
|
||||
void ReapplyGfxStateInternal() override;
|
||||
void ReapplyGfxState() override;
|
||||
void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) override;
|
||||
void GetStats(char *buffer, size_t bufsize) override;
|
||||
void ClearCacheNextFrame() override;
|
||||
@@ -96,9 +96,9 @@ private:
|
||||
void CheckFlushOp(int cmd, u32 diff);
|
||||
void BuildReportingInfo();
|
||||
|
||||
void InitClearInternal() override;
|
||||
void BeginFrameInternal() override;
|
||||
void CopyDisplayToOutputInternal() override;
|
||||
void InitClear() override;
|
||||
void BeginFrame() override;
|
||||
void CopyDisplayToOutput() override;
|
||||
|
||||
ID3D11Device *device_;
|
||||
ID3D11DeviceContext *context_;
|
||||
|
||||
@@ -203,7 +203,6 @@ void TextureCacheD3D11::SetFramebufferSamplingParams(u16 bufferWidth, u16 buffer
|
||||
bool sClamp;
|
||||
bool tClamp;
|
||||
float lodBias;
|
||||
bool autoMip;
|
||||
GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0);
|
||||
|
||||
key.minFilt = minFilt & 1;
|
||||
|
||||
@@ -251,7 +251,7 @@ void GPU_DX9::DeviceRestore() {
|
||||
// Nothing needed.
|
||||
}
|
||||
|
||||
void GPU_DX9::InitClearInternal() {
|
||||
void GPU_DX9::InitClear() {
|
||||
bool useNonBufferedRendering = g_Config.iRenderingMode == FB_NON_BUFFERED_MODE;
|
||||
if (useNonBufferedRendering) {
|
||||
dxstate.depthWrite.set(true);
|
||||
@@ -272,12 +272,12 @@ void GPU_DX9::BeginHostFrame() {
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_DX9::ReapplyGfxStateInternal() {
|
||||
void GPU_DX9::ReapplyGfxState() {
|
||||
dxstate.Restore();
|
||||
GPUCommon::ReapplyGfxStateInternal();
|
||||
GPUCommon::ReapplyGfxState();
|
||||
}
|
||||
|
||||
void GPU_DX9::BeginFrameInternal() {
|
||||
void GPU_DX9::BeginFrame() {
|
||||
// Turn off vsync when unthrottled
|
||||
int desiredVSyncInterval = g_Config.bVSync ? 1 : 0;
|
||||
if ((PSP_CoreParameter().unthrottle) || (PSP_CoreParameter().fpsLimit == 1))
|
||||
@@ -292,7 +292,7 @@ void GPU_DX9::BeginFrameInternal() {
|
||||
depalShaderCache_.Decimate();
|
||||
// fragmentTestCache_.Decimate();
|
||||
|
||||
GPUCommon::BeginFrameInternal();
|
||||
GPUCommon::BeginFrame();
|
||||
shaderManagerDX9_->DirtyShader();
|
||||
|
||||
framebufferManager_->BeginFrame();
|
||||
@@ -304,13 +304,6 @@ void GPU_DX9::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat for
|
||||
}
|
||||
|
||||
bool GPU_DX9::FramebufferDirty() {
|
||||
// FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause.
|
||||
if (ThreadEnabled()) {
|
||||
// FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause.
|
||||
ScheduleEvent(GPU_EVENT_PROCESS_QUEUE);
|
||||
// Allow it to process fully before deciding if it's dirty.
|
||||
SyncThread();
|
||||
}
|
||||
VirtualFramebuffer *vfb = framebufferManager_->GetDisplayVFB();
|
||||
if (vfb) {
|
||||
bool dirty = vfb->dirtyAfterDisplay;
|
||||
@@ -319,15 +312,8 @@ bool GPU_DX9::FramebufferDirty() {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool GPU_DX9::FramebufferReallyDirty() {
|
||||
// FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause.
|
||||
if (ThreadEnabled()) {
|
||||
// FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause.
|
||||
ScheduleEvent(GPU_EVENT_PROCESS_QUEUE);
|
||||
// Allow it to process fully before deciding if it's dirty.
|
||||
SyncThread();
|
||||
}
|
||||
|
||||
bool GPU_DX9::FramebufferReallyDirty() {
|
||||
VirtualFramebuffer *vfb = framebufferManager_->GetDisplayVFB();
|
||||
if (vfb) {
|
||||
bool dirty = vfb->reallyDirtyAfterDisplay;
|
||||
@@ -337,7 +323,7 @@ bool GPU_DX9::FramebufferReallyDirty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void GPU_DX9::CopyDisplayToOutputInternal() {
|
||||
void GPU_DX9::CopyDisplayToOutput() {
|
||||
dxstate.depthWrite.set(true);
|
||||
dxstate.colorMask.set(true, true, true, true);
|
||||
|
||||
@@ -659,6 +645,7 @@ void GPU_DX9::GetStats(char *buffer, size_t bufsize) {
|
||||
"Cached, Uncached Vertices Drawn: %i, %i\n"
|
||||
"FBOs active: %i\n"
|
||||
"Textures active: %i, decoded: %i invalidated: %i\n"
|
||||
"Readbacks: %d\n"
|
||||
"Vertex, Fragment shaders loaded: %i, %i\n",
|
||||
gpuStats.msProcessingDisplayLists * 1000.0f,
|
||||
gpuStats.numDrawCalls,
|
||||
@@ -675,6 +662,7 @@ void GPU_DX9::GetStats(char *buffer, size_t bufsize) {
|
||||
(int)textureCacheDX9_->NumLoadedTextures(),
|
||||
gpuStats.numTexturesDecoded,
|
||||
gpuStats.numTextureInvalidations,
|
||||
gpuStats.numReadbacks,
|
||||
shaderManagerDX9_->GetNumVertexShaders(),
|
||||
shaderManagerDX9_->GetNumFragmentShaders()
|
||||
);
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
void PreExecuteOp(u32 op, u32 diff) override;
|
||||
void ExecuteOp(u32 op, u32 diff) override;
|
||||
|
||||
void ReapplyGfxStateInternal() override;
|
||||
void ReapplyGfxState() override;
|
||||
void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) override;
|
||||
void GetStats(char *buffer, size_t bufsize) override;
|
||||
void ClearCacheNextFrame() override;
|
||||
@@ -96,9 +96,9 @@ private:
|
||||
void CheckFlushOp(int cmd, u32 diff);
|
||||
void BuildReportingInfo();
|
||||
|
||||
void InitClearInternal() override;
|
||||
void BeginFrameInternal() override;
|
||||
void CopyDisplayToOutputInternal() override;
|
||||
void InitClear() override;
|
||||
void BeginFrame() override;
|
||||
void CopyDisplayToOutput() override;
|
||||
|
||||
LPDIRECT3DDEVICE9 device_;
|
||||
LPDIRECT3DDEVICE9EX deviceEx_;
|
||||
|
||||
+10
-17
@@ -401,13 +401,14 @@ void GPU_GLES::DeviceRestore() {
|
||||
UpdateVsyncInterval(true);
|
||||
}
|
||||
|
||||
void GPU_GLES::ReinitializeInternal() {
|
||||
void GPU_GLES::Reinitialize() {
|
||||
GPUCommon::Reinitialize();
|
||||
textureCacheGL_->Clear(true);
|
||||
depalShaderCache_.Clear();
|
||||
framebufferManagerGL_->DestroyAllFBOs();
|
||||
}
|
||||
|
||||
void GPU_GLES::InitClearInternal() {
|
||||
void GPU_GLES::InitClear() {
|
||||
bool useNonBufferedRendering = g_Config.iRenderingMode == FB_NON_BUFFERED_MODE;
|
||||
if (useNonBufferedRendering) {
|
||||
glstate.depthWrite.set(GL_TRUE);
|
||||
@@ -467,13 +468,13 @@ void GPU_GLES::UpdateCmdInfo() {
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_GLES::ReapplyGfxStateInternal() {
|
||||
void GPU_GLES::ReapplyGfxState() {
|
||||
drawEngine_.RestoreVAO();
|
||||
glstate.Restore();
|
||||
GPUCommon::ReapplyGfxStateInternal();
|
||||
GPUCommon::ReapplyGfxState();
|
||||
}
|
||||
|
||||
void GPU_GLES::BeginFrameInternal() {
|
||||
void GPU_GLES::BeginFrame() {
|
||||
UpdateVsyncInterval(resized_);
|
||||
resized_ = false;
|
||||
|
||||
@@ -483,7 +484,7 @@ void GPU_GLES::BeginFrameInternal() {
|
||||
depalShaderCache_.Decimate();
|
||||
fragmentTestCache_.Decimate();
|
||||
|
||||
GPUCommon::BeginFrameInternal();
|
||||
GPUCommon::BeginFrame();
|
||||
|
||||
// Save the cache from time to time. TODO: How often?
|
||||
if (!shaderCachePath_.empty() && (gpuStats.numFlips & 1023) == 0) {
|
||||
@@ -504,11 +505,6 @@ void GPU_GLES::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat fo
|
||||
}
|
||||
|
||||
bool GPU_GLES::FramebufferDirty() {
|
||||
if (ThreadEnabled()) {
|
||||
// Allow it to process fully before deciding if it's dirty.
|
||||
SyncThread();
|
||||
}
|
||||
|
||||
VirtualFramebuffer *vfb = framebufferManagerGL_->GetDisplayVFB();
|
||||
if (vfb) {
|
||||
bool dirty = vfb->dirtyAfterDisplay;
|
||||
@@ -519,11 +515,6 @@ bool GPU_GLES::FramebufferDirty() {
|
||||
}
|
||||
|
||||
bool GPU_GLES::FramebufferReallyDirty() {
|
||||
if (ThreadEnabled()) {
|
||||
// Allow it to process fully before deciding if it's dirty.
|
||||
SyncThread();
|
||||
}
|
||||
|
||||
VirtualFramebuffer *vfb = framebufferManagerGL_->GetDisplayVFB();
|
||||
if (vfb) {
|
||||
bool dirty = vfb->reallyDirtyAfterDisplay;
|
||||
@@ -533,7 +524,7 @@ bool GPU_GLES::FramebufferReallyDirty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void GPU_GLES::CopyDisplayToOutputInternal() {
|
||||
void GPU_GLES::CopyDisplayToOutput() {
|
||||
// Flush anything left over.
|
||||
framebufferManagerGL_->RebindFramebuffer();
|
||||
drawEngine_.Flush();
|
||||
@@ -893,6 +884,7 @@ void GPU_GLES::GetStats(char *buffer, size_t bufsize) {
|
||||
"Cached, Uncached Vertices Drawn: %i, %i\n"
|
||||
"FBOs active: %i\n"
|
||||
"Textures active: %i, decoded: %i invalidated: %i\n"
|
||||
"Readbacks: %d\n"
|
||||
"Vertex, Fragment, Programs loaded: %i, %i, %i\n",
|
||||
gpuStats.msProcessingDisplayLists * 1000.0f,
|
||||
gpuStats.numDrawCalls,
|
||||
@@ -909,6 +901,7 @@ void GPU_GLES::GetStats(char *buffer, size_t bufsize) {
|
||||
(int)textureCacheGL_->NumLoadedTextures(),
|
||||
gpuStats.numTexturesDecoded,
|
||||
gpuStats.numTextureInvalidations,
|
||||
gpuStats.numReadbacks,
|
||||
shaderManagerGL_->GetNumVertexShaders(),
|
||||
shaderManagerGL_->GetNumFragmentShaders(),
|
||||
shaderManagerGL_->GetNumPrograms());
|
||||
|
||||
+5
-5
@@ -41,7 +41,7 @@ public:
|
||||
void PreExecuteOp(u32 op, u32 diff) override;
|
||||
void ExecuteOp(u32 op, u32 diff) override;
|
||||
|
||||
void ReapplyGfxStateInternal() override;
|
||||
void ReapplyGfxState() override;
|
||||
void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) override;
|
||||
void GetStats(char *buffer, size_t bufsize) override;
|
||||
|
||||
@@ -95,10 +95,10 @@ private:
|
||||
void CheckFlushOp(int cmd, u32 diff);
|
||||
void BuildReportingInfo();
|
||||
|
||||
void InitClearInternal() override;
|
||||
void BeginFrameInternal() override;
|
||||
void CopyDisplayToOutputInternal() override;
|
||||
void ReinitializeInternal() override;
|
||||
void InitClear() override;
|
||||
void BeginFrame() override;
|
||||
void CopyDisplayToOutput() override;
|
||||
void Reinitialize() override;
|
||||
|
||||
inline void UpdateVsyncInterval(bool force);
|
||||
void UpdateCmdInfo();
|
||||
|
||||
@@ -67,6 +67,7 @@ struct GPUStatistics {
|
||||
numShaderSwitches = 0;
|
||||
numFlushes = 0;
|
||||
numTexturesDecoded = 0;
|
||||
numReadbacks = 0;
|
||||
msProcessingDisplayLists = 0;
|
||||
vertexGPUCycles = 0;
|
||||
otherGPUCycles = 0;
|
||||
@@ -85,6 +86,7 @@ struct GPUStatistics {
|
||||
int numTextureSwitches;
|
||||
int numShaderSwitches;
|
||||
int numTexturesDecoded;
|
||||
int numReadbacks;
|
||||
double msProcessingDisplayLists;
|
||||
int vertexGPUCycles;
|
||||
int otherGPUCycles;
|
||||
|
||||
+16
-199
@@ -359,11 +359,9 @@ GPUCommon::GPUCommon(GraphicsContext *gfxCtx, Draw::DrawContext *draw) :
|
||||
// The compiler was not rounding the struct size up to an 8 byte boundary, which
|
||||
// you'd expect due to the int64 field, but the Linux ABI apparently does not require that.
|
||||
static_assert(sizeof(DisplayList) == 456, "Bad DisplayList size");
|
||||
listLock.set_enabled(g_Config.bSeparateCPUThread);
|
||||
|
||||
Reinitialize();
|
||||
SetupColorConv();
|
||||
SetThreadEnabled(g_Config.bSeparateCPUThread);
|
||||
gstate.Reset();
|
||||
gstate_c.Reset();
|
||||
gpuStats.Reset();
|
||||
@@ -383,16 +381,7 @@ void GPUCommon::EndHostFrame() {
|
||||
|
||||
}
|
||||
|
||||
void GPUCommon::InitClear() {
|
||||
ScheduleEvent(GPU_EVENT_INIT_CLEAR);
|
||||
}
|
||||
|
||||
void GPUCommon::CopyDisplayToOutput() {
|
||||
ScheduleEvent(GPU_EVENT_COPY_DISPLAY_TO_OUTPUT);
|
||||
}
|
||||
|
||||
void GPUCommon::Reinitialize() {
|
||||
easy_guard guard(listLock);
|
||||
memset(dls, 0, sizeof(dls));
|
||||
for (int i = 0; i < DisplayListMaxCount; ++i) {
|
||||
dls[i].state = PSP_GE_DL_STATE_NONE;
|
||||
@@ -400,14 +389,12 @@ void GPUCommon::Reinitialize() {
|
||||
}
|
||||
|
||||
nextListID = 0;
|
||||
currentList = NULL;
|
||||
currentList = nullptr;
|
||||
isbreak = false;
|
||||
drawCompleteTicks = 0;
|
||||
busyTicks = 0;
|
||||
timeSpentStepping_ = 0.0;
|
||||
interruptsEnabled_ = true;
|
||||
UpdateTickEstimate(0);
|
||||
ScheduleEvent(GPU_EVENT_REINITIALIZE);
|
||||
}
|
||||
|
||||
int GPUCommon::EstimatePerVertexCost() {
|
||||
@@ -440,7 +427,6 @@ int GPUCommon::EstimatePerVertexCost() {
|
||||
}
|
||||
|
||||
void GPUCommon::PopDLQueue() {
|
||||
easy_guard guard(listLock);
|
||||
if(!dlQueue.empty()) {
|
||||
dlQueue.pop_front();
|
||||
if(!dlQueue.empty()) {
|
||||
@@ -449,7 +435,7 @@ void GPUCommon::PopDLQueue() {
|
||||
if (running)
|
||||
currentList->state = PSP_GE_DL_STATE_RUNNING;
|
||||
} else {
|
||||
currentList = NULL;
|
||||
currentList = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -457,7 +443,6 @@ void GPUCommon::PopDLQueue() {
|
||||
bool GPUCommon::BusyDrawing() {
|
||||
u32 state = DrawSync(1);
|
||||
if (state == PSP_GE_LIST_DRAWING || state == PSP_GE_LIST_STALLING) {
|
||||
easy_guard guard(listLock);
|
||||
if (currentList && currentList->state != PSP_GE_DL_STATE_PAUSED) {
|
||||
return true;
|
||||
}
|
||||
@@ -474,12 +459,6 @@ void GPUCommon::DumpNextFrame() {
|
||||
}
|
||||
|
||||
u32 GPUCommon::DrawSync(int mode) {
|
||||
if (ThreadEnabled()) {
|
||||
// Sync first, because the CPU is usually faster than the emulated GPU.
|
||||
SyncThread();
|
||||
}
|
||||
|
||||
easy_guard guard(listLock);
|
||||
if (mode < 0 || mode > 1)
|
||||
return SCE_KERNEL_ERROR_INVALID_MODE;
|
||||
|
||||
@@ -521,7 +500,6 @@ u32 GPUCommon::DrawSync(int mode) {
|
||||
}
|
||||
|
||||
void GPUCommon::CheckDrawSync() {
|
||||
easy_guard guard(listLock);
|
||||
if (dlQueue.empty()) {
|
||||
for (int i = 0; i < DisplayListMaxCount; ++i)
|
||||
dls[i].state = PSP_GE_DL_STATE_NONE;
|
||||
@@ -529,12 +507,6 @@ void GPUCommon::CheckDrawSync() {
|
||||
}
|
||||
|
||||
int GPUCommon::ListSync(int listid, int mode) {
|
||||
if (ThreadEnabled()) {
|
||||
// Sync first, because the CPU is usually faster than the emulated GPU.
|
||||
SyncThread();
|
||||
}
|
||||
|
||||
easy_guard guard(listLock);
|
||||
if (listid < 0 || listid >= DisplayListMaxCount)
|
||||
return SCE_KERNEL_ERROR_INVALID_ID;
|
||||
|
||||
@@ -579,8 +551,7 @@ int GPUCommon::ListSync(int listid, int mode) {
|
||||
}
|
||||
|
||||
int GPUCommon::GetStack(int index, u32 stackPtr) {
|
||||
easy_guard guard(listLock);
|
||||
if (currentList == NULL) {
|
||||
if (!currentList) {
|
||||
// Seems like it doesn't return an error code?
|
||||
return 0;
|
||||
}
|
||||
@@ -605,7 +576,6 @@ int GPUCommon::GetStack(int index, u32 stackPtr) {
|
||||
}
|
||||
|
||||
u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, int subIntrBase, PSPPointer<PspGeListArgs> args, bool head) {
|
||||
easy_guard guard(listLock);
|
||||
// TODO Check the stack values in missing arg and ajust the stack depth
|
||||
|
||||
// Check alignment
|
||||
@@ -704,7 +674,6 @@ u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, int subIntrBase, PSPPointer<Ps
|
||||
drawCompleteTicks = (u64)-1;
|
||||
|
||||
// TODO save context when starting the list if param is set
|
||||
guard.unlock();
|
||||
ProcessDLQueue();
|
||||
}
|
||||
|
||||
@@ -712,7 +681,6 @@ u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, int subIntrBase, PSPPointer<Ps
|
||||
}
|
||||
|
||||
u32 GPUCommon::DequeueList(int listid) {
|
||||
easy_guard guard(listLock);
|
||||
if (listid < 0 || listid >= DisplayListMaxCount || dls[listid].state == PSP_GE_DL_STATE_NONE)
|
||||
return SCE_KERNEL_ERROR_INVALID_ID;
|
||||
|
||||
@@ -736,7 +704,6 @@ u32 GPUCommon::DequeueList(int listid) {
|
||||
}
|
||||
|
||||
u32 GPUCommon::UpdateStall(int listid, u32 newstall) {
|
||||
easy_guard guard(listLock);
|
||||
if (listid < 0 || listid >= DisplayListMaxCount || dls[listid].state == PSP_GE_DL_STATE_NONE)
|
||||
return SCE_KERNEL_ERROR_INVALID_ID;
|
||||
auto &dl = dls[listid];
|
||||
@@ -748,14 +715,12 @@ u32 GPUCommon::UpdateStall(int listid, u32 newstall) {
|
||||
if (dl.signal == PSP_GE_SIGNAL_HANDLER_PAUSE && PSP_CoreParameter().compat.flags().HackFixHangs)
|
||||
dl.signal = PSP_GE_SIGNAL_HANDLER_SUSPEND;
|
||||
|
||||
guard.unlock();
|
||||
ProcessDLQueue();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 GPUCommon::Continue() {
|
||||
easy_guard guard(listLock);
|
||||
if (!currentList)
|
||||
return 0;
|
||||
|
||||
@@ -791,13 +756,11 @@ u32 GPUCommon::Continue() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
guard.unlock();
|
||||
ProcessDLQueue();
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 GPUCommon::Break(int mode) {
|
||||
easy_guard guard(listLock);
|
||||
if (mode < 0 || mode > 1)
|
||||
return SCE_KERNEL_ERROR_INVALID_MODE;
|
||||
|
||||
@@ -886,8 +849,6 @@ bool GPUCommon::InterpretList(DisplayList &list) {
|
||||
start = time_now_d();
|
||||
}
|
||||
|
||||
easy_guard guard(listLock);
|
||||
|
||||
if (list.state == PSP_GE_DL_STATE_PAUSED)
|
||||
return false;
|
||||
currentList = &list;
|
||||
@@ -911,14 +872,12 @@ bool GPUCommon::InterpretList(DisplayList &list) {
|
||||
list.interrupted = false;
|
||||
|
||||
gpuState = list.pc == list.stall ? GPUSTATE_STALL : GPUSTATE_RUNNING;
|
||||
guard.unlock();
|
||||
|
||||
debugRecording_ = GPURecord::IsActive();
|
||||
const bool useDebugger = host->GPUDebuggingActive() || debugRecording_;
|
||||
const bool useFastRunLoop = !dumpThisFrame_ && !useDebugger;
|
||||
while (gpuState == GPUSTATE_RUNNING) {
|
||||
{
|
||||
easy_guard innerGuard(listLock);
|
||||
if (list.pc == list.stall) {
|
||||
gpuState = GPUSTATE_STALL;
|
||||
if (PSP_CoreParameter().compat.flags().FlushAtStall) {
|
||||
@@ -935,7 +894,6 @@ bool GPUCommon::InterpretList(DisplayList &list) {
|
||||
}
|
||||
|
||||
{
|
||||
easy_guard innerGuard(listLock);
|
||||
downcount = list.stall == 0 ? 0x0FFFFFFF : (list.stall - list.pc) / 4;
|
||||
|
||||
if (gpuState == GPUSTATE_STALL && list.stall != list.pc) {
|
||||
@@ -965,10 +923,6 @@ bool GPUCommon::InterpretList(DisplayList &list) {
|
||||
}
|
||||
|
||||
void GPUCommon::BeginFrame() {
|
||||
ScheduleEvent(GPU_EVENT_BEGIN_FRAME);
|
||||
}
|
||||
|
||||
void GPUCommon::BeginFrameInternal() {
|
||||
if (dumpNextFrame_) {
|
||||
NOTICE_LOG(G3D, "DUMPING THIS FRAME");
|
||||
dumpThisFrame_ = true;
|
||||
@@ -1032,14 +986,6 @@ void GPUCommon::UpdatePC(u32 currentPC, u32 newPC) {
|
||||
}
|
||||
|
||||
void GPUCommon::ReapplyGfxState() {
|
||||
if (IsOnSeparateCPUThread()) {
|
||||
ScheduleEvent(GPU_EVENT_REAPPLY_GFX_STATE);
|
||||
} else {
|
||||
ReapplyGfxStateInternal();
|
||||
}
|
||||
}
|
||||
|
||||
void GPUCommon::ReapplyGfxStateInternal() {
|
||||
// The commands are embedded in the command memory so we can just reexecute the words. Convenient.
|
||||
// To be safe we pass 0xFFFFFFFF as the diff.
|
||||
|
||||
@@ -1070,55 +1016,7 @@ inline void GPUCommon::UpdateState(GPURunState state) {
|
||||
downcount = 0;
|
||||
}
|
||||
|
||||
void GPUCommon::ProcessEvent(GPUEvent ev) {
|
||||
switch (ev.type) {
|
||||
case GPU_EVENT_PROCESS_QUEUE:
|
||||
ProcessDLQueueInternal();
|
||||
break;
|
||||
|
||||
case GPU_EVENT_REAPPLY_GFX_STATE:
|
||||
ReapplyGfxStateInternal();
|
||||
break;
|
||||
|
||||
case GPU_EVENT_INIT_CLEAR:
|
||||
InitClearInternal();
|
||||
break;
|
||||
|
||||
case GPU_EVENT_BEGIN_FRAME:
|
||||
BeginFrameInternal();
|
||||
break;
|
||||
|
||||
case GPU_EVENT_COPY_DISPLAY_TO_OUTPUT:
|
||||
CopyDisplayToOutputInternal();
|
||||
break;
|
||||
|
||||
case GPU_EVENT_INVALIDATE_CACHE:
|
||||
InvalidateCacheInternal(ev.invalidate_cache.addr, ev.invalidate_cache.size, ev.invalidate_cache.type);
|
||||
break;
|
||||
|
||||
case GPU_EVENT_FB_MEMCPY:
|
||||
PerformMemoryCopyInternal(ev.fb_memcpy.dst, ev.fb_memcpy.src, ev.fb_memcpy.size);
|
||||
break;
|
||||
|
||||
case GPU_EVENT_FB_MEMSET:
|
||||
PerformMemorySetInternal(ev.fb_memset.dst, ev.fb_memset.v, ev.fb_memset.size);
|
||||
break;
|
||||
|
||||
case GPU_EVENT_FB_STENCIL_UPLOAD:
|
||||
PerformStencilUploadInternal(ev.fb_stencil_upload.dst, ev.fb_stencil_upload.size);
|
||||
break;
|
||||
|
||||
case GPU_EVENT_REINITIALIZE:
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG_REPORT(G3D, "Unexpected GPU event type: %d", (int)ev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int GPUCommon::GetNextListIndex() {
|
||||
easy_guard guard(listLock);
|
||||
auto iter = dlQueue.begin();
|
||||
if (iter != dlQueue.end()) {
|
||||
return *iter;
|
||||
@@ -1127,15 +1025,9 @@ int GPUCommon::GetNextListIndex() {
|
||||
}
|
||||
}
|
||||
|
||||
bool GPUCommon::ProcessDLQueue() {
|
||||
ScheduleEvent(GPU_EVENT_PROCESS_QUEUE);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GPUCommon::ProcessDLQueueInternal() {
|
||||
void GPUCommon::ProcessDLQueue() {
|
||||
startingTicks = CoreTiming::GetTicks();
|
||||
cyclesExecuted = 0;
|
||||
UpdateTickEstimate(std::max(busyTicks, startingTicks + cyclesExecuted));
|
||||
|
||||
// Seems to be correct behaviour to process the list anyway?
|
||||
if (startingTicks < busyTicks) {
|
||||
@@ -1149,25 +1041,20 @@ void GPUCommon::ProcessDLQueueInternal() {
|
||||
if (!InterpretList(l)) {
|
||||
return;
|
||||
} else {
|
||||
easy_guard guard(listLock);
|
||||
|
||||
// Some other list could've taken the spot while we dilly-dallied around.
|
||||
if (l.state != PSP_GE_DL_STATE_QUEUED) {
|
||||
// At the end, we can remove it from the queue and continue.
|
||||
dlQueue.erase(std::remove(dlQueue.begin(), dlQueue.end(), listIndex), dlQueue.end());
|
||||
}
|
||||
UpdateTickEstimate(std::max(busyTicks, startingTicks + cyclesExecuted));
|
||||
}
|
||||
}
|
||||
|
||||
easy_guard guard(listLock);
|
||||
currentList = NULL;
|
||||
currentList = nullptr;
|
||||
|
||||
drawCompleteTicks = startingTicks + cyclesExecuted;
|
||||
busyTicks = std::max(busyTicks, drawCompleteTicks);
|
||||
__GeTriggerSync(GPU_SYNC_DRAW, 1, drawCompleteTicks);
|
||||
// Since the event is in CoreTiming, we're in sync. Just set 0 now.
|
||||
UpdateTickEstimate(0);
|
||||
}
|
||||
|
||||
void GPUCommon::PreExecuteOp(u32 op, u32 diff) {
|
||||
@@ -1187,12 +1074,10 @@ void GPUCommon::Execute_Iaddr(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPUCommon::Execute_Origin(u32 op, u32 diff) {
|
||||
easy_guard guard(listLock);
|
||||
gstate_c.offsetAddr = currentList->pc;
|
||||
}
|
||||
|
||||
void GPUCommon::Execute_Jump(u32 op, u32 diff) {
|
||||
easy_guard guard(listLock);
|
||||
const u32 target = gstate_c.getRelativeAddress(op & 0x00FFFFFC);
|
||||
#ifdef _DEBUG
|
||||
if (!Memory::IsValidAddress(target)) {
|
||||
@@ -1207,7 +1092,6 @@ void GPUCommon::Execute_Jump(u32 op, u32 diff) {
|
||||
void GPUCommon::Execute_BJump(u32 op, u32 diff) {
|
||||
if (!currentList->bboxResult) {
|
||||
// bounding box jump.
|
||||
easy_guard guard(listLock);
|
||||
const u32 target = gstate_c.getRelativeAddress(op & 0x00FFFFFC);
|
||||
if (Memory::IsValidAddress(target)) {
|
||||
UpdatePC(currentList->pc, target - 4);
|
||||
@@ -1220,7 +1104,6 @@ void GPUCommon::Execute_BJump(u32 op, u32 diff) {
|
||||
|
||||
void GPUCommon::Execute_Call(u32 op, u32 diff) {
|
||||
PROFILE_THIS_SCOPE("gpu_call");
|
||||
easy_guard guard(listLock);
|
||||
|
||||
// Saint Seiya needs correct support for relative calls.
|
||||
const u32 retval = currentList->pc + 4;
|
||||
@@ -1259,7 +1142,6 @@ void GPUCommon::Execute_Call(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
void GPUCommon::Execute_Ret(u32 op, u32 diff) {
|
||||
easy_guard guard(listLock);
|
||||
if (currentList->stackptr == 0) {
|
||||
DEBUG_LOG_REPORT(G3D, "RET: Stack empty!");
|
||||
} else {
|
||||
@@ -1281,7 +1163,6 @@ void GPUCommon::Execute_Ret(u32 op, u32 diff) {
|
||||
void GPUCommon::Execute_End(u32 op, u32 diff) {
|
||||
Flush();
|
||||
|
||||
easy_guard guard(listLock);
|
||||
const u32 prev = Memory::ReadUnchecked_U32(currentList->pc - 4);
|
||||
UpdatePC(currentList->pc, currentList->pc);
|
||||
// Count in a few extra cycles on END.
|
||||
@@ -1425,7 +1306,7 @@ void GPUCommon::Execute_End(u32 op, u32 diff) {
|
||||
__GeTriggerSync(GPU_SYNC_LIST, currentList->id, currentList->waitTicks);
|
||||
if (currentList->started && currentList->context.IsValid()) {
|
||||
gstate.Restore(currentList->context);
|
||||
ReapplyGfxStateInternal();
|
||||
ReapplyGfxState();
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1606,7 +1487,6 @@ void GPUCommon::Execute_WorldMtxNum(u32 op, u32 diff) {
|
||||
gstate.worldmtxnum = (GE_CMD_WORLDMATRIXNUMBER << 24) | ((op + count) & 0xF);
|
||||
|
||||
// Skip over the loaded data, it's done now.
|
||||
easy_guard innerGuard(listLock);
|
||||
UpdatePC(currentList->pc, currentList->pc + count * 4);
|
||||
currentList->pc += count * 4;
|
||||
}
|
||||
@@ -1654,7 +1534,6 @@ void GPUCommon::Execute_ViewMtxNum(u32 op, u32 diff) {
|
||||
gstate.viewmtxnum = (GE_CMD_VIEWMATRIXNUMBER << 24) | ((op + count) & 0xF);
|
||||
|
||||
// Skip over the loaded data, it's done now.
|
||||
easy_guard innerGuard(listLock);
|
||||
UpdatePC(currentList->pc, currentList->pc + count * 4);
|
||||
currentList->pc += count * 4;
|
||||
}
|
||||
@@ -1702,7 +1581,6 @@ void GPUCommon::Execute_ProjMtxNum(u32 op, u32 diff) {
|
||||
gstate.projmtxnum = (GE_CMD_PROJMATRIXNUMBER << 24) | ((op + count) & 0x1F);
|
||||
|
||||
// Skip over the loaded data, it's done now.
|
||||
easy_guard innerGuard(listLock);
|
||||
UpdatePC(currentList->pc, currentList->pc + count * 4);
|
||||
currentList->pc += count * 4;
|
||||
}
|
||||
@@ -1751,7 +1629,6 @@ void GPUCommon::Execute_TgenMtxNum(u32 op, u32 diff) {
|
||||
gstate.texmtxnum = (GE_CMD_TGENMATRIXNUMBER << 24) | ((op + count) & 0xF);
|
||||
|
||||
// Skip over the loaded data, it's done now.
|
||||
easy_guard innerGuard(listLock);
|
||||
UpdatePC(currentList->pc, currentList->pc + count * 4);
|
||||
currentList->pc += count * 4;
|
||||
}
|
||||
@@ -1818,7 +1695,6 @@ void GPUCommon::Execute_BoneMtxNum(u32 op, u32 diff) {
|
||||
gstate.boneMatrixNumber = (GE_CMD_BONEMATRIXNUMBER << 24) | ((op + count) & 0x7F);
|
||||
|
||||
// Skip over the loaded data, it's done now.
|
||||
easy_guard innerGuard(listLock);
|
||||
UpdatePC(currentList->pc, currentList->pc + count * 4);
|
||||
currentList->pc += count * 4;
|
||||
}
|
||||
@@ -2034,8 +1910,6 @@ struct DisplayList_v2 {
|
||||
};
|
||||
|
||||
void GPUCommon::DoState(PointerWrap &p) {
|
||||
easy_guard guard(listLock);
|
||||
|
||||
auto s = p.Section("GPUCommon", 1, 4);
|
||||
if (!s)
|
||||
return;
|
||||
@@ -2114,7 +1988,6 @@ void GPUCommon::InterruptStart(int listid) {
|
||||
interruptRunning = true;
|
||||
}
|
||||
void GPUCommon::InterruptEnd(int listid) {
|
||||
easy_guard guard(listLock);
|
||||
interruptRunning = false;
|
||||
isbreak = false;
|
||||
|
||||
@@ -2130,13 +2003,11 @@ void GPUCommon::InterruptEnd(int listid) {
|
||||
__GeTriggerWait(GPU_SYNC_LIST, listid);
|
||||
}
|
||||
|
||||
guard.unlock();
|
||||
ProcessDLQueue();
|
||||
}
|
||||
|
||||
// TODO: Maybe cleaner to keep this in GE and trigger the clear directly?
|
||||
void GPUCommon::SyncEnd(GPUSyncType waitType, int listid, bool wokeThreads) {
|
||||
easy_guard guard(listLock);
|
||||
if (waitType == GPU_SYNC_DRAW && wokeThreads)
|
||||
{
|
||||
for (int i = 0; i < DisplayListMaxCount; ++i) {
|
||||
@@ -2148,7 +2019,6 @@ void GPUCommon::SyncEnd(GPUSyncType waitType, int listid, bool wokeThreads) {
|
||||
}
|
||||
|
||||
bool GPUCommon::GetCurrentDisplayList(DisplayList &list) {
|
||||
easy_guard guard(listLock);
|
||||
if (!currentList) {
|
||||
return false;
|
||||
}
|
||||
@@ -2159,7 +2029,6 @@ bool GPUCommon::GetCurrentDisplayList(DisplayList &list) {
|
||||
std::vector<DisplayList> GPUCommon::ActiveDisplayLists() {
|
||||
std::vector<DisplayList> result;
|
||||
|
||||
easy_guard guard(listLock);
|
||||
for (auto it = dlQueue.begin(), end = dlQueue.end(); it != end; ++it) {
|
||||
result.push_back(dls[*it]);
|
||||
}
|
||||
@@ -2173,7 +2042,6 @@ void GPUCommon::ResetListPC(int listID, u32 pc) {
|
||||
return;
|
||||
}
|
||||
|
||||
easy_guard guard(listLock);
|
||||
dls[listID].pc = pc;
|
||||
}
|
||||
|
||||
@@ -2183,7 +2051,6 @@ void GPUCommon::ResetListStall(int listID, u32 stall) {
|
||||
return;
|
||||
}
|
||||
|
||||
easy_guard guard(listLock);
|
||||
dls[listID].stall = stall;
|
||||
}
|
||||
|
||||
@@ -2193,7 +2060,6 @@ void GPUCommon::ResetListState(int listID, DisplayListState state) {
|
||||
return;
|
||||
}
|
||||
|
||||
easy_guard guard(listLock);
|
||||
dls[listID].state = state;
|
||||
}
|
||||
|
||||
@@ -2345,38 +2211,17 @@ void GPUCommon::DoBlockTransfer(u32 skipDrawReason) {
|
||||
cyclesExecuted += ((height * width * bpp) * 16) / 10;
|
||||
}
|
||||
|
||||
void GPUCommon::PerformMemoryCopyInternal(u32 dest, u32 src, int size) {
|
||||
if (!framebufferManager_->NotifyFramebufferCopy(src, dest, size, false, gstate_c.skipDrawReason)) {
|
||||
// We use a little hack for Download/Upload using a VRAM mirror.
|
||||
// Since they're identical we don't need to copy.
|
||||
if (!Memory::IsVRAMAddress(dest) || (dest ^ 0x00400000) != src) {
|
||||
Memory::Memcpy(dest, src, size);
|
||||
}
|
||||
}
|
||||
InvalidateCache(dest, size, GPU_INVALIDATE_HINT);
|
||||
}
|
||||
|
||||
void GPUCommon::PerformMemorySetInternal(u32 dest, u8 v, int size) {
|
||||
if (!framebufferManager_->NotifyFramebufferCopy(dest, dest, size, true, gstate_c.skipDrawReason)) {
|
||||
InvalidateCache(dest, size, GPU_INVALIDATE_HINT);
|
||||
}
|
||||
}
|
||||
|
||||
bool GPUCommon::PerformMemoryCopy(u32 dest, u32 src, int size) {
|
||||
// Track stray copies of a framebuffer in RAM. MotoGP does this.
|
||||
if (framebufferManager_->MayIntersectFramebuffer(src) || framebufferManager_->MayIntersectFramebuffer(dest)) {
|
||||
if (IsOnSeparateCPUThread()) {
|
||||
GPUEvent ev(GPU_EVENT_FB_MEMCPY);
|
||||
ev.fb_memcpy.dst = dest;
|
||||
ev.fb_memcpy.src = src;
|
||||
ev.fb_memcpy.size = size;
|
||||
ScheduleEvent(ev);
|
||||
|
||||
// This is a memcpy, so we need to wait for it to complete.
|
||||
SyncThread();
|
||||
} else {
|
||||
PerformMemoryCopyInternal(dest, src, size);
|
||||
if (!framebufferManager_->NotifyFramebufferCopy(src, dest, size, false, gstate_c.skipDrawReason)) {
|
||||
// We use a little hack for Download/Upload using a VRAM mirror.
|
||||
// Since they're identical we don't need to copy.
|
||||
if (!Memory::IsVRAMAddress(dest) || (dest ^ 0x00400000) != src) {
|
||||
Memory::Memcpy(dest, src, size);
|
||||
}
|
||||
}
|
||||
InvalidateCache(dest, size, GPU_INVALIDATE_HINT);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2389,17 +2234,8 @@ bool GPUCommon::PerformMemorySet(u32 dest, u8 v, int size) {
|
||||
// This may indicate a memset, usually to 0, of a framebuffer.
|
||||
if (framebufferManager_->MayIntersectFramebuffer(dest)) {
|
||||
Memory::Memset(dest, v, size);
|
||||
|
||||
if (IsOnSeparateCPUThread()) {
|
||||
GPUEvent ev(GPU_EVENT_FB_MEMSET);
|
||||
ev.fb_memset.dst = dest;
|
||||
ev.fb_memset.v = v;
|
||||
ev.fb_memset.size = size;
|
||||
ScheduleEvent(ev);
|
||||
|
||||
// We don't need to wait for the framebuffer to be updated.
|
||||
} else {
|
||||
PerformMemorySetInternal(dest, v, size);
|
||||
if (!framebufferManager_->NotifyFramebufferCopy(dest, dest, size, true, gstate_c.skipDrawReason)) {
|
||||
InvalidateCache(dest, size, GPU_INVALIDATE_HINT);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -2430,14 +2266,6 @@ bool GPUCommon::PerformMemoryUpload(u32 dest, int size) {
|
||||
}
|
||||
|
||||
void GPUCommon::InvalidateCache(u32 addr, int size, GPUInvalidationType type) {
|
||||
GPUEvent ev(GPU_EVENT_INVALIDATE_CACHE);
|
||||
ev.invalidate_cache.addr = addr;
|
||||
ev.invalidate_cache.size = size;
|
||||
ev.invalidate_cache.type = type;
|
||||
ScheduleEvent(ev);
|
||||
}
|
||||
|
||||
void GPUCommon::InvalidateCacheInternal(u32 addr, int size, GPUInvalidationType type) {
|
||||
if (size > 0)
|
||||
textureCache_->Invalidate(addr, size, type);
|
||||
else
|
||||
@@ -2462,23 +2290,12 @@ void GPUCommon::NotifyVideoUpload(u32 addr, int size, int width, int format) {
|
||||
|
||||
bool GPUCommon::PerformStencilUpload(u32 dest, int size) {
|
||||
if (framebufferManager_->MayIntersectFramebuffer(dest)) {
|
||||
if (IsOnSeparateCPUThread()) {
|
||||
GPUEvent ev(GPU_EVENT_FB_STENCIL_UPLOAD);
|
||||
ev.fb_stencil_upload.dst = dest;
|
||||
ev.fb_stencil_upload.size = size;
|
||||
ScheduleEvent(ev);
|
||||
} else {
|
||||
PerformStencilUploadInternal(dest, size);
|
||||
}
|
||||
framebufferManager_->NotifyStencilUpload(dest, size);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GPUCommon::PerformStencilUploadInternal(u32 dest, int size) {
|
||||
framebufferManager_->NotifyStencilUpload(dest, size);
|
||||
}
|
||||
|
||||
bool GPUCommon::GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes) {
|
||||
u32 fb_address = type == GPU_DBG_FRAMEBUF_RENDER ? gstate.getFrameBufRawAddress() : framebufferManager_->DisplayFramebufAddr();
|
||||
int fb_stride = type == GPU_DBG_FRAMEBUF_RENDER ? gstate.FrameBufStride() : framebufferManager_->DisplayFramebufStride();
|
||||
|
||||
+7
-115
@@ -2,7 +2,6 @@
|
||||
|
||||
#include "Common/Common.h"
|
||||
#include "Common/MemoryUtil.h"
|
||||
#include "Core/ThreadEventQueue.h"
|
||||
#include "GPU/GPUInterface.h"
|
||||
#include "GPU/GPUState.h"
|
||||
#include "GPU/Common/GPUDebugInterface.h"
|
||||
@@ -15,8 +14,6 @@
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
typedef ThreadEventQueue<GPUInterface, GPUEvent, GPUEventType, GPU_EVENT_INVALID, GPU_EVENT_SYNC_THREAD, GPU_EVENT_FINISH_EVENT_LOOP> GPUThreadEventQueue;
|
||||
|
||||
class FramebufferManagerCommon;
|
||||
class TextureCacheCommon;
|
||||
class DrawEngineCommon;
|
||||
@@ -42,7 +39,7 @@ enum {
|
||||
FLAG_DIRTYONCHANGE = 64, // NOTE: Either this or FLAG_EXECUTE*, not both!
|
||||
};
|
||||
|
||||
class GPUCommon : public GPUThreadEventQueue, public GPUDebugInterface {
|
||||
class GPUCommon : public GPUInterface, public GPUDebugInterface {
|
||||
public:
|
||||
GPUCommon(GraphicsContext *gfxCtx, Draw::DrawContext *draw);
|
||||
virtual ~GPUCommon();
|
||||
@@ -69,7 +66,7 @@ public:
|
||||
void PreExecuteOp(u32 op, u32 diff) override;
|
||||
|
||||
bool InterpretList(DisplayList &list) override;
|
||||
virtual bool ProcessDLQueue();
|
||||
void ProcessDLQueue();
|
||||
u32 UpdateStall(int listid, u32 newstall) override;
|
||||
u32 EnqueueList(u32 listpc, u32 stall, int subIntrBase, PSPPointer<PspGeListArgs> args, bool head) override;
|
||||
u32 DequeueList(int listid) override;
|
||||
@@ -77,21 +74,13 @@ public:
|
||||
u32 DrawSync(int mode) override;
|
||||
int GetStack(int index, u32 stackPtr) override;
|
||||
void DoState(PointerWrap &p) override;
|
||||
bool FramebufferDirty() override {
|
||||
SyncThread();
|
||||
return true;
|
||||
}
|
||||
bool FramebufferReallyDirty() override {
|
||||
SyncThread();
|
||||
return true;
|
||||
}
|
||||
bool BusyDrawing() override;
|
||||
u32 Continue() override;
|
||||
u32 Break(int mode) override;
|
||||
void ReapplyGfxState() override;
|
||||
|
||||
void CopyDisplayToOutput() override;
|
||||
void InitClear() override;
|
||||
void CopyDisplayToOutput() override = 0;
|
||||
void InitClear() override = 0;
|
||||
bool PerformMemoryCopy(u32 dest, u32 src, int size) override;
|
||||
bool PerformMemorySet(u32 dest, u8 v, int size) override;
|
||||
bool PerformMemoryDownload(u32 dest, int size) override;
|
||||
@@ -116,10 +105,6 @@ public:
|
||||
void Execute_BoundingBox(u32 op, u32 diff);
|
||||
void Execute_BlockTransferStart(u32 op, u32 diff);
|
||||
|
||||
void Execute_TexScaleU(u32 op, u32 diff);
|
||||
void Execute_TexScaleV(u32 op, u32 diff);
|
||||
void Execute_TexOffsetU(u32 op, u32 diff);
|
||||
void Execute_TexOffsetV(u32 op, u32 diff);
|
||||
void Execute_TexLevel(u32 op, u32 diff);
|
||||
|
||||
void Execute_WorldMtxNum(u32 op, u32 diff);
|
||||
@@ -142,20 +127,6 @@ public:
|
||||
// Note: Not virtual!
|
||||
inline void Flush();
|
||||
|
||||
u64 GetTickEstimate() override {
|
||||
#if defined(_M_X64) || defined(__ANDROID__)
|
||||
return curTickEst_;
|
||||
#elif defined(_M_SSE)
|
||||
__m64 result = *(__m64 *)&curTickEst_;
|
||||
u64 safeResult = *(u64 *)&result;
|
||||
_mm_empty();
|
||||
return safeResult;
|
||||
#else
|
||||
std::lock_guard<std::mutex> guard(curTickEstLock_);
|
||||
return curTickEst_;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_CRT_DBG
|
||||
#undef new
|
||||
#endif
|
||||
@@ -254,11 +225,7 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void InitClearInternal() {}
|
||||
void BeginFrame() override;
|
||||
virtual void BeginFrameInternal();
|
||||
virtual void CopyDisplayToOutputInternal() {}
|
||||
virtual void ReinitializeInternal() {}
|
||||
|
||||
// To avoid virtual calls to PreExecuteOp().
|
||||
virtual void FastRunLoop(DisplayList &list) = 0;
|
||||
@@ -268,15 +235,10 @@ protected:
|
||||
void PopDLQueue();
|
||||
void CheckDrawSync();
|
||||
int GetNextListIndex();
|
||||
void ProcessDLQueueInternal();
|
||||
virtual void ReapplyGfxStateInternal();
|
||||
virtual void FastLoadBoneMatrix(u32 target);
|
||||
void ProcessEvent(GPUEvent ev) override;
|
||||
bool ShouldExitEventLoop() override {
|
||||
return coreState != CORE_RUNNING;
|
||||
}
|
||||
virtual void FinishDeferred() {
|
||||
}
|
||||
|
||||
// TODO: Unify this.
|
||||
virtual void FinishDeferred() {}
|
||||
|
||||
void DoBlockTransfer(u32 skipDrawReason);
|
||||
|
||||
@@ -289,53 +251,6 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
void PerformMemoryCopyInternal(u32 dest, u32 src, int size);
|
||||
void PerformMemorySetInternal(u32 dest, u8 v, int size);
|
||||
void PerformStencilUploadInternal(u32 dest, int size);
|
||||
void InvalidateCacheInternal(u32 addr, int size, GPUInvalidationType type);
|
||||
|
||||
// This mutex can be disabled, which is useful for single core mode.
|
||||
class optional_mutex {
|
||||
public:
|
||||
optional_mutex() : enabled_(true) {}
|
||||
void set_enabled(bool enabled) {
|
||||
enabled_ = enabled;
|
||||
}
|
||||
void lock() {
|
||||
if (enabled_)
|
||||
mutex_.lock();
|
||||
}
|
||||
void unlock() {
|
||||
if (enabled_)
|
||||
mutex_.unlock();
|
||||
}
|
||||
private:
|
||||
std::mutex mutex_;
|
||||
bool enabled_;
|
||||
};
|
||||
|
||||
|
||||
// Allows early unlocking with a guard. Do not double unlock.
|
||||
class easy_guard {
|
||||
public:
|
||||
easy_guard(optional_mutex &mtx) : mtx_(mtx), locked_(true) { mtx_.lock(); }
|
||||
~easy_guard() {
|
||||
if (locked_)
|
||||
mtx_.unlock();
|
||||
}
|
||||
void unlock() {
|
||||
if (locked_)
|
||||
mtx_.unlock();
|
||||
else
|
||||
Crash();
|
||||
locked_ = false;
|
||||
}
|
||||
|
||||
private:
|
||||
optional_mutex &mtx_;
|
||||
bool locked_;
|
||||
};
|
||||
|
||||
FramebufferManagerCommon *framebufferManager_;
|
||||
TextureCacheCommon *textureCache_;
|
||||
DrawEngineCommon *drawEngineCommon_;
|
||||
@@ -350,7 +265,6 @@ protected:
|
||||
DisplayList dls[DisplayListMaxCount];
|
||||
DisplayList *currentList;
|
||||
DisplayListQueue dlQueue;
|
||||
optional_mutex listLock;
|
||||
|
||||
bool interruptRunning;
|
||||
GPURunState gpuState;
|
||||
@@ -372,28 +286,6 @@ protected:
|
||||
GEPrimitiveType lastPrim_;
|
||||
|
||||
private:
|
||||
|
||||
// For CPU/GPU sync.
|
||||
#ifdef __ANDROID__
|
||||
alignas(16) std::atomic<u64> curTickEst_;
|
||||
#else
|
||||
alignas(16) volatile u64 curTickEst_;
|
||||
std::mutex curTickEstLock_;
|
||||
#endif
|
||||
|
||||
inline void UpdateTickEstimate(u64 value) {
|
||||
#if defined(_M_X64) || defined(__ANDROID__)
|
||||
curTickEst_ = value;
|
||||
#elif defined(_M_SSE)
|
||||
__m64 result = *(__m64 *)&value;
|
||||
*(__m64 *)&curTickEst_ = result;
|
||||
_mm_empty();
|
||||
#else
|
||||
std::lock_guard<std::mutex> guard(curTickEstLock_);
|
||||
curTickEst_ = value;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Debug stats.
|
||||
double timeSteppingStarted_;
|
||||
double timeSpentStepping_;
|
||||
|
||||
@@ -155,56 +155,6 @@ enum GPUInvalidationType {
|
||||
GPU_INVALIDATE_SAFE,
|
||||
};
|
||||
|
||||
enum GPUEventType {
|
||||
GPU_EVENT_INVALID,
|
||||
GPU_EVENT_PROCESS_QUEUE,
|
||||
GPU_EVENT_INIT_CLEAR,
|
||||
GPU_EVENT_BEGIN_FRAME,
|
||||
GPU_EVENT_COPY_DISPLAY_TO_OUTPUT,
|
||||
GPU_EVENT_REAPPLY_GFX_STATE,
|
||||
GPU_EVENT_INVALIDATE_CACHE,
|
||||
GPU_EVENT_FINISH_EVENT_LOOP,
|
||||
GPU_EVENT_SYNC_THREAD,
|
||||
GPU_EVENT_FB_MEMCPY,
|
||||
GPU_EVENT_FB_MEMSET,
|
||||
GPU_EVENT_FB_STENCIL_UPLOAD,
|
||||
GPU_EVENT_REINITIALIZE,
|
||||
};
|
||||
|
||||
struct GPUEvent {
|
||||
GPUEvent(GPUEventType t) : type(t) {}
|
||||
GPUEventType type;
|
||||
union {
|
||||
// GPU_EVENT_INVALIDATE_CACHE
|
||||
struct {
|
||||
u32 addr;
|
||||
int size;
|
||||
GPUInvalidationType type;
|
||||
} invalidate_cache;
|
||||
// GPU_EVENT_FB_MEMCPY
|
||||
struct {
|
||||
u32 dst;
|
||||
u32 src;
|
||||
int size;
|
||||
} fb_memcpy;
|
||||
// GPU_EVENT_FB_MEMSET
|
||||
struct {
|
||||
u32 dst;
|
||||
u8 v;
|
||||
int size;
|
||||
} fb_memset;
|
||||
// GPU_EVENT_FB_STENCIL_UPLOAD
|
||||
struct {
|
||||
u32 dst;
|
||||
int size;
|
||||
} fb_stencil_upload;
|
||||
};
|
||||
|
||||
operator GPUEventType() const {
|
||||
return type;
|
||||
}
|
||||
};
|
||||
|
||||
namespace Draw {
|
||||
class DrawContext;
|
||||
}
|
||||
@@ -225,10 +175,6 @@ public:
|
||||
virtual void BeginHostFrame() = 0;
|
||||
virtual void EndHostFrame() = 0;
|
||||
|
||||
// Events
|
||||
virtual void RunEventsUntil(u64 globalticks) = 0;
|
||||
virtual void FinishEventLoop() = 0;
|
||||
|
||||
// Draw queue management
|
||||
virtual DisplayList* getList(int listid) = 0;
|
||||
// TODO: Much of this should probably be shared between the different GPU implementations.
|
||||
@@ -277,9 +223,6 @@ public:
|
||||
virtual void DeviceLost() = 0;
|
||||
virtual void DeviceRestore() = 0;
|
||||
virtual void ReapplyGfxState() = 0;
|
||||
virtual void SyncThread(bool force = false) = 0;
|
||||
virtual void SyncBeginFrame() = 0;
|
||||
virtual u64 GetTickEstimate() = 0;
|
||||
virtual void DoState(PointerWrap &p) = 0;
|
||||
|
||||
// Called by the window system if the window size changed. This will be reflected in PSPCoreParam.pixel*.
|
||||
@@ -289,7 +232,6 @@ public:
|
||||
virtual bool FramebufferDirty() = 0;
|
||||
virtual bool FramebufferReallyDirty() = 0;
|
||||
virtual bool BusyDrawing() = 0;
|
||||
virtual void SetThreadEnabled(bool threadEnabled) = 0;
|
||||
|
||||
// If any jit is being used inside the GPU.
|
||||
virtual bool DescribeCodePtr(const u8 *ptr, std::string &name) = 0;
|
||||
|
||||
@@ -40,6 +40,7 @@ public:
|
||||
bool PerformMemoryUpload(u32 dest, int size) override;
|
||||
bool PerformStencilUpload(u32 dest, int size) override;
|
||||
void ClearCacheNextFrame() override {}
|
||||
bool FramebufferDirty() override { return true; }
|
||||
|
||||
void DeviceLost() override {}
|
||||
void DeviceRestore() override {}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "Core/HLE/sceGe.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/Reporting.h"
|
||||
#include "Core/Core.h"
|
||||
#include "profiler/profiler.h"
|
||||
#include "thin3d/thin3d.h"
|
||||
|
||||
@@ -280,13 +281,7 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) {
|
||||
draw_->BindIndexBuffer(nullptr, 0);
|
||||
}
|
||||
|
||||
void SoftGPU::CopyDisplayToOutput()
|
||||
{
|
||||
ScheduleEvent(GPU_EVENT_COPY_DISPLAY_TO_OUTPUT);
|
||||
}
|
||||
|
||||
void SoftGPU::CopyDisplayToOutputInternal()
|
||||
{
|
||||
void SoftGPU::CopyDisplayToOutput() {
|
||||
// The display always shows 480x272.
|
||||
CopyToCurrentFboFromDisplayRam(FB_WIDTH, FB_HEIGHT);
|
||||
framebufferDirty_ = false;
|
||||
@@ -301,17 +296,6 @@ void SoftGPU::CopyDisplayToOutputInternal()
|
||||
}
|
||||
}
|
||||
|
||||
void SoftGPU::ProcessEvent(GPUEvent ev) {
|
||||
switch (ev.type) {
|
||||
case GPU_EVENT_COPY_DISPLAY_TO_OUTPUT:
|
||||
CopyDisplayToOutputInternal();
|
||||
break;
|
||||
|
||||
default:
|
||||
GPUCommon::ProcessEvent(ev);
|
||||
}
|
||||
}
|
||||
|
||||
void SoftGPU::FastRunLoop(DisplayList &list) {
|
||||
PROFILE_THIS_SCOPE("soft_runloop");
|
||||
for (; downcount > 0; --downcount) {
|
||||
@@ -913,11 +897,6 @@ bool SoftGPU::PerformStencilUpload(u32 dest, int size)
|
||||
}
|
||||
|
||||
bool SoftGPU::FramebufferDirty() {
|
||||
if (g_Config.bSeparateCPUThread) {
|
||||
// Allow it to process fully before deciding if it's dirty.
|
||||
SyncThread();
|
||||
}
|
||||
|
||||
if (g_Config.iFrameSkip != 0) {
|
||||
bool dirty = framebufferDirty_;
|
||||
framebufferDirty_ = false;
|
||||
|
||||
@@ -94,12 +94,9 @@ public:
|
||||
|
||||
protected:
|
||||
void FastRunLoop(DisplayList &list) override;
|
||||
void ProcessEvent(GPUEvent ev) override;
|
||||
void CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight);
|
||||
|
||||
private:
|
||||
void CopyDisplayToOutputInternal() override;
|
||||
|
||||
bool framebufferDirty_;
|
||||
u32 displayFramebuf_;
|
||||
u32 displayStride_;
|
||||
|
||||
@@ -986,11 +986,11 @@ void DrawEngineVulkan::DoFlush() {
|
||||
Draw::NativeObject object = g_Config.iRenderingMode != 0 ? Draw::NativeObject::FRAMEBUFFER_RENDERPASS : Draw::NativeObject::BACKBUFFER_RENDERPASS;
|
||||
VkRenderPass renderPass = (VkRenderPass)draw_->GetNativeObject(object);
|
||||
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, dec_, vshader, fshader, false);
|
||||
renderManager->BindPipeline(pipeline->pipeline);
|
||||
if (!pipeline) {
|
||||
// Already logged, let's bail out.
|
||||
return;
|
||||
}
|
||||
renderManager->BindPipeline(pipeline->pipeline);
|
||||
if (pipeline != lastPipeline_) {
|
||||
if (lastPipeline_ && !lastPipeline_->useBlendConstant && pipeline->useBlendConstant) {
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE);
|
||||
|
||||
+10
-20
@@ -177,7 +177,9 @@ void GPU_Vulkan::CheckGPUFeatures() {
|
||||
features |= GPU_SUPPORTS_WIDE_LINES;
|
||||
}
|
||||
if (vulkan_->GetFeaturesEnabled().dualSrcBlend) {
|
||||
features |= GPU_SUPPORTS_DUALSOURCE_BLEND;
|
||||
// Work around for Intel driver bug. See issue #10074.
|
||||
if (vulkan_->GetPhysicalDeviceProperties().vendorID != VULKAN_VENDOR_INTEL)
|
||||
features |= GPU_SUPPORTS_DUALSOURCE_BLEND;
|
||||
}
|
||||
if (vulkan_->GetFeaturesEnabled().logicOp) {
|
||||
features |= GPU_SUPPORTS_LOGIC_OP;
|
||||
@@ -332,21 +334,17 @@ void GPU_Vulkan::BuildReportingInfo() {
|
||||
Reporting::UpdateConfig();
|
||||
}
|
||||
|
||||
void GPU_Vulkan::ReinitializeInternal() {
|
||||
void GPU_Vulkan::Reinitialize() {
|
||||
GPUCommon::Reinitialize();
|
||||
textureCacheVulkan_->Clear(true);
|
||||
depalShaderCache_.Clear();
|
||||
framebufferManagerVulkan_->DestroyAllFBOs();
|
||||
}
|
||||
|
||||
void GPU_Vulkan::InitClearInternal() {
|
||||
void GPU_Vulkan::InitClear() {
|
||||
bool useNonBufferedRendering = g_Config.iRenderingMode == FB_NON_BUFFERED_MODE;
|
||||
if (useNonBufferedRendering) {
|
||||
/*
|
||||
glstate.depthWrite.set(GL_TRUE);
|
||||
glstate.colorMask.set(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
*/
|
||||
// TODO?
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,11 +368,6 @@ void GPU_Vulkan::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat
|
||||
}
|
||||
|
||||
bool GPU_Vulkan::FramebufferDirty() {
|
||||
if (ThreadEnabled()) {
|
||||
// Allow it to process fully before deciding if it's dirty.
|
||||
SyncThread();
|
||||
}
|
||||
|
||||
VirtualFramebuffer *vfb = framebufferManager_->GetDisplayVFB();
|
||||
if (vfb) {
|
||||
bool dirty = vfb->dirtyAfterDisplay;
|
||||
@@ -385,11 +378,6 @@ bool GPU_Vulkan::FramebufferDirty() {
|
||||
}
|
||||
|
||||
bool GPU_Vulkan::FramebufferReallyDirty() {
|
||||
if (ThreadEnabled()) {
|
||||
// Allow it to process fully before deciding if it's dirty.
|
||||
SyncThread();
|
||||
}
|
||||
|
||||
VirtualFramebuffer *vfb = framebufferManager_->GetDisplayVFB();
|
||||
if (vfb) {
|
||||
bool dirty = vfb->reallyDirtyAfterDisplay;
|
||||
@@ -399,7 +387,7 @@ bool GPU_Vulkan::FramebufferReallyDirty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void GPU_Vulkan::CopyDisplayToOutputInternal() {
|
||||
void GPU_Vulkan::CopyDisplayToOutput() {
|
||||
// Flush anything left over.
|
||||
drawEngine_.Flush();
|
||||
|
||||
@@ -847,6 +835,7 @@ void GPU_Vulkan::GetStats(char *buffer, size_t bufsize) {
|
||||
"Cached, Uncached Vertices Drawn: %i, %i\n"
|
||||
"FBOs active: %i\n"
|
||||
"Textures active: %i, decoded: %i invalidated: %i\n"
|
||||
"Readbacks: %d\n"
|
||||
"Vertex, Fragment, Pipelines loaded: %i, %i, %i\n"
|
||||
"Pushbuffer space used: UBO %d, Vtx %d, Idx %d\n",
|
||||
gpuStats.msProcessingDisplayLists * 1000.0f,
|
||||
@@ -864,6 +853,7 @@ void GPU_Vulkan::GetStats(char *buffer, size_t bufsize) {
|
||||
(int)textureCacheVulkan_->NumLoadedTextures(),
|
||||
gpuStats.numTexturesDecoded,
|
||||
gpuStats.numTextureInvalidations,
|
||||
gpuStats.numReadbacks,
|
||||
shaderManagerVulkan_->GetNumVertexShaders(),
|
||||
shaderManagerVulkan_->GetNumFragmentShaders(),
|
||||
pipelineManager_->GetNumPipelines(),
|
||||
|
||||
@@ -96,9 +96,9 @@ private:
|
||||
}
|
||||
void CheckFlushOp(int cmd, u32 diff);
|
||||
void BuildReportingInfo();
|
||||
void InitClearInternal() override;
|
||||
void CopyDisplayToOutputInternal() override;
|
||||
void ReinitializeInternal() override;
|
||||
void InitClear() override;
|
||||
void CopyDisplayToOutput() override;
|
||||
void Reinitialize() override;
|
||||
inline void UpdateVsyncInterval(bool force);
|
||||
void UpdateCmdInfo();
|
||||
|
||||
|
||||
@@ -281,7 +281,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
|
||||
VkPipeline pipeline;
|
||||
VkResult result = vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipe, nullptr, &pipeline);
|
||||
if (result != VK_SUCCESS) {
|
||||
ERROR_LOG(G3D, "Failed creating graphics pipeline!");
|
||||
ERROR_LOG(G3D, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -321,6 +321,7 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VkPipelineLayout layo
|
||||
VulkanPipeline *pipeline = CreateVulkanPipeline(
|
||||
vulkan_->GetDevice(), pipelineCache_, layout, renderPass,
|
||||
rasterKey, vtxDec, vs, fs, useHwTransform);
|
||||
// Even if the result is nullptr, insert it so we don't try to create it repeatedly.
|
||||
pipelines_.Insert(key, pipeline);
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
@@ -155,6 +155,7 @@ UI::EventReturn CwCheatScreen::OnEnableAll(UI::EventParams ¶ms) {
|
||||
}
|
||||
fs.close();
|
||||
|
||||
g_Config.bReloadCheats = true;
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
|
||||
+10
-8
@@ -1014,10 +1014,13 @@ void EmuScreen::postRender() {
|
||||
void EmuScreen::render() {
|
||||
using namespace Draw;
|
||||
|
||||
DrawContext *thin3d = screenManager()->getDrawContext();
|
||||
|
||||
if (invalid_) {
|
||||
// It's possible this might be set outside PSP_RunLoopFor().
|
||||
// In this case, we need to double check it here.
|
||||
checkPowerDown();
|
||||
thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1032,6 +1035,8 @@ void EmuScreen::render() {
|
||||
}
|
||||
}
|
||||
|
||||
Core_UpdateDebugStats(g_Config.bShowDebugStats || g_Config.bLogFrameDrops);
|
||||
|
||||
PSP_BeginHostFrame();
|
||||
|
||||
// We just run the CPU until we get to vblank. This will quickly sync up pretty nicely.
|
||||
@@ -1047,22 +1052,19 @@ void EmuScreen::render() {
|
||||
if (coreState == CORE_NEXTFRAME) {
|
||||
// set back to running for the next frame
|
||||
coreState = CORE_RUNNING;
|
||||
} else {
|
||||
// Didn't actually reach the end of the frame, ran out of the blockTicks cycles.
|
||||
// In this case we need to bind and wipe the backbuffer, at least.
|
||||
// It's possible we never ended up outputted anything - make sure we have the backbuffer cleared
|
||||
thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR });
|
||||
}
|
||||
checkPowerDown();
|
||||
|
||||
PSP_EndHostFrame();
|
||||
|
||||
if (invalid_)
|
||||
return;
|
||||
|
||||
// Here the backbuffer will always be bound.
|
||||
|
||||
if (!osm.IsEmpty() || g_Config.bShowDebugStats || g_Config.iShowFPSCounter || g_Config.bShowTouchControls || g_Config.bShowDeveloperMenu || g_Config.bShowAudioDebug || saveStatePreview_->GetVisibility() != UI::V_GONE || g_Config.bShowFrameProfiler) {
|
||||
DrawContext *thin3d = screenManager()->getDrawContext();
|
||||
|
||||
// It's possible we never ended up outputted anything - make sure we have the backbuffer.
|
||||
thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::KEEP, RPAction::KEEP });
|
||||
|
||||
// This sets up some important states but not the viewport.
|
||||
screenManager()->getUIContext()->Begin();
|
||||
|
||||
|
||||
@@ -670,13 +670,7 @@ void GameSettingsScreen::CreateViews() {
|
||||
|
||||
systemSettings->Add(new CheckBox(&g_Config.bFastMemory, sy->T("Fast Memory", "Fast Memory (Unstable)")))->OnClick.Handle(this, &GameSettingsScreen::OnJitAffectingSetting);
|
||||
|
||||
auto separateCPUThread = new CheckBox(&g_Config.bSeparateCPUThread, sy->T("Multithreaded (experimental)"));
|
||||
systemSettings->Add(separateCPUThread);
|
||||
separateCPUThread->OnClick.Add([=](EventParams &e) {
|
||||
if (g_Config.bSeparateCPUThread)
|
||||
settingInfo_->Show(sy->T("Multithreaded Tip", "Not always faster, causes glitches/crashing"), e.v);
|
||||
return UI::EVENT_CONTINUE;
|
||||
});
|
||||
|
||||
systemSettings->Add(new CheckBox(&g_Config.bSeparateIOThread, sy->T("I/O on thread (experimental)")))->SetEnabled(!PSP_IsInited());
|
||||
static const char *ioTimingMethods[] = { "Fast (lag on slow storage)", "Host (bugs, less lag)", "Simulate UMD delays" };
|
||||
View *ioTimingMethod = systemSettings->Add(new PopupMultiChoice(&g_Config.iIOTimingMethod, sy->T("IO timing method"), ioTimingMethods, 0, ARRAY_SIZE(ioTimingMethods), sy->GetName(), screenManager()));
|
||||
|
||||
@@ -323,7 +323,6 @@
|
||||
<ClInclude Include="..\..\ext\glslang\hlsl\hlslGrammar.h" />
|
||||
<ClInclude Include="..\..\ext\glslang\hlsl\hlslOpMap.h" />
|
||||
<ClInclude Include="..\..\ext\glslang\hlsl\hlslParseables.h" />
|
||||
<ClInclude Include="..\..\ext\glslang\hlsl\hlslParseHelper.h" />
|
||||
<ClInclude Include="..\..\ext\glslang\hlsl\hlslScanContext.h" />
|
||||
<ClInclude Include="..\..\ext\glslang\hlsl\hlslTokens.h" />
|
||||
<ClInclude Include="..\..\ext\glslang\hlsl\hlslTokenStream.h" />
|
||||
@@ -365,9 +364,7 @@
|
||||
<ClCompile Include="..\..\ext\glslang\glslang\MachineIndependent\preprocessor\Pp.cpp" />
|
||||
<ClCompile Include="..\..\ext\glslang\glslang\MachineIndependent\preprocessor\PpAtom.cpp" />
|
||||
<ClCompile Include="..\..\ext\glslang\glslang\MachineIndependent\preprocessor\PpContext.cpp" />
|
||||
<ClCompile Include="..\..\ext\glslang\glslang\MachineIndependent\preprocessor\PpMemory.cpp" />
|
||||
<ClCompile Include="..\..\ext\glslang\glslang\MachineIndependent\preprocessor\PpScanner.cpp" />
|
||||
<ClCompile Include="..\..\ext\glslang\glslang\MachineIndependent\preprocessor\PpSymbols.cpp" />
|
||||
<ClCompile Include="..\..\ext\glslang\glslang\MachineIndependent\preprocessor\PpTokens.cpp" />
|
||||
<ClCompile Include="..\..\ext\glslang\glslang\MachineIndependent\propagateNoContraction.cpp" />
|
||||
<ClCompile Include="..\..\ext\glslang\glslang\MachineIndependent\reflection.cpp" />
|
||||
@@ -381,7 +378,6 @@
|
||||
<ClCompile Include="..\..\ext\glslang\hlsl\hlslGrammar.cpp" />
|
||||
<ClCompile Include="..\..\ext\glslang\hlsl\hlslOpMap.cpp" />
|
||||
<ClCompile Include="..\..\ext\glslang\hlsl\hlslParseables.cpp" />
|
||||
<ClCompile Include="..\..\ext\glslang\hlsl\hlslParseHelper.cpp" />
|
||||
<ClCompile Include="..\..\ext\glslang\hlsl\hlslScanContext.cpp" />
|
||||
<ClCompile Include="..\..\ext\glslang\hlsl\hlslTokenStream.cpp" />
|
||||
<ClCompile Include="..\..\ext\glslang\OGLCompilersDLL\InitializeDll.cpp" />
|
||||
@@ -407,4 +403,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -103,15 +103,9 @@
|
||||
<ClCompile Include="..\..\ext\glslang\glslang\MachineIndependent\preprocessor\PpContext.cpp">
|
||||
<Filter>glslang\MachineIndependent\Preprocessor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\ext\glslang\glslang\MachineIndependent\preprocessor\PpMemory.cpp">
|
||||
<Filter>glslang\MachineIndependent\Preprocessor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\ext\glslang\glslang\MachineIndependent\preprocessor\PpScanner.cpp">
|
||||
<Filter>glslang\MachineIndependent\Preprocessor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\ext\glslang\glslang\MachineIndependent\preprocessor\PpSymbols.cpp">
|
||||
<Filter>glslang\MachineIndependent\Preprocessor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\ext\glslang\glslang\MachineIndependent\preprocessor\PpTokens.cpp">
|
||||
<Filter>glslang\MachineIndependent\Preprocessor</Filter>
|
||||
</ClCompile>
|
||||
@@ -154,9 +148,6 @@
|
||||
<ClCompile Include="..\..\ext\glslang\hlsl\hlslParseables.cpp">
|
||||
<Filter>hlsl</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\ext\glslang\hlsl\hlslParseHelper.cpp">
|
||||
<Filter>hlsl</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\ext\glslang\hlsl\hlslScanContext.cpp">
|
||||
<Filter>hlsl</Filter>
|
||||
</ClCompile>
|
||||
@@ -314,9 +305,6 @@
|
||||
<ClInclude Include="..\..\ext\glslang\hlsl\hlslParseables.h">
|
||||
<Filter>hlsl</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\ext\glslang\hlsl\hlslParseHelper.h">
|
||||
<Filter>hlsl</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\ext\glslang\hlsl\hlslScanContext.h">
|
||||
<Filter>hlsl</Filter>
|
||||
</ClInclude>
|
||||
@@ -330,4 +318,4 @@
|
||||
<Filter>OGLCompilersDLL</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -30,8 +30,6 @@ android {
|
||||
}
|
||||
} else {
|
||||
release {
|
||||
// Can't build release builds without a key store.
|
||||
println 'This build type should only be invoked from CI. Use Optimized builds instead.'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,5 +135,5 @@ afterEvaluate {
|
||||
android.sourceSets.main.assets.getSrcDirs().each { println it }
|
||||
}
|
||||
dependencies {
|
||||
compile project(':com.bda.controller')
|
||||
implementation project(':com.bda.controller')
|
||||
}
|
||||
@@ -290,12 +290,21 @@ bool AndroidVulkanContext::Init(ANativeWindow *wnd, int desiredBackbufferSizeX,
|
||||
return false;
|
||||
}
|
||||
|
||||
g_Vulkan->ChooseDevice(g_Vulkan->GetBestPhysicalDevice());
|
||||
int physicalDevice = g_Vulkan->GetBestPhysicalDevice();
|
||||
if (physicalDevice < 0) {
|
||||
ELOG("No usable Vulkan device found.");
|
||||
delete g_Vulkan;
|
||||
g_Vulkan = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
g_Vulkan->ChooseDevice(physicalDevice);
|
||||
// Here we can enable device extensions if we like.
|
||||
|
||||
ILOG("Creating vulkan device");
|
||||
if (g_Vulkan->CreateDevice() != VK_SUCCESS) {
|
||||
ILOG("Failed to create vulkan device: %s", g_Vulkan->InitError().c_str());
|
||||
System_SendMessage("toast", "No Vulkan driver found. Using OpenGL instead.");
|
||||
delete g_Vulkan;
|
||||
g_Vulkan = nullptr;
|
||||
return false;
|
||||
|
||||
@@ -57,6 +57,7 @@ public class TextRenderer {
|
||||
|
||||
int [] pixels = new int[w * h];
|
||||
bmp.getPixels(pixels, 0, w, 0, 0, w, h);
|
||||
bmp.recycle();
|
||||
return pixels;
|
||||
}
|
||||
}
|
||||
+1
-1
Submodule ext/glslang updated: 136b1e2d5d...2edde6665d.
@@ -33,16 +33,13 @@ LOCAL_SRC_FILES := \
|
||||
../glslang/glslang/MachineIndependent/preprocessor/Pp.cpp \
|
||||
../glslang/glslang/MachineIndependent/preprocessor/PpAtom.cpp \
|
||||
../glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp \
|
||||
../glslang/glslang/MachineIndependent/preprocessor/PpMemory.cpp \
|
||||
../glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp \
|
||||
../glslang/glslang/MachineIndependent/preprocessor/PpSymbols.cpp \
|
||||
../glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp \
|
||||
../glslang/glslang/OSDependent/Unix/ossource.cpp \
|
||||
../glslang/hlsl/hlslAttributes.cpp \
|
||||
../glslang/hlsl/hlslGrammar.cpp \
|
||||
../glslang/hlsl/hlslOpMap.cpp \
|
||||
../glslang/hlsl/hlslParseables.cpp \
|
||||
../glslang/hlsl/hlslParseHelper.cpp \
|
||||
../glslang/hlsl/hlslScanContext.cpp \
|
||||
../glslang/hlsl/hlslTokenStream.cpp \
|
||||
../glslang/SPIRV/disassemble.cpp \
|
||||
|
||||
+2
-5
@@ -22,7 +22,8 @@
|
||||
<ProjectGuid>{EDFA2E87-8AC1-4853-95D4-D7594FF81947}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>glslang</RootNamespace>
|
||||
<WindowsTargetPlatformVersion></WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>
|
||||
</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
@@ -168,9 +169,7 @@
|
||||
<ClCompile Include="glslang\glslang\MachineIndependent\preprocessor\Pp.cpp" />
|
||||
<ClCompile Include="glslang\glslang\MachineIndependent\preprocessor\PpAtom.cpp" />
|
||||
<ClCompile Include="glslang\glslang\MachineIndependent\preprocessor\PpContext.cpp" />
|
||||
<ClCompile Include="glslang\glslang\MachineIndependent\preprocessor\PpMemory.cpp" />
|
||||
<ClCompile Include="glslang\glslang\MachineIndependent\preprocessor\PpScanner.cpp" />
|
||||
<ClCompile Include="glslang\glslang\MachineIndependent\preprocessor\PpSymbols.cpp" />
|
||||
<ClCompile Include="glslang\glslang\MachineIndependent\preprocessor\PpTokens.cpp" />
|
||||
<ClCompile Include="glslang\glslang\MachineIndependent\propagateNoContraction.cpp" />
|
||||
<ClCompile Include="glslang\glslang\MachineIndependent\reflection.cpp" />
|
||||
@@ -184,7 +183,6 @@
|
||||
<ClCompile Include="glslang\hlsl\hlslGrammar.cpp" />
|
||||
<ClCompile Include="glslang\hlsl\hlslOpMap.cpp" />
|
||||
<ClCompile Include="glslang\hlsl\hlslParseables.cpp" />
|
||||
<ClCompile Include="glslang\hlsl\hlslParseHelper.cpp" />
|
||||
<ClCompile Include="glslang\hlsl\hlslScanContext.cpp" />
|
||||
<ClCompile Include="glslang\hlsl\hlslTokenStream.cpp" />
|
||||
<ClCompile Include="glslang\OGLCompilersDLL\InitializeDll.cpp" />
|
||||
@@ -231,7 +229,6 @@
|
||||
<ClInclude Include="glslang\hlsl\hlslGrammar.h" />
|
||||
<ClInclude Include="glslang\hlsl\hlslOpMap.h" />
|
||||
<ClInclude Include="glslang\hlsl\hlslParseables.h" />
|
||||
<ClInclude Include="glslang\hlsl\hlslParseHelper.h" />
|
||||
<ClInclude Include="glslang\hlsl\hlslScanContext.h" />
|
||||
<ClInclude Include="glslang\hlsl\hlslTokens.h" />
|
||||
<ClInclude Include="glslang\hlsl\hlslTokenStream.h" />
|
||||
|
||||
@@ -42,15 +42,9 @@
|
||||
<ClCompile Include="glslang\glslang\MachineIndependent\preprocessor\PpContext.cpp">
|
||||
<Filter>glslang</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\glslang\MachineIndependent\preprocessor\PpMemory.cpp">
|
||||
<Filter>glslang</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\glslang\MachineIndependent\preprocessor\PpScanner.cpp">
|
||||
<Filter>glslang</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\glslang\MachineIndependent\preprocessor\PpSymbols.cpp">
|
||||
<Filter>glslang</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\glslang\MachineIndependent\preprocessor\PpTokens.cpp">
|
||||
<Filter>glslang</Filter>
|
||||
</ClCompile>
|
||||
@@ -137,9 +131,6 @@
|
||||
<ClCompile Include="glslang\hlsl\hlslParseables.cpp">
|
||||
<Filter>HLSL</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\hlsl\hlslParseHelper.cpp">
|
||||
<Filter>HLSL</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\hlsl\hlslScanContext.cpp">
|
||||
<Filter>HLSL</Filter>
|
||||
</ClCompile>
|
||||
@@ -290,9 +281,6 @@
|
||||
<ClInclude Include="glslang\hlsl\hlslParseables.h">
|
||||
<Filter>HLSL</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\hlsl\hlslParseHelper.h">
|
||||
<Filter>HLSL</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\hlsl\hlslScanContext.h">
|
||||
<Filter>HLSL</Filter>
|
||||
</ClInclude>
|
||||
|
||||
@@ -164,9 +164,6 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x,
|
||||
std::string text(NormalizeString(std::string(str)));
|
||||
if (text.empty())
|
||||
return;
|
||||
JNIEnv *env;
|
||||
int result = javaVM->GetEnv((void **)&env, JNI_VERSION_1_6);
|
||||
assert(env == env_);
|
||||
|
||||
uint32_t stringHash = hash::Adler32((const uint8_t *)text.data(), text.size());
|
||||
uint32_t entryHash = stringHash ^ fontHash_ ^ (align << 24);
|
||||
@@ -221,6 +218,7 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x,
|
||||
}
|
||||
}
|
||||
env_->ReleaseIntArrayElements(imageData, jimage, 0);
|
||||
env_->DeleteLocalRef(imageData);
|
||||
desc.initData.push_back((uint8_t *)bitmapData);
|
||||
entry->texture = draw_->CreateTexture(desc);
|
||||
delete[] bitmapData;
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#include "VulkanQueueRunner.h"
|
||||
#include "VulkanRenderManager.h"
|
||||
|
||||
// Debug help: adb logcat -s DEBUG NativeActivity NativeApp PPSSPP
|
||||
|
||||
// TODO: This is only enough for 4x render resolution / 4x texture upscale for debugger.
|
||||
// Maybe we should use a dynamically allocated one for larger?
|
||||
const uint32_t readbackBufferSize = 2048 * 2048 * 4;
|
||||
@@ -342,6 +344,12 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c
|
||||
iter.fb->Release();
|
||||
}
|
||||
|
||||
// Don't execute empty renderpasses.
|
||||
if (step.commands.empty() && step.render.color == VKRRenderPassAction::KEEP && step.render.depthStencil == VKRRenderPassAction::KEEP) {
|
||||
// Nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
// This is supposed to bind a vulkan render pass to the command buffer.
|
||||
PerformBindFramebufferAsRenderTarget(step, cmd);
|
||||
|
||||
@@ -481,28 +489,17 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c
|
||||
}
|
||||
|
||||
void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step, VkCommandBuffer cmd) {
|
||||
VkRenderPass renderPass;
|
||||
int numClearVals = 0;
|
||||
VkClearValue clearVal[2]{};
|
||||
VkFramebuffer framebuf;
|
||||
int w;
|
||||
int h;
|
||||
VkImageLayout prevLayout;
|
||||
if (step.render.framebuffer) {
|
||||
VKRFramebuffer *fb = step.render.framebuffer;
|
||||
framebuf = fb->framebuf;
|
||||
w = fb->width;
|
||||
h = fb->height;
|
||||
prevLayout = fb->color.layout;
|
||||
} else {
|
||||
framebuf = backbuffer_;
|
||||
w = vulkan_->GetBackbufferWidth();
|
||||
h = vulkan_->GetBackbufferHeight();
|
||||
}
|
||||
|
||||
VkRenderPass renderPass;
|
||||
int numClearVals = 0;
|
||||
VkClearValue clearVal[2];
|
||||
memset(clearVal, 0, sizeof(clearVal));
|
||||
if (step.render.framebuffer) {
|
||||
VKRFramebuffer *fb = step.render.framebuffer;
|
||||
// Now, if the image needs transitioning, let's transition.
|
||||
// The backbuffer does not, that's handled by VulkanContext.
|
||||
if (step.render.framebuffer->color.layout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
|
||||
@@ -526,15 +523,17 @@ void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step
|
||||
break;
|
||||
}
|
||||
|
||||
// Due to a known bug in the Mali driver, pass the level count explicitly.
|
||||
TransitionImageLayout2(cmd, fb->color.image, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
fb->color.layout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
srcStage, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
srcAccessMask, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT);
|
||||
srcAccessMask, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, 1);
|
||||
fb->color.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
if (fb->depth.layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
|
||||
VkAccessFlags srcAccessMask;
|
||||
VkPipelineStageFlags srcStage;
|
||||
|
||||
switch (fb->depth.layout) {
|
||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||
srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
@@ -552,10 +551,13 @@ void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step
|
||||
Crash();
|
||||
break;
|
||||
}
|
||||
|
||||
// Due to a known bug in the Mali driver, pass the level count explicitly (last param).
|
||||
TransitionImageLayout2(cmd, fb->depth.image, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
|
||||
fb->depth.layout, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
srcStage, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
srcAccessMask, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT);
|
||||
srcAccessMask, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
|
||||
1);
|
||||
fb->depth.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
|
||||
@@ -570,6 +572,9 @@ void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step
|
||||
numClearVals = 2;
|
||||
}
|
||||
} else {
|
||||
framebuf = backbuffer_;
|
||||
w = vulkan_->GetBackbufferWidth();
|
||||
h = vulkan_->GetBackbufferHeight();
|
||||
renderPass = GetBackbufferRenderPass();
|
||||
assert(step.render.color == VKRRenderPassAction::CLEAR || step.render.color == VKRRenderPassAction::DONT_CARE);
|
||||
assert(step.render.depthStencil == VKRRenderPassAction::CLEAR || step.render.depthStencil == VKRRenderPassAction::DONT_CARE);
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#endif
|
||||
|
||||
// TODO: Using a thread here is unfinished and does not work correctly.
|
||||
const bool useThread = false;
|
||||
const bool useThread = true;
|
||||
|
||||
#ifndef UINT64_MAX
|
||||
#define UINT64_MAX 0xFFFFFFFFFFFFFFFFULL
|
||||
@@ -217,13 +217,15 @@ void VulkanRenderManager::StopThread(bool shutdown) {
|
||||
thread_.join();
|
||||
VLOG("thread joined.");
|
||||
|
||||
// Resignal fences for next time around - must be done after join.
|
||||
// Wait for any fences to finish and be resignaled, so we don't have sync issues.
|
||||
for (int i = 0; i < vulkan_->GetInflightFrames(); i++) {
|
||||
auto &frameData = frameData_[i];
|
||||
frameData.readyForRun = false;
|
||||
if (!shutdown && !frameData.readyForFence) {
|
||||
vkDestroyFence(vulkan_->GetDevice(), frameData.fence, nullptr);
|
||||
frameData.fence = vulkan_->CreateFence(true);
|
||||
|
||||
std::unique_lock<std::mutex> lock(frameData.push_mutex);
|
||||
while (!frameData.readyForFence) {
|
||||
VLOG("PUSH: Waiting for frame[%d].readyForFence = 1 (stop)", i);
|
||||
frameData.push_condVar.wait(lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -268,12 +270,11 @@ VulkanRenderManager::~VulkanRenderManager() {
|
||||
queueRunner_.DestroyDeviceObjects();
|
||||
}
|
||||
|
||||
// TODO: Activate this code.
|
||||
void VulkanRenderManager::ThreadFunc() {
|
||||
setCurrentThreadName("RenderMan");
|
||||
int threadFrame = threadInitFrame_;
|
||||
bool nextFrame = false;
|
||||
while (run_) {
|
||||
while (true) {
|
||||
{
|
||||
if (nextFrame) {
|
||||
threadFrame++;
|
||||
@@ -286,6 +287,10 @@ void VulkanRenderManager::ThreadFunc() {
|
||||
VLOG("PULL: Waiting for frame[%d].readyForRun", threadFrame);
|
||||
frameData.pull_condVar.wait(lock);
|
||||
}
|
||||
if (!frameData.readyForRun && !run_) {
|
||||
// This means we're out of frames to render and run_ is false, so bail.
|
||||
break;
|
||||
}
|
||||
VLOG("PULL: frame[%d].readyForRun = false", threadFrame);
|
||||
frameData.readyForRun = false;
|
||||
// Previously we had a quick exit here that avoided calling Run() if run_ was suddenly false,
|
||||
@@ -586,11 +591,17 @@ void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect,
|
||||
_dbg_assert_msg_(G3D, srcRect.offset.x + srcRect.extent.width <= (uint32_t)src->width, "srcrect offset x + extent > width");
|
||||
_dbg_assert_msg_(G3D, srcRect.offset.y + srcRect.extent.height <= (uint32_t)src->height, "srcrect offset y + extent > height");
|
||||
|
||||
_dbg_assert_msg_(G3D, srcRect.extent.width > 0, "blit srcwidth == 0");
|
||||
_dbg_assert_msg_(G3D, srcRect.extent.height > 0, "blit srcheight == 0");
|
||||
|
||||
_dbg_assert_msg_(G3D, dstRect.offset.x >= 0, "dstrect offset x < 0");
|
||||
_dbg_assert_msg_(G3D, dstRect.offset.y >= 0, "dstrect offset y < 0");
|
||||
_dbg_assert_msg_(G3D, dstRect.offset.x + dstRect.extent.width <= (uint32_t)dst->width, "dstrect offset x + extent > width");
|
||||
_dbg_assert_msg_(G3D, dstRect.offset.y + dstRect.extent.height <= (uint32_t)dst->height, "dstrect offset y + extent > height");
|
||||
|
||||
_dbg_assert_msg_(G3D, dstRect.extent.width > 0, "blit dstwidth == 0");
|
||||
_dbg_assert_msg_(G3D, dstRect.extent.height > 0, "blit dstheight == 0");
|
||||
|
||||
VKRStep *step = new VKRStep{ VKRStepType::BLIT };
|
||||
|
||||
step->blit.aspectMask = aspectMask;
|
||||
@@ -650,7 +661,6 @@ void VulkanRenderManager::Finish() {
|
||||
}
|
||||
|
||||
void VulkanRenderManager::Wipe() {
|
||||
int curFrame = vulkan_->GetCurFrame();
|
||||
for (auto step : steps_) {
|
||||
// Need to release held framebuffers.
|
||||
switch (step->stepType) {
|
||||
@@ -689,7 +699,13 @@ void VulkanRenderManager::BeginSubmitFrame(int frame) {
|
||||
// Get the index of the next available swapchain image, and a semaphore to block command buffer execution on.
|
||||
// Now, I wonder if we should do this early in the frame or late? Right now we do it early, which should be fine.
|
||||
VkResult res = vkAcquireNextImageKHR(vulkan_->GetDevice(), vulkan_->GetSwapchain(), UINT64_MAX, acquireSemaphore_, (VkFence)VK_NULL_HANDLE, &frameData.curSwapchainImage);
|
||||
assert(res == VK_SUCCESS);
|
||||
if (res == VK_SUBOPTIMAL_KHR) {
|
||||
// Hopefully the resize will happen shortly. Ignore.
|
||||
} else if (res == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||
frameData.skipSwap = true;
|
||||
} else {
|
||||
assert(res == VK_SUCCESS);
|
||||
}
|
||||
// TODO: Deal with the VK_SUBOPTIMAL_KHR and VK_ERROR_OUT_OF_DATE_KHR
|
||||
// return codes
|
||||
|
||||
@@ -737,7 +753,7 @@ void VulkanRenderManager::Submit(int frame, bool triggerFence) {
|
||||
cmdBufs[numCmdBufs++] = frameData.mainCmd;
|
||||
|
||||
VkSubmitInfo submit_info{ VK_STRUCTURE_TYPE_SUBMIT_INFO };
|
||||
if (triggerFence) {
|
||||
if (triggerFence && !frameData.skipSwap) {
|
||||
submit_info.waitSemaphoreCount = 1;
|
||||
submit_info.pWaitSemaphores = &acquireSemaphore_;
|
||||
VkPipelineStageFlags waitStage[1]{ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
|
||||
@@ -745,7 +761,7 @@ void VulkanRenderManager::Submit(int frame, bool triggerFence) {
|
||||
}
|
||||
submit_info.commandBufferCount = (uint32_t)numCmdBufs;
|
||||
submit_info.pCommandBuffers = cmdBufs;
|
||||
if (triggerFence) {
|
||||
if (triggerFence && !frameData.skipSwap) {
|
||||
submit_info.signalSemaphoreCount = 1;
|
||||
submit_info.pSignalSemaphores = &renderingCompleteSemaphore_;
|
||||
}
|
||||
@@ -771,21 +787,25 @@ void VulkanRenderManager::EndSubmitFrame(int frame) {
|
||||
|
||||
Submit(frame, true);
|
||||
|
||||
VkSwapchainKHR swapchain = vulkan_->GetSwapchain();
|
||||
VkPresentInfoKHR present = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
|
||||
present.swapchainCount = 1;
|
||||
present.pSwapchains = &swapchain;
|
||||
present.pImageIndices = &frameData.curSwapchainImage;
|
||||
present.pWaitSemaphores = &renderingCompleteSemaphore_;
|
||||
present.waitSemaphoreCount = 1;
|
||||
if (!frameData.skipSwap) {
|
||||
VkSwapchainKHR swapchain = vulkan_->GetSwapchain();
|
||||
VkPresentInfoKHR present = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
|
||||
present.swapchainCount = 1;
|
||||
present.pSwapchains = &swapchain;
|
||||
present.pImageIndices = &frameData.curSwapchainImage;
|
||||
present.pWaitSemaphores = &renderingCompleteSemaphore_;
|
||||
present.waitSemaphoreCount = 1;
|
||||
|
||||
VkResult res = vkQueuePresentKHR(vulkan_->GetGraphicsQueue(), &present);
|
||||
// TODO: Deal with the VK_SUBOPTIMAL_WSI and VK_ERROR_OUT_OF_DATE_WSI
|
||||
// return codes
|
||||
if (res == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||
// ignore, it'll be fine. this happens sometimes during resizes, and we do make sure to recreate the swap chain.
|
||||
VkResult res = vkQueuePresentKHR(vulkan_->GetGraphicsQueue(), &present);
|
||||
// TODO: Deal with the VK_SUBOPTIMAL_WSI and VK_ERROR_OUT_OF_DATE_WSI
|
||||
// return codes
|
||||
if (res == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||
// ignore, it'll be fine. this happens sometimes during resizes, and we do make sure to recreate the swap chain.
|
||||
} else {
|
||||
assert(res == VK_SUCCESS);
|
||||
}
|
||||
} else {
|
||||
assert(res == VK_SUCCESS);
|
||||
frameData.skipSwap = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -238,6 +238,7 @@ private:
|
||||
|
||||
bool readyForFence = true;
|
||||
bool readyForRun = false;
|
||||
bool skipSwap = false;
|
||||
VKRRunType type = VKRRunType::END;
|
||||
|
||||
VkFence fence;
|
||||
|
||||
@@ -429,7 +429,7 @@ public:
|
||||
switch (info) {
|
||||
case APINAME: return "Vulkan";
|
||||
case VENDORSTRING: return vulkan_->GetPhysicalDeviceProperties().deviceName;
|
||||
case VENDOR: return StringFromFormat("%08x", vulkan_->GetPhysicalDeviceProperties().vendorID);
|
||||
case VENDOR: return VulkanVendorString(vulkan_->GetPhysicalDeviceProperties().vendorID);
|
||||
case DRIVER: return StringFromFormat("%08x", vulkan_->GetPhysicalDeviceProperties().driverVersion);
|
||||
case SHADELANGVERSION: return "N/A";;
|
||||
case APIVERSION:
|
||||
|
||||
@@ -158,6 +158,8 @@ bool RunAutoTest(HeadlessHost *headlessHost, CoreParameter &coreParameter, bool
|
||||
static double deadline;
|
||||
deadline = time_now() + timeout;
|
||||
|
||||
Core_UpdateDebugStats(g_Config.bShowDebugStats || g_Config.bLogFrameDrops);
|
||||
|
||||
PSP_BeginHostFrame();
|
||||
|
||||
coreState = CORE_RUNNING;
|
||||
|
||||
Reference in new issue
Block a user