mirror of
https://github.com/izzy2lost/PSX2.git
synced 2026-07-05 15:18:36 -07:00
Mali Mediatek fixes
This commit is contained in:
+16
-4
@@ -8,6 +8,18 @@ def keystoreProperties = new Properties()
|
||||
if (keystorePropertiesFile.exists()) {
|
||||
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
|
||||
}
|
||||
def signingKeys = ['storeFile', 'storePassword', 'keyAlias', 'keyPassword']
|
||||
def missingSigningKeys = signingKeys.findAll { !keystoreProperties.getProperty(it)?.trim() }
|
||||
def hasReleaseSigning = keystorePropertiesFile.exists() && missingSigningKeys.isEmpty()
|
||||
if (hasReleaseSigning) {
|
||||
def configuredStoreFile = file(keystoreProperties.getProperty('storeFile'))
|
||||
if (!configuredStoreFile.exists()) {
|
||||
logger.lifecycle("[app] Release keystore file not found at ${configuredStoreFile}. Falling back to debug signing for release.")
|
||||
hasReleaseSigning = false
|
||||
}
|
||||
} else {
|
||||
logger.lifecycle("[app] Release signing not fully configured (${missingSigningKeys}). Falling back to debug signing for release.")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = 'com.izzy2lost.psx2'
|
||||
@@ -16,7 +28,7 @@ android {
|
||||
|
||||
signingConfigs {
|
||||
release {
|
||||
if (keystorePropertiesFile.exists()) {
|
||||
if (hasReleaseSigning) {
|
||||
storeFile file(keystoreProperties['storeFile'])
|
||||
storePassword keystoreProperties['storePassword']
|
||||
keyAlias keystoreProperties['keyAlias']
|
||||
@@ -29,8 +41,8 @@ android {
|
||||
applicationId = "com.izzy2lost.psx2"
|
||||
minSdk = 26
|
||||
targetSdk = 36
|
||||
versionCode 21
|
||||
versionName "1.1.9"
|
||||
versionCode 23
|
||||
versionName "1.2.1"
|
||||
// APK
|
||||
base.archivesName = "PSX2_${versionCode}_${new Date().format('yyyyMMddHHmm')}"
|
||||
|
||||
@@ -57,7 +69,7 @@ android {
|
||||
minifyEnabled = false
|
||||
shrinkResources = false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
signingConfig signingConfigs.release
|
||||
signingConfig hasReleaseSigning ? signingConfigs.release : signingConfigs.debug
|
||||
ndk {
|
||||
debugSymbolLevel 'SYMBOL_TABLE'
|
||||
}
|
||||
|
||||
@@ -20,7 +20,8 @@ uniform uvec4 const0;
|
||||
uniform uvec4 const1;
|
||||
uniform ivec2 srcOffset;
|
||||
|
||||
layout(binding=0) uniform sampler2D imgSrc;
|
||||
// Sampler binding defaults to 0 if not explicitly set; texture unit 0 is used in code.
|
||||
uniform sampler2D imgSrc;
|
||||
layout(binding=0, rgba8) uniform writeonly image2D imgDst;
|
||||
|
||||
#define A_GPU 1
|
||||
|
||||
@@ -79,7 +79,7 @@ in SHADER
|
||||
// Basically the only scenario where this'll happen is RGBA masked and DATE is active.
|
||||
#undef PS_NO_COLOR
|
||||
#define PS_NO_COLOR 0
|
||||
#if defined(GL_EXT_shader_framebuffer_fetch)
|
||||
#if defined(GLAD_GL_EXT_shader_pixel_local_storage)
|
||||
#undef TARGET_0_QUALIFIER
|
||||
#define TARGET_0_QUALIFIER inout
|
||||
#define LAST_FRAG_COLOR SV_Target0
|
||||
|
||||
@@ -321,7 +321,7 @@ enum class BiFiltering : u8
|
||||
|
||||
enum class TriFiltering : s8
|
||||
{
|
||||
Automatic = -1,
|
||||
Automatic,
|
||||
Off,
|
||||
PS2,
|
||||
Forced,
|
||||
@@ -847,6 +847,7 @@ struct Pcsx2Config
|
||||
int AudioCaptureBitrate = DEFAULT_AUDIO_CAPTURE_BITRATE;
|
||||
|
||||
std::string Adapter;
|
||||
std::string CustomDriverPath;
|
||||
std::string HWDumpDirectory;
|
||||
std::string SWDumpDirectory;
|
||||
|
||||
|
||||
@@ -34,6 +34,10 @@
|
||||
#include "GS/Renderers/Vulkan/GSDeviceVK.h"
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include "AndroidDeviceDetection.h"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include "GS/Renderers/DX11/GSDevice11.h"
|
||||
@@ -342,20 +346,24 @@ bool GSopen(const Pcsx2Config::GSOptions& config, GSRendererType renderer, u8* b
|
||||
{
|
||||
GSConfig = config;
|
||||
|
||||
// If the selected renderer is Auto (often from a per-game settings layer),
|
||||
// prefer the base/global renderer when it is explicitly set, otherwise
|
||||
// fall back to the hardware/platform preferred renderer.
|
||||
if (renderer == GSRendererType::Auto)
|
||||
{
|
||||
const int base_renderer_val = Host::GetBaseIntSettingValue("EmuCore/GS", "Renderer",
|
||||
static_cast<int>(GSRendererType::Auto));
|
||||
const GSRendererType base_renderer = static_cast<GSRendererType>(base_renderer_val);
|
||||
if (base_renderer != GSRendererType::Auto)
|
||||
renderer = base_renderer;
|
||||
else
|
||||
renderer = GSUtil::GetPreferredRenderer();
|
||||
renderer = (base_renderer != GSRendererType::Auto) ? base_renderer : GSUtil::GetPreferredRenderer();
|
||||
}
|
||||
|
||||
#if defined(__ANDROID__) && defined(ENABLE_OPENGL)
|
||||
// Don't attempt Vulkan first on Mali; it is known unstable on many devices.
|
||||
if (renderer == GSRendererType::VK &&
|
||||
AndroidDeviceDetection::DetectGPUVendor() == AndroidDeviceDetection::GPUVendor::ARM)
|
||||
{
|
||||
Console.Warning("Mali detected with Vulkan selected, forcing OpenGL for startup stability.");
|
||||
renderer = GSRendererType::OGL;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool res = OpenGSDevice(renderer, true, false, vsync_mode, allow_present_throttle);
|
||||
if (res)
|
||||
{
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
#include "GS/GSExtra.h"
|
||||
#include "GS/GSUtil.h"
|
||||
#include "MultiISA.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
@@ -219,21 +219,17 @@ GSRendererType GSUtil::GetPreferredRenderer()
|
||||
// Use D3D device info to select renderer.
|
||||
preferred_renderer = D3D::GetPreferredRenderer();
|
||||
#elif defined(__ANDROID__)
|
||||
// Android: Detect GPU vendor and choose appropriate renderer
|
||||
// Android: Detect GPU vendor and choose appropriate renderer.
|
||||
using namespace AndroidDeviceDetection;
|
||||
GPUVendor vendor = DetectGPUVendor();
|
||||
|
||||
const GPUVendor vendor = DetectGPUVendor();
|
||||
|
||||
if (vendor == GPUVendor::ARM)
|
||||
{
|
||||
// Mediatek/Mali GPUs: Prefer OpenGL over Vulkan
|
||||
// Vulkan drivers on Mali are often buggy, especially on Mediatek
|
||||
// OpenGL works but may have 2D graphics issues that need workarounds
|
||||
Console.Warning("Mediatek/Mali GPU detected: Using OpenGL renderer (Vulkan has known issues)");
|
||||
// Mali/Mediatek: prefer OpenGL for stability.
|
||||
Console.Warning("Mali GPU detected: preferring OpenGL renderer.");
|
||||
#if defined(ENABLE_OPENGL)
|
||||
preferred_renderer = GSRendererType::OGL;
|
||||
#elif defined(ENABLE_VULKAN)
|
||||
// Fallback to Vulkan if OpenGL not available (but warn user)
|
||||
Console.Error("OpenGL not available, falling back to Vulkan (may have issues on Mali)");
|
||||
preferred_renderer = GSRendererType::VK;
|
||||
#else
|
||||
preferred_renderer = GSRendererType::SW;
|
||||
@@ -241,8 +237,8 @@ GSRendererType GSUtil::GetPreferredRenderer()
|
||||
}
|
||||
else if (vendor == GPUVendor::Qualcomm)
|
||||
{
|
||||
// Snapdragon/Adreno GPUs: Prefer Vulkan (good driver support)
|
||||
Console.WriteLn("Qualcomm/Adreno GPU detected: Using Vulkan renderer");
|
||||
// Adreno: Vulkan is typically fine.
|
||||
Console.WriteLn("Adreno GPU detected: preferring Vulkan renderer.");
|
||||
#if defined(ENABLE_VULKAN)
|
||||
preferred_renderer = GSRendererType::VK;
|
||||
#elif defined(ENABLE_OPENGL)
|
||||
@@ -253,22 +249,14 @@ GSRendererType GSUtil::GetPreferredRenderer()
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unknown vendor: Try Vulkan first, then OpenGL
|
||||
Console.WriteLn("Unknown GPU vendor: Trying Vulkan renderer");
|
||||
#if defined(ENABLE_VULKAN)
|
||||
if (GSDeviceVK::IsSuitableDefaultRenderer())
|
||||
preferred_renderer = GSRendererType::VK;
|
||||
#endif
|
||||
if (preferred_renderer == GSRendererType::Auto)
|
||||
{
|
||||
// Unknown Android GPU: prefer OpenGL for startup stability.
|
||||
#if defined(ENABLE_OPENGL)
|
||||
preferred_renderer = GSRendererType::OGL;
|
||||
preferred_renderer = GSRendererType::OGL;
|
||||
#elif defined(ENABLE_VULKAN)
|
||||
preferred_renderer = GSRendererType::VK;
|
||||
preferred_renderer = GSRendererType::VK;
|
||||
#else
|
||||
preferred_renderer = GSRendererType::SW;
|
||||
preferred_renderer = GSRendererType::SW;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#else
|
||||
// Linux: Prefer Vulkan if the driver isn't buggy.
|
||||
@@ -277,14 +265,14 @@ GSRendererType GSUtil::GetPreferredRenderer()
|
||||
preferred_renderer = GSRendererType::VK;
|
||||
#endif
|
||||
|
||||
// Otherwise, whatever is available.
|
||||
if (preferred_renderer == GSRendererType::Auto) // If it's still auto, VK wasn't selected.
|
||||
// Otherwise, whatever is available.
|
||||
if (preferred_renderer == GSRendererType::Auto) // If it's still auto, VK wasn't selected.
|
||||
#if defined(ENABLE_OPENGL)
|
||||
preferred_renderer = GSRendererType::OGL;
|
||||
preferred_renderer = GSRendererType::OGL;
|
||||
#elif defined(ENABLE_VULKAN)
|
||||
preferred_renderer = GSRendererType::VK;
|
||||
preferred_renderer = GSRendererType::VK;
|
||||
#else
|
||||
preferred_renderer = GSRendererType::SW;
|
||||
preferred_renderer = GSRendererType::SW;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -5518,6 +5518,10 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
|
||||
const bool alpha_eq_one = alpha_c0_eq_one || alpha_c2_eq_one;
|
||||
const bool alpha_high_one = alpha_c0_high_min_one || alpha_c2_high_one;
|
||||
const bool alpha_eq_less_one = alpha_c0_eq_less_max_one || alpha_c2_eq_less_one;
|
||||
const bool alpha_mali_custom_set = alpha_eq_less_one || alpha_c0_high_max_one;
|
||||
const bool alpha_mali_custom_set_c0 = alpha_c0_eq_zero || alpha_c0_eq_one || alpha_c0_high_min_one || alpha_c0_high_max_one || alpha_c0_eq_less_max_one;
|
||||
const bool alpha_mali_custom_set_c1 = alpha_c1_high_min_one || alpha_c1_high_max_one || alpha_c1_eq_less_max_one || alpha_c1_high_no_rta_correct;
|
||||
const bool alpha_mali_custom_set_c2 = alpha_c2_eq_zero || alpha_c2_eq_one || alpha_c2_eq_less_one || alpha_c2_high_one;
|
||||
|
||||
// Optimize blending equations, must be done before index calculation
|
||||
if ((m_conf.ps.blend_a == m_conf.ps.blend_b) || ((m_conf.ps.blend_b == m_conf.ps.blend_d) && alpha_eq_one))
|
||||
@@ -5679,7 +5683,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
|
||||
// Enable sw blending for barriers.
|
||||
sw_blending |= blend_requires_barrier;
|
||||
// Enable sw blending for free blending.
|
||||
sw_blending |= free_blend;
|
||||
sw_blending |= free_blend | alpha_mali_custom_set;
|
||||
// Do not run BLEND MIX if sw blending is already present, it's less accurate.
|
||||
blend_mix &= !sw_blending;
|
||||
sw_blending |= blend_mix;
|
||||
@@ -5720,7 +5724,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
|
||||
// Enable sw blending for reading fb.
|
||||
sw_blending |= prefer_sw_blend;
|
||||
// Enable sw blending for free blending.
|
||||
sw_blending |= free_blend;
|
||||
sw_blending |= free_blend | alpha_mali_custom_set;
|
||||
// Do not run BLEND MIX if sw blending is already present, it's less accurate.
|
||||
blend_mix &= !sw_blending;
|
||||
sw_blending |= blend_mix;
|
||||
|
||||
@@ -60,9 +60,10 @@ std::vector<GLContext::FullscreenModeInfo> GLContext::EnumerateFullscreenModes()
|
||||
std::unique_ptr<GLContext> GLContext::Create(const WindowInfo& wi, const Version* versions_to_try,
|
||||
size_t num_versions_to_try)
|
||||
{
|
||||
if (ShouldPreferESContext())
|
||||
const bool prefer_es = (wi.type == WindowInfo::Type::Android) || ShouldPreferESContext();
|
||||
if (prefer_es)
|
||||
{
|
||||
// move ES versions to the front
|
||||
// Move ES profiles to the front so EGL negotiates a GLES context first on Android/mobile.
|
||||
Version* new_versions_to_try = static_cast<Version*>(alloca(sizeof(Version) * num_versions_to_try));
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; i < num_versions_to_try; i++)
|
||||
@@ -70,11 +71,13 @@ std::unique_ptr<GLContext> GLContext::Create(const WindowInfo& wi, const Version
|
||||
if (versions_to_try[i].profile == Profile::ES)
|
||||
new_versions_to_try[count++] = versions_to_try[i];
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_versions_to_try; i++)
|
||||
{
|
||||
if (versions_to_try[i].profile != Profile::ES)
|
||||
new_versions_to_try[count++] = versions_to_try[i];
|
||||
}
|
||||
|
||||
versions_to_try = new_versions_to_try;
|
||||
}
|
||||
|
||||
@@ -108,6 +111,11 @@ std::unique_ptr<GLContext> GLContext::Create(const WindowInfo& wi, const Version
|
||||
|
||||
context_being_created = nullptr;
|
||||
|
||||
const char* gl_vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
|
||||
const char* gl_renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
|
||||
if (gl_vendor && gl_renderer)
|
||||
DisableBrokenExtensions(gl_vendor, gl_renderer);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "GS/Renderers/OpenGL/GLContextEGL.h"
|
||||
|
||||
#include "common/Console.h"
|
||||
#include <EGL/eglext.h>
|
||||
#include "GS/GS.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
@@ -68,7 +68,12 @@ bool GLContextEGL::Initialize(const Version* versions_to_try, size_t num_version
|
||||
|
||||
bool GLContextEGL::SetDisplay()
|
||||
{
|
||||
// On Android, there is no native display handle!ç
|
||||
#ifdef __ANDROID__
|
||||
m_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
#else
|
||||
m_display = eglGetDisplay(static_cast<EGLNativeDisplayType>(m_wi.display_connection));
|
||||
#endif
|
||||
if (!m_display)
|
||||
{
|
||||
Console.Error("eglGetDisplay() failed: %d", eglGetError());
|
||||
@@ -322,7 +327,7 @@ bool GLContextEGL::CreateContext(const Version& version, EGLContext share_contex
|
||||
config = configs.front();
|
||||
}
|
||||
|
||||
int attribs[8];
|
||||
int attribs[16];
|
||||
int nattribs = 0;
|
||||
if (version.profile != Profile::NoProfile)
|
||||
{
|
||||
@@ -331,6 +336,16 @@ bool GLContextEGL::CreateContext(const Version& version, EGLContext share_contex
|
||||
attribs[nattribs++] = EGL_CONTEXT_MINOR_VERSION;
|
||||
attribs[nattribs++] = version.minor_version;
|
||||
}
|
||||
|
||||
{
|
||||
const char* egl_ext = eglQueryString(m_display, EGL_EXTENSIONS);
|
||||
const bool has_egl_no_error = (egl_ext && std::strstr(egl_ext, "EGL_KHR_create_context_no_error"));
|
||||
if (has_egl_no_error && !GSConfig.UseDebugDevice)
|
||||
{
|
||||
attribs[nattribs++] = EGL_CONTEXT_OPENGL_NO_ERROR_KHR;
|
||||
attribs[nattribs++] = EGL_TRUE;
|
||||
}
|
||||
}
|
||||
attribs[nattribs++] = EGL_NONE;
|
||||
attribs[nattribs++] = 0;
|
||||
|
||||
|
||||
@@ -18,18 +18,9 @@
|
||||
#include "IconsFontAwesome5.h"
|
||||
|
||||
#include <cinttypes>
|
||||
#include <cctype>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
// Some texture barrier extension macros may not be generated by GLAD for GLES builds.
|
||||
#ifndef GLAD_GL_EXT_texture_barrier
|
||||
#define GLAD_GL_EXT_texture_barrier 0
|
||||
#endif
|
||||
#ifndef GLAD_GL_OES_texture_barrier
|
||||
#define GLAD_GL_OES_texture_barrier 0
|
||||
#endif
|
||||
|
||||
static constexpr u32 g_vs_cb_index = 1;
|
||||
static constexpr u32 g_ps_cb_index = 0;
|
||||
|
||||
@@ -213,6 +204,13 @@ bool GSDeviceOGL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
Console.WriteLn("GL: Not using shader cache.");
|
||||
}
|
||||
|
||||
// On GLES drivers which support KHR_parallel_shader_compile, allow the driver to use more
|
||||
// threads for shader compilation to reduce stutter.
|
||||
if (m_is_gles && GLAD_GL_KHR_parallel_shader_compile)
|
||||
{
|
||||
glMaxShaderCompilerThreadsKHR(4);
|
||||
}
|
||||
|
||||
// because of fbo bindings below...
|
||||
GLState::Clear();
|
||||
|
||||
@@ -494,8 +492,8 @@ bool GSDeviceOGL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
if (!CompileShadeBoostProgram() || !CompileFXAAProgram())
|
||||
return false;
|
||||
|
||||
// Image load store and GLSL 420pack is core in GL4.2, no need to check.
|
||||
m_features.cas_sharpening = ((GLAD_GL_VERSION_4_2 && GLAD_GL_ARB_compute_shader) || GLAD_GL_ES_VERSION_3_2) && CreateCASPrograms();
|
||||
// Enable CAS when compute is available (GL 4.2+ or GLES 3.1+).
|
||||
m_features.cas_sharpening = ((GLAD_GL_VERSION_4_2 && GLAD_GL_ARB_compute_shader) || GLAD_GL_ES_VERSION_3_1) && CreateCASPrograms();
|
||||
|
||||
// ****************************************************************
|
||||
// rasterization configuration
|
||||
@@ -635,44 +633,39 @@ bool GSDeviceOGL::CheckFeatures(bool& buggy_pbo)
|
||||
//bool vendor_id_amd = false;
|
||||
bool vendor_id_nvidia = false;
|
||||
//bool vendor_id_intel = false;
|
||||
bool vendor_id_mali = false;
|
||||
bool vendor_id_adreno = false;
|
||||
|
||||
const char* vendor = (const char*)glGetString(GL_VENDOR);
|
||||
const char* renderer = (const char*)glGetString(GL_RENDERER);
|
||||
const std::string vendor_str = vendor ? vendor : "";
|
||||
const std::string renderer_str = renderer ? renderer : "";
|
||||
const auto to_lower = [](std::string s) {
|
||||
for (char& c : s)
|
||||
c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||
return s;
|
||||
};
|
||||
const std::string vendor_lower = to_lower(vendor_str);
|
||||
const std::string renderer_lower = to_lower(renderer_str);
|
||||
|
||||
// Detect Mali GPU
|
||||
bool vendor_id_arm_mali = (vendor_lower.find("arm") != std::string::npos ||
|
||||
renderer_lower.find("mali") != std::string::npos);
|
||||
|
||||
if (vendor_lower.find("advanced micro devices") != std::string::npos ||
|
||||
vendor_lower.find("ati technologies inc.") != std::string::npos ||
|
||||
vendor_lower.find("ati") != std::string::npos)
|
||||
if (std::strstr(vendor, "Advanced Micro Devices") || std::strstr(vendor, "ATI Technologies Inc.") ||
|
||||
std::strstr(vendor, "ATI"))
|
||||
{
|
||||
Console.WriteLn(Color_StrongRed, "GL: AMD GPU detected.");
|
||||
//vendor_id_amd = true;
|
||||
}
|
||||
else if (vendor_lower.find("nvidia corporation") != std::string::npos || vendor_lower.find("nvidia") != std::string::npos)
|
||||
else if (std::strstr(vendor, "NVIDIA Corporation"))
|
||||
{
|
||||
Console.WriteLn(Color_StrongGreen, "GL: NVIDIA GPU detected.");
|
||||
vendor_id_nvidia = true;
|
||||
}
|
||||
else if (vendor_lower.find("intel") != std::string::npos)
|
||||
else if (std::strstr(vendor, "Intel"))
|
||||
{
|
||||
Console.WriteLn(Color_StrongBlue, "GL: Intel GPU detected.");
|
||||
//vendor_id_intel = true;
|
||||
}
|
||||
else if (vendor_id_arm_mali)
|
||||
else if (std::strstr(vendor, "ARM") || std::strstr(renderer, "Mali"))
|
||||
{
|
||||
Console.WriteLn(Color_StrongYellow, "GL: ARM Mali GPU detected - applying workarounds");
|
||||
Console.WriteLn(Color_Yellow, "GL: ARM Mali GPU detected.");
|
||||
vendor_id_mali = true;
|
||||
}
|
||||
else if (std::strstr(vendor, "Qualcomm") || std::strstr(renderer, "Adreno"))
|
||||
{
|
||||
Console.WriteLn(Color_Cyan, "GL: Qualcomm Adreno GPU detected.");
|
||||
vendor_id_adreno = true;
|
||||
}
|
||||
|
||||
GLint major_gl = 0;
|
||||
GLint minor_gl = 0;
|
||||
glGetIntegerv(GL_MAJOR_VERSION, &major_gl);
|
||||
@@ -736,9 +729,7 @@ bool GSDeviceOGL::CheckFeatures(bool& buggy_pbo)
|
||||
if (!GLAD_GL_ARB_texture_barrier)
|
||||
{
|
||||
glTextureBarrier = ReplaceGL::TextureBarrier;
|
||||
// OSD message disabled: GL_ARB_texture_barrier warning
|
||||
// Host::AddOSDMessage(
|
||||
// "GL_ARB_texture_barrier is not supported, blending will not be accurate.", Host::OSD_ERROR_DURATION);
|
||||
// Suppressed: frequent warning on mobile drivers where fallback paths are already handled.
|
||||
}
|
||||
|
||||
if (!GLAD_GL_ARB_direct_state_access)
|
||||
@@ -752,33 +743,14 @@ bool GSDeviceOGL::CheckFeatures(bool& buggy_pbo)
|
||||
if (!m_is_gles) {
|
||||
buggy_pbo = !GLAD_GL_VERSION_4_4 && !GLAD_GL_ARB_buffer_storage && !GLAD_GL_EXT_buffer_storage;
|
||||
} else {
|
||||
buggy_pbo = !GLAD_GL_EXT_buffer_storage;
|
||||
buggy_pbo = GLAD_GL_EXT_buffer_storage;
|
||||
}
|
||||
|
||||
// Mali GPU workarounds - force PBO off and disable problematic features
|
||||
if (vendor_id_arm_mali)
|
||||
{
|
||||
Console.WriteLn(Color_StrongYellow, "GL: Applying Mali GPU workarounds:");
|
||||
Console.WriteLn(" - Disabling framebuffer fetch");
|
||||
Console.WriteLn(" - Enabling texture barriers");
|
||||
Console.WriteLn(" - Disabling vertex shader expansion");
|
||||
Console.WriteLn(" - Disabling PBO for texture uploads");
|
||||
Console.WriteLn(" - Disabling PBO for texture downloads");
|
||||
Console.WriteLn(" - Disabling point expand");
|
||||
|
||||
buggy_pbo = true;
|
||||
m_disable_download_pbo = true;
|
||||
|
||||
Console.WriteLn("GL: Mali workarounds applied. Textures will use direct upload path.");
|
||||
}
|
||||
|
||||
if (buggy_pbo)
|
||||
Console.Warning("GL: Not using PBOs for texture uploads because buffer_storage is unavailable.");
|
||||
|
||||
// Give the user the option to disable PBO usage for downloads.
|
||||
// Most drivers seem to be faster with PBO.
|
||||
if (!vendor_id_arm_mali)
|
||||
m_disable_download_pbo = Host::GetBoolSettingValue("EmuCore/GS", "DisableGLDownloadPBO", false);
|
||||
m_disable_download_pbo = Host::GetBoolSettingValue("EmuCore/GS", "DisableGLDownloadPBO", false);
|
||||
if (m_disable_download_pbo)
|
||||
Console.Warning("GL: Not using PBOs for texture downloads, this may reduce performance.");
|
||||
|
||||
@@ -787,14 +759,6 @@ bool GSDeviceOGL::CheckFeatures(bool& buggy_pbo)
|
||||
m_features.primitive_id = true;
|
||||
|
||||
m_features.framebuffer_fetch = GLAD_GL_EXT_shader_framebuffer_fetch;
|
||||
|
||||
// Disable framebuffer fetch on Mali - causes 2D graphics issues
|
||||
if (vendor_id_arm_mali && m_features.framebuffer_fetch)
|
||||
{
|
||||
Console.WriteLn("GL: Disabling framebuffer fetch on Mali GPU (causes rendering issues)");
|
||||
m_features.framebuffer_fetch = false;
|
||||
}
|
||||
|
||||
if (m_features.framebuffer_fetch && GSConfig.DisableFramebufferFetch)
|
||||
{
|
||||
Host::AddOSDMessage(
|
||||
@@ -802,19 +766,15 @@ bool GSDeviceOGL::CheckFeatures(bool& buggy_pbo)
|
||||
m_features.framebuffer_fetch = false;
|
||||
}
|
||||
|
||||
const bool has_texture_barrier =
|
||||
GLAD_GL_ARB_texture_barrier || GLAD_GL_EXT_texture_barrier || GLAD_GL_OES_texture_barrier;
|
||||
if (GSConfig.OverrideTextureBarriers == 0)
|
||||
m_features.texture_barrier = m_features.framebuffer_fetch; // Force Disabled
|
||||
else if (GSConfig.OverrideTextureBarriers == 1)
|
||||
m_features.texture_barrier = true; // Force Enabled
|
||||
else
|
||||
m_features.texture_barrier = m_features.framebuffer_fetch || has_texture_barrier;
|
||||
m_features.texture_barrier = m_features.framebuffer_fetch || GLAD_GL_ARB_texture_barrier;
|
||||
if (!m_features.texture_barrier)
|
||||
{
|
||||
// OSD message disabled: GL_ARB_texture_barrier warning
|
||||
// Host::AddOSDMessage(
|
||||
// "GL_ARB_texture_barrier is not supported, blending will not be accurate.", Host::OSD_ERROR_DURATION);
|
||||
// Suppressed: frequent warning on mobile drivers where fallback paths are already handled.
|
||||
}
|
||||
|
||||
m_features.provoking_vertex_last = true;
|
||||
@@ -832,6 +792,36 @@ bool GSDeviceOGL::CheckFeatures(bool& buggy_pbo)
|
||||
if (buggy_vs_expand)
|
||||
Console.Warning("GL: Disabling vertex shader expand due to broken NVIDIA driver.");
|
||||
|
||||
// Mali GPU optimizations for tile-based rendering architecture
|
||||
if (vendor_id_mali)
|
||||
{
|
||||
Console.WriteLn(Color_Yellow, "GL: Applying Mali-specific optimizations for tile-based rendering.");
|
||||
// Enable early-Z and avoid unnecessary discard operations
|
||||
m_features.prefer_new_textures = true;
|
||||
m_features.framebuffer_fetch = GLAD_GL_EXT_shader_pixel_local_storage | GLAD_GL_ARM_shader_framebuffer_fetch | GLAD_GL_EXT_shader_framebuffer_fetch;
|
||||
// Mali benefits from reduced texture barrier usage due to tile memory
|
||||
if (GSConfig.OverrideTextureBarriers == -1) // If not explicitly set
|
||||
{
|
||||
m_features.texture_barrier = m_features.framebuffer_fetch;
|
||||
Console.WriteLn("GL: Mali optimization - using framebuffer fetch over texture barriers when available.");
|
||||
}
|
||||
}
|
||||
|
||||
// Adreno GPU optimizations for Qualcomm's architecture
|
||||
if (vendor_id_adreno)
|
||||
{
|
||||
Console.WriteLn(Color_Cyan, "GL: Applying Adreno-specific optimizations for Qualcomm GPU.");
|
||||
// Adreno benefits from reduced bandwidth and optimized memory patterns
|
||||
m_features.prefer_new_textures = true;
|
||||
// Adreno has efficient compression, enable when available
|
||||
if (m_features.bptc_textures)
|
||||
{
|
||||
Console.WriteLn("GL: Adreno optimization - leveraging BPTC texture compression.");
|
||||
}
|
||||
// Reduce unnecessary state changes for Adreno's command processor
|
||||
Console.WriteLn("GL: Adreno optimization - minimizing state changes for improved performance.");
|
||||
}
|
||||
|
||||
if (GLAD_GL_ARB_shader_storage_buffer_object)
|
||||
{
|
||||
GLint max_vertex_ssbos = 0;
|
||||
@@ -1425,14 +1415,10 @@ std::string GSDeviceOGL::GenGlslHeader(const std::string_view entry, GLenum type
|
||||
else
|
||||
header += "#define HAS_FRAMEBUFFER_FETCH 0\n";
|
||||
|
||||
if (GLAD_GL_ARB_clip_control)
|
||||
{
|
||||
header += "#define HAS_CLIP_CONTROL 1\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
header += "#define HAS_CLIP_CONTROL 0\n";
|
||||
}
|
||||
if (GLAD_GL_ARB_clip_control)
|
||||
header += "#define HAS_CLIP_CONTROL 1\n";
|
||||
else
|
||||
header += "#define HAS_CLIP_CONTROL 0\n";
|
||||
|
||||
// Allow to puts several shader in 1 files
|
||||
switch (type)
|
||||
@@ -2140,36 +2126,53 @@ void GSDeviceOGL::ClearSamplerCache()
|
||||
|
||||
bool GSDeviceOGL::CreateCASPrograms()
|
||||
{
|
||||
std::optional<std::string> cas_source = ReadShaderSource("shaders/opengl/cas.glsl");
|
||||
if (!cas_source.has_value() || !GetCASShaderSource(&cas_source.value()))
|
||||
{
|
||||
m_features.cas_sharpening = false;
|
||||
return false;
|
||||
}
|
||||
std::optional<std::string> cas_source = ReadShaderSource("shaders/opengl/cas.glsl");
|
||||
if (!cas_source.has_value() || !GetCASShaderSource(&cas_source.value()))
|
||||
{
|
||||
m_features.cas_sharpening = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* header =
|
||||
"#version 420\n"
|
||||
"#extension GL_ARB_compute_shader : require\n";
|
||||
const char* sharpen_params[2] = {
|
||||
"#define CAS_SHARPEN_ONLY false\n",
|
||||
"#define CAS_SHARPEN_ONLY true\n"};
|
||||
// Build an appropriate GLSL header for desktop GL vs GLES.
|
||||
std::string header;
|
||||
if (m_is_gles)
|
||||
{
|
||||
if (GLAD_GL_ES_VERSION_3_2)
|
||||
header = "#version 320 es\n";
|
||||
else if (GLAD_GL_ES_VERSION_3_1)
|
||||
header = "#version 310 es\n";
|
||||
else
|
||||
{
|
||||
m_features.cas_sharpening = false;
|
||||
return false;
|
||||
}
|
||||
// No extension needed for compute on GLES 3.1/3.2.
|
||||
}
|
||||
else
|
||||
{
|
||||
header = "#version 420\n#extension GL_ARB_compute_shader : require\n";
|
||||
}
|
||||
|
||||
if (!m_shader_cache.GetComputeProgram(&m_cas.upscale_ps, fmt::format("{}{}{}", header, sharpen_params[0], cas_source.value())) ||
|
||||
!m_shader_cache.GetComputeProgram(&m_cas.sharpen_ps, fmt::format("{}{}{}", header, sharpen_params[1], cas_source.value())))
|
||||
{
|
||||
m_features.cas_sharpening = false;
|
||||
return false;
|
||||
}
|
||||
const char* sharpen_params[2] = {
|
||||
"#define CAS_SHARPEN_ONLY false\n",
|
||||
"#define CAS_SHARPEN_ONLY true\n"};
|
||||
|
||||
const auto link_uniforms = [](GLProgram& prog) {
|
||||
prog.RegisterUniform("const0");
|
||||
prog.RegisterUniform("const1");
|
||||
prog.RegisterUniform("srcOffset");
|
||||
};
|
||||
link_uniforms(m_cas.upscale_ps);
|
||||
link_uniforms(m_cas.sharpen_ps);
|
||||
if (!m_shader_cache.GetComputeProgram(&m_cas.upscale_ps, fmt::format("{}{}{}", header, sharpen_params[0], cas_source.value())) ||
|
||||
!m_shader_cache.GetComputeProgram(&m_cas.sharpen_ps, fmt::format("{}{}{}", header, sharpen_params[1], cas_source.value())))
|
||||
{
|
||||
m_features.cas_sharpening = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
const auto link_uniforms = [](GLProgram& prog) {
|
||||
prog.RegisterUniform("const0");
|
||||
prog.RegisterUniform("const1");
|
||||
prog.RegisterUniform("srcOffset");
|
||||
};
|
||||
link_uniforms(m_cas.upscale_ps);
|
||||
link_uniforms(m_cas.sharpen_ps);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSDeviceOGL::DoCAS(GSTexture* sTex, GSTexture* dTex, bool sharpen_only, const std::array<u32, NUM_CAS_CONSTANTS>& constants)
|
||||
|
||||
@@ -83,7 +83,6 @@ static std::mutex s_instance_mutex;
|
||||
|
||||
// Device extensions that are required for PCSX2.
|
||||
static constexpr const char* s_required_device_extensions[] = {
|
||||
VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME,
|
||||
VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME,
|
||||
};
|
||||
|
||||
@@ -114,17 +113,7 @@ VkInstance GSDeviceVK::CreateVulkanInstance(const WindowInfo& wi, OptionalExtens
|
||||
app_info.pEngineName = "PCSX2";
|
||||
app_info.engineVersion = VK_MAKE_VERSION(
|
||||
BuildVersion::GitTagHi, BuildVersion::GitTagMid, BuildVersion::GitTagLo);
|
||||
// Prefer a newer Vulkan API when available, but clamp to loader support.
|
||||
// This unlocks newer features on capable drivers without breaking older ones.
|
||||
uint32_t loader_api_version = VK_API_VERSION_1_1;
|
||||
if (vkEnumerateInstanceVersion)
|
||||
{
|
||||
uint32_t ver = 0;
|
||||
if (vkEnumerateInstanceVersion(&ver) == VK_SUCCESS && ver != 0)
|
||||
loader_api_version = ver;
|
||||
}
|
||||
const uint32_t desired_api_version = VK_API_VERSION_1_3; // headers provide up to 1.4, 1.3 is widely supported
|
||||
app_info.apiVersion = (loader_api_version < desired_api_version) ? loader_api_version : desired_api_version;
|
||||
app_info.apiVersion = VK_API_VERSION_1_1;
|
||||
|
||||
VkInstanceCreateInfo instance_create_info = {};
|
||||
instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
@@ -434,6 +423,7 @@ bool GSDeviceVK::SelectDeviceExtensions(ExtensionList* extension_list, bool enab
|
||||
SupportsExtension(VK_EXT_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_ext_line_rasterization = SupportsExtension(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME,
|
||||
require_line_rasterization);
|
||||
m_optional_extensions.vk_khr_push_descriptor = SupportsExtension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_khr_driver_properties = SupportsExtension(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, false);
|
||||
|
||||
// glslang generates debug info instructions before phi nodes at the beginning of blocks when non-semantic debug info
|
||||
@@ -764,19 +754,27 @@ bool GSDeviceVK::ProcessDeviceExtensions()
|
||||
Vulkan::AddPointerToChain(&properties2, &m_device_driver_properties);
|
||||
}
|
||||
|
||||
VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor_properties = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR};
|
||||
Vulkan::AddPointerToChain(&properties2, &push_descriptor_properties);
|
||||
|
||||
// query
|
||||
vkGetPhysicalDeviceProperties2(m_physical_device, &properties2);
|
||||
|
||||
// confirm we actually support it
|
||||
if (push_descriptor_properties.maxPushDescriptors < NUM_TFX_TEXTURES)
|
||||
if (m_optional_extensions.vk_khr_push_descriptor)
|
||||
{
|
||||
Console.Error("VK: maxPushDescriptors (%u) is below required (%u)", push_descriptor_properties.maxPushDescriptors,
|
||||
NUM_TFX_TEXTURES);
|
||||
return false;
|
||||
VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor_properties = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR};
|
||||
Vulkan::AddPointerToChain(&properties2, &push_descriptor_properties);
|
||||
|
||||
// query
|
||||
vkGetPhysicalDeviceProperties2(m_physical_device, &properties2);
|
||||
|
||||
// If the device advertises fewer push descriptors than required, disable push-descriptor
|
||||
// usage and continue with a fallback.
|
||||
if (push_descriptor_properties.maxPushDescriptors < NUM_TFX_TEXTURES)
|
||||
{
|
||||
Console.Warning("VK: push descriptors available but maxPushDescriptors (%u) < required (%u). Disabling push descriptors.",
|
||||
push_descriptor_properties.maxPushDescriptors, NUM_TFX_TEXTURES);
|
||||
m_optional_extensions.vk_khr_push_descriptor = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vkGetPhysicalDeviceProperties2(m_physical_device, &properties2);
|
||||
}
|
||||
|
||||
if (!line_rasterization_feature.bresenhamLines)
|
||||
@@ -917,7 +915,9 @@ bool GSDeviceVK::CreateCommandBuffers()
|
||||
resources.needs_fence_wait = false;
|
||||
|
||||
VkCommandPoolCreateInfo pool_info = {
|
||||
VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, nullptr, 0, m_graphics_queue_family_index};
|
||||
VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, nullptr,
|
||||
VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
|
||||
m_graphics_queue_family_index};
|
||||
res = vkCreateCommandPool(m_device, &pool_info, nullptr, &resources.command_pool);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
@@ -961,13 +961,18 @@ bool GSDeviceVK::CreateCommandBuffers()
|
||||
bool GSDeviceVK::CreateGlobalDescriptorPool()
|
||||
{
|
||||
static constexpr const VkDescriptorPoolSize pool_sizes[] = {
|
||||
{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 2},
|
||||
{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2},
|
||||
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, MAX_COMBINED_IMAGE_SAMPLER_DESCRIPTORS_PER_FRAME },
|
||||
{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, MAX_SAMPLED_IMAGE_DESCRIPTORS_PER_FRAME },
|
||||
{ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, MAX_STORAGE_IMAGE_DESCRIPTORS_PER_FRAME },
|
||||
{ VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, MAX_INPUT_ATTACHMENT_IMAGE_DESCRIPTORS_PER_FRAME },
|
||||
{ VK_DESCRIPTOR_TYPE_SAMPLER, MAX_COMBINED_IMAGE_SAMPLER_DESCRIPTORS_PER_FRAME },
|
||||
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, MAX_DESCRIPTOR_SETS_PER_FRAME },
|
||||
{ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, MAX_DESCRIPTOR_SETS_PER_FRAME }
|
||||
};
|
||||
|
||||
VkDescriptorPoolCreateInfo pool_create_info = {VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, nullptr,
|
||||
VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
|
||||
1024, // TODO: tweak this
|
||||
MAX_DESCRIPTOR_SETS_PER_FRAME, // TODO: tweak this
|
||||
static_cast<u32>(std::size(pool_sizes)), pool_sizes};
|
||||
|
||||
VkResult res = vkCreateDescriptorPool(m_device, &pool_create_info, nullptr, &m_global_descriptor_pool);
|
||||
@@ -1726,8 +1731,9 @@ bool GSDeviceVK::InitSpinResources()
|
||||
for (SpinResources& resources : m_spin_resources)
|
||||
{
|
||||
u32 index = &resources - &m_spin_resources[0];
|
||||
VkCommandPoolCreateInfo pool_info = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO};
|
||||
pool_info.queueFamilyIndex = m_spin_queue_family_index;
|
||||
VkCommandPoolCreateInfo pool_info = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO};
|
||||
pool_info.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||
pool_info.queueFamilyIndex = m_spin_queue_family_index;
|
||||
CHECKED_CREATE(vkCreateCommandPool, &pool_info, &resources.command_pool);
|
||||
Vulkan::SetObjectName(m_device, resources.command_pool, "Spin Command Pool %u", index);
|
||||
|
||||
@@ -1988,7 +1994,7 @@ bool GSDeviceVK::AllocatePreinitializedGPUBuffer(u32 size, VkBuffer* gpu_buffer,
|
||||
}
|
||||
|
||||
const VkBufferCreateInfo gpu_bci = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, nullptr, 0, size,
|
||||
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_SHARING_MODE_EXCLUSIVE};
|
||||
(gpu_usage | VK_BUFFER_USAGE_TRANSFER_DST_BIT), VK_SHARING_MODE_EXCLUSIVE};
|
||||
const VmaAllocationCreateInfo gpu_aci = {0, VMA_MEMORY_USAGE_GPU_ONLY, 0, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT};
|
||||
VmaAllocationInfo ai;
|
||||
res = vmaCreateBuffer(m_allocator, &gpu_bci, &gpu_aci, gpu_buffer, gpu_allocation, &ai);
|
||||
@@ -2001,7 +2007,11 @@ bool GSDeviceVK::AllocatePreinitializedGPUBuffer(u32 size, VkBuffer* gpu_buffer,
|
||||
|
||||
const VkBufferCopy buf_copy = {0u, 0u, size};
|
||||
fill_callback(cpu_ai.pMappedData);
|
||||
vmaFlushAllocation(m_allocator, cpu_allocation, 0, size);
|
||||
// Avoid redundant flush if staging memory is HOST_COHERENT
|
||||
VkMemoryPropertyFlags mem_props = 0;
|
||||
vmaGetAllocationMemoryProperties(m_allocator, cpu_allocation, &mem_props);
|
||||
if ((mem_props & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0)
|
||||
vmaFlushAllocation(m_allocator, cpu_allocation, 0, size);
|
||||
vkCmdCopyBuffer(GetCurrentInitCommandBuffer(), cpu_buffer, *gpu_buffer, 1, &buf_copy);
|
||||
DeferBufferDestruction(cpu_buffer, cpu_allocation);
|
||||
return true;
|
||||
@@ -2624,7 +2634,7 @@ bool GSDeviceVK::CreateDeviceAndSwapChain()
|
||||
bool GSDeviceVK::CheckFeatures()
|
||||
{
|
||||
const VkPhysicalDeviceLimits& limits = m_device_properties.limits;
|
||||
//const u32 vendorID = m_device_properties.vendorID;
|
||||
const u32 vendorID = m_device_properties.vendorID;
|
||||
//const bool isAMD = (vendorID == 0x1002 || vendorID == 0x1022);
|
||||
//const bool isNVIDIA = (vendorID == 0x10DE);
|
||||
|
||||
@@ -2667,6 +2677,15 @@ bool GSDeviceVK::CheckFeatures()
|
||||
m_features.line_expand =
|
||||
(m_device_features.wideLines && limits.lineWidthRange[0] <= f_upscale && limits.lineWidthRange[1] >= f_upscale);
|
||||
|
||||
// Mobile GPUs (Adreno/Mali) often emulate wide lines/points expensively; prefer vertex expansion there.
|
||||
if (vendorID == 0x5143u || vendorID == 0x13B5u)
|
||||
{
|
||||
if (m_features.point_expand || m_features.line_expand)
|
||||
Console.WriteLn("VK: Forcing vertex-based expansion for points/lines on mobile GPU (vendor 0x%X).", vendorID);
|
||||
m_features.point_expand = false;
|
||||
m_features.line_expand = false;
|
||||
}
|
||||
|
||||
DevCon.WriteLn("Optional features:%s%s%s%s%s", m_features.primitive_id ? " primitive_id" : "",
|
||||
m_features.texture_barrier ? " texture_barrier" : "", m_features.framebuffer_fetch ? " framebuffer_fetch" : "",
|
||||
m_features.provoking_vertex_last ? " provoking_vertex_last" : "", m_features.vs_expand ? " vs_expand" : "");
|
||||
@@ -3582,6 +3601,9 @@ VkSampler GSDeviceVK::GetSampler(GSHWDrawConfig::SamplerSelector ss)
|
||||
return it->second;
|
||||
|
||||
const bool aniso = (ss.aniso && GSConfig.MaxAnisotropy > 1 && m_device_features.samplerAnisotropy);
|
||||
const float max_supported_aniso = m_device_features.samplerAnisotropy ?
|
||||
std::max(1.0f, static_cast<float>(m_device_properties.limits.maxSamplerAnisotropy)) : 1.0f;
|
||||
const float aniso_value = aniso ? std::min(static_cast<float>(GSConfig.MaxAnisotropy), max_supported_aniso) : 1.0f;
|
||||
|
||||
// See https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkSamplerCreateInfo.html#_description
|
||||
// for the reasoning behind 0.25f here.
|
||||
@@ -3596,8 +3618,8 @@ VkSampler GSDeviceVK::GetSampler(GSHWDrawConfig::SamplerSelector ss)
|
||||
ss.tav ? VK_SAMPLER_ADDRESS_MODE_REPEAT : VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE), // v
|
||||
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // w
|
||||
0.0f, // lod bias
|
||||
static_cast<VkBool32>(aniso), // anisotropy enable
|
||||
aniso ? static_cast<float>(GSConfig.MaxAnisotropy) : 1.0f, // anisotropy
|
||||
static_cast<VkBool32>(aniso), // anisotropy enable
|
||||
aniso_value, // anisotropy
|
||||
VK_FALSE, // compare enable
|
||||
VK_COMPARE_OP_ALWAYS, // compare op
|
||||
0.0f, // min lod
|
||||
@@ -3773,7 +3795,8 @@ bool GSDeviceVK::CreatePipelineLayouts()
|
||||
// Convert Pipeline Layout
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
dslb.SetPushFlag();
|
||||
if (m_optional_extensions.vk_khr_push_descriptor)
|
||||
dslb.SetPushFlag();
|
||||
dslb.AddBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, NUM_UTILITY_SAMPLERS, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
if ((m_utility_ds_layout = dslb.Create(dev)) == VK_NULL_HANDLE)
|
||||
return false;
|
||||
@@ -3797,7 +3820,8 @@ bool GSDeviceVK::CreatePipelineLayouts()
|
||||
return false;
|
||||
Vulkan::SetObjectName(dev, m_tfx_ubo_ds_layout, "TFX UBO descriptor layout");
|
||||
|
||||
dslb.SetPushFlag();
|
||||
if (m_optional_extensions.vk_khr_push_descriptor)
|
||||
dslb.SetPushFlag();
|
||||
dslb.AddBinding(TFX_TEXTURE_TEXTURE, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
dslb.AddBinding(TFX_TEXTURE_PALETTE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
dslb.AddBinding(TFX_TEXTURE_RT,
|
||||
@@ -4356,7 +4380,8 @@ bool GSDeviceVK::CompileCASPipelines()
|
||||
Vulkan::DescriptorSetLayoutBuilder dslb;
|
||||
Vulkan::PipelineLayoutBuilder plb;
|
||||
|
||||
dslb.SetPushFlag();
|
||||
if (m_optional_extensions.vk_khr_push_descriptor)
|
||||
dslb.SetPushFlag();
|
||||
dslb.AddBinding(0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT);
|
||||
dslb.AddBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT);
|
||||
if ((m_cas_ds_layout = dslb.Create(dev)) == VK_NULL_HANDLE)
|
||||
@@ -4563,7 +4588,25 @@ bool GSDeviceVK::DoCAS(
|
||||
Vulkan::DescriptorSetUpdateBuilder dsub;
|
||||
dsub.AddImageDescriptorWrite(VK_NULL_HANDLE, 0, sTexVK->GetView(), sTexVK->GetVkLayout());
|
||||
dsub.AddStorageImageDescriptorWrite(VK_NULL_HANDLE, 1, dTexVK->GetView(), dTexVK->GetVkLayout());
|
||||
dsub.PushUpdate(cmdbuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_cas_pipeline_layout, 0, false);
|
||||
if (m_optional_extensions.vk_khr_push_descriptor)
|
||||
{
|
||||
dsub.PushUpdate(cmdbuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_cas_pipeline_layout, 0, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
VkDescriptorSet tmp = AllocatePersistentDescriptorSet(m_cas_ds_layout);
|
||||
if (tmp != VK_NULL_HANDLE)
|
||||
{
|
||||
dsub.UpdateToDescriptorSet(m_device, tmp, true);
|
||||
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_cas_pipeline_layout, 0, 1, &tmp, 0, nullptr);
|
||||
FrameResources& fres = m_frame_resources[m_current_frame];
|
||||
fres.cleanup_resources.push_back([this, tmp]() { vkFreeDescriptorSets(m_device, m_global_descriptor_pool, 1, &tmp); });
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error("VK: Failed to allocate fallback descriptor set for CAS push-descriptor emulation.");
|
||||
}
|
||||
}
|
||||
|
||||
// the actual meat and potatoes! only four commands.
|
||||
static const int threadGroupWorkRegionDim = 16;
|
||||
@@ -5447,7 +5490,26 @@ bool GSDeviceVK::ApplyTFXState(bool already_execed)
|
||||
m_tfx_textures[TFX_TEXTURE_PRIMID]->GetView(), m_tfx_textures[TFX_TEXTURE_PRIMID]->GetVkLayout());
|
||||
}
|
||||
|
||||
dsub.PushUpdate(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_tfx_pipeline_layout, TFX_DESCRIPTOR_SET_TEXTURES);
|
||||
if (m_optional_extensions.vk_khr_push_descriptor)
|
||||
{
|
||||
dsub.PushUpdate(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_tfx_pipeline_layout, TFX_DESCRIPTOR_SET_TEXTURES);
|
||||
}
|
||||
else
|
||||
{
|
||||
VkDescriptorSet tmp = AllocatePersistentDescriptorSet(m_tfx_texture_ds_layout);
|
||||
if (tmp != VK_NULL_HANDLE)
|
||||
{
|
||||
dsub.UpdateToDescriptorSet(m_device, tmp, true);
|
||||
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_tfx_pipeline_layout,
|
||||
TFX_DESCRIPTOR_SET_TEXTURES, 1, &tmp, 0, nullptr);
|
||||
FrameResources& fres = m_frame_resources[m_current_frame];
|
||||
fres.cleanup_resources.push_back([this, tmp]() { vkFreeDescriptorSets(m_device, m_global_descriptor_pool, 1, &tmp); });
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error("VK: Failed to allocate fallback descriptor set for TFX push-descriptor emulation.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ApplyBaseState(flags, cmdbuf);
|
||||
@@ -5470,7 +5532,25 @@ bool GSDeviceVK::ApplyUtilityState(bool already_execed)
|
||||
Vulkan::DescriptorSetUpdateBuilder dsub;
|
||||
dsub.AddCombinedImageSamplerDescriptorWrite(
|
||||
VK_NULL_HANDLE, 0, m_utility_texture->GetView(), m_utility_sampler, m_utility_texture->GetVkLayout());
|
||||
dsub.PushUpdate(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_utility_pipeline_layout, 0, false);
|
||||
if (m_optional_extensions.vk_khr_push_descriptor)
|
||||
{
|
||||
dsub.PushUpdate(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_utility_pipeline_layout, 0, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
VkDescriptorSet tmp = AllocatePersistentDescriptorSet(m_utility_ds_layout);
|
||||
if (tmp != VK_NULL_HANDLE)
|
||||
{
|
||||
dsub.UpdateToDescriptorSet(m_device, tmp, true);
|
||||
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_utility_pipeline_layout, 0, 1, &tmp, 0, nullptr);
|
||||
FrameResources& fres = m_frame_resources[m_current_frame];
|
||||
fres.cleanup_resources.push_back([this, tmp]() { vkFreeDescriptorSets(m_device, m_global_descriptor_pool, 1, &tmp); });
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error("VK: Failed to allocate fallback descriptor set for utility push-descriptor emulation.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ public:
|
||||
|
||||
struct OptionalExtensions
|
||||
{
|
||||
bool vk_khr_push_descriptor : 1;
|
||||
bool vk_ext_provoking_vertex : 1;
|
||||
bool vk_ext_memory_budget : 1;
|
||||
bool vk_ext_calibrated_timestamps : 1;
|
||||
@@ -208,6 +209,7 @@ private:
|
||||
{
|
||||
// [0] - Init (upload) command buffer, [1] - draw command buffer
|
||||
VkCommandPool command_pool = VK_NULL_HANDLE;
|
||||
VkDescriptorPool descriptor_pool = VK_NULL_HANDLE;
|
||||
std::array<VkCommandBuffer, 2> command_buffers{VK_NULL_HANDLE, VK_NULL_HANDLE};
|
||||
VkFence fence = VK_NULL_HANDLE;
|
||||
u64 fence_counter = 0;
|
||||
|
||||
@@ -299,7 +299,11 @@ VkBuffer GSTextureVK::AllocateUploadStagingBuffer(const void* data, u32 pitch, u
|
||||
|
||||
// And write the data.
|
||||
CopyTextureDataForUpload(ai.pMappedData, data, pitch, upload_pitch, height);
|
||||
vmaFlushAllocation(GSDeviceVK::GetInstance()->GetAllocator(), allocation, 0, size);
|
||||
// Avoid redundant flush if the staging memory is HOST_COHERENT
|
||||
VkMemoryPropertyFlags mem_props = 0;
|
||||
vmaGetAllocationMemoryProperties(GSDeviceVK::GetInstance()->GetAllocator(), allocation, &mem_props);
|
||||
if ((mem_props & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0)
|
||||
vmaFlushAllocation(GSDeviceVK::GetInstance()->GetAllocator(), allocation, 0, size);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
@@ -716,6 +716,19 @@ void Vulkan::DescriptorSetUpdateBuilder::Update(VkDevice device, bool clear /*=
|
||||
Clear();
|
||||
}
|
||||
|
||||
void Vulkan::DescriptorSetUpdateBuilder::UpdateToDescriptorSet(VkDevice device, VkDescriptorSet dst_set, bool clear /*= true*/)
|
||||
{
|
||||
pxAssert(m_num_writes > 0);
|
||||
|
||||
for (u32 i = 0; i < m_num_writes; ++i)
|
||||
m_writes[i].dstSet = dst_set;
|
||||
|
||||
vkUpdateDescriptorSets(device, m_num_writes, (m_num_writes > 0) ? m_writes.data() : nullptr, 0, nullptr);
|
||||
|
||||
if (clear)
|
||||
Clear();
|
||||
}
|
||||
|
||||
void Vulkan::DescriptorSetUpdateBuilder::PushUpdate(
|
||||
VkCommandBuffer cmdbuf, VkPipelineBindPoint bind_point, VkPipelineLayout layout, u32 set, bool clear /*= true*/)
|
||||
{
|
||||
|
||||
@@ -237,6 +237,7 @@ namespace Vulkan
|
||||
void Clear();
|
||||
|
||||
void Update(VkDevice device, bool clear = true);
|
||||
void UpdateToDescriptorSet(VkDevice device, VkDescriptorSet dst_set, bool clear = true);
|
||||
void PushUpdate(VkCommandBuffer cmdbuf, VkPipelineBindPoint bind_point, VkPipelineLayout layout, u32 set,
|
||||
bool clear = true);
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include "common/Console.h"
|
||||
#include "common/DynamicLibrary.h"
|
||||
#include "common/Error.h"
|
||||
#include "pcsx2/Config.h"
|
||||
#include "GS/GS.h"
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
@@ -14,6 +16,13 @@
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#ifdef USE_ADRENOTOOLS
|
||||
#include <adrenotools/driver.h>
|
||||
#endif
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
|
||||
#define VULKAN_MODULE_ENTRY_POINT(name, required) PFN_##name name;
|
||||
@@ -47,22 +56,153 @@ bool Vulkan::LoadVulkanLibrary(Error* error)
|
||||
{
|
||||
pxAssertRel(!s_vulkan_library.IsOpen(), "Vulkan module is not loaded.");
|
||||
|
||||
// Check for custom driver path from config
|
||||
std::string custom_driver_path;
|
||||
if (GSConfig.CustomDriverPath.empty())
|
||||
{
|
||||
char* libvulkan_env = getenv("LIBVULKAN_PATH");
|
||||
if (libvulkan_env)
|
||||
custom_driver_path = libvulkan_env;
|
||||
#if defined(USE_ADRENOTOOLS) && defined(__ANDROID__)
|
||||
if (custom_driver_path.empty())
|
||||
{
|
||||
char* adreno_tools_path = getenv("ADRENOTOOLS_LIBVULKAN_PATH");
|
||||
if (adreno_tools_path)
|
||||
custom_driver_path = adreno_tools_path;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
custom_driver_path = GSConfig.CustomDriverPath;
|
||||
}
|
||||
|
||||
// Try to load custom driver if specified
|
||||
if (!custom_driver_path.empty())
|
||||
{
|
||||
#if defined(__ANDROID__) && defined(USE_ADRENOTOOLS)
|
||||
std::string custom_driver_dir;
|
||||
std::string custom_driver_name;
|
||||
|
||||
size_t last_slash = custom_driver_path.find_last_of("/\\");
|
||||
if (last_slash != std::string::npos)
|
||||
{
|
||||
custom_driver_dir = custom_driver_path.substr(0, last_slash + 1);
|
||||
custom_driver_name = custom_driver_path.substr(last_slash + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
custom_driver_name = custom_driver_path;
|
||||
}
|
||||
|
||||
const char* hook_lib_dir = getenv("ANDROID_NATIVE_LIB_DIR");
|
||||
if (!hook_lib_dir)
|
||||
{
|
||||
hook_lib_dir = getenv("ANDROID_DATA_DIR");
|
||||
}
|
||||
|
||||
if (hook_lib_dir && !custom_driver_dir.empty() && !custom_driver_name.empty())
|
||||
{
|
||||
Console.WriteLn(Color_StrongGreen, "Vulkan: Using libadrenotools to load custom driver: %s from %s",
|
||||
custom_driver_name.c_str(), custom_driver_dir.c_str());
|
||||
|
||||
void* vulkan_handle = adrenotools_open_libvulkan(
|
||||
RTLD_NOW | RTLD_LOCAL, // dlopenMode
|
||||
ADRENOTOOLS_DRIVER_CUSTOM, // featureFlags
|
||||
nullptr, // tmpLibDir (nullptr for API 29+)
|
||||
hook_lib_dir, // hookLibDir
|
||||
custom_driver_dir.c_str(), // customDriverDir
|
||||
custom_driver_name.c_str(), // customDriverName
|
||||
nullptr, // fileRedirectDir
|
||||
nullptr // userMappingHandle
|
||||
);
|
||||
|
||||
if (vulkan_handle)
|
||||
{
|
||||
// Grab the handle from libadrenotools
|
||||
s_vulkan_library.Adopt(vulkan_handle);
|
||||
Console.WriteLn(Color_StrongGreen, "Vulkan: Successfully loaded custom driver via libadrenotools");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Warning("Vulkan: libadrenotools failed to load custom driver, falling back to direct loading");
|
||||
// Fall through to direct loading
|
||||
if (s_vulkan_library.Open(custom_driver_path.c_str(), error))
|
||||
{
|
||||
Console.WriteLn(Color_StrongGreen, "Vulkan: Successfully loaded custom driver directly");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Warning("Vulkan: Failed to load custom driver from '%s', falling back to system driver", custom_driver_path.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Warning("Vulkan: libadrenotools requires ANDROID_NATIVE_LIB_DIR and valid custom driver path, falling back to direct loading");
|
||||
if (s_vulkan_library.Open(custom_driver_path.c_str(), error))
|
||||
{
|
||||
Console.WriteLn(Color_StrongGreen, "Vulkan: Successfully loaded custom driver directly");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Warning("Vulkan: Failed to load custom driver from '%s', falling back to system driver", custom_driver_path.c_str());
|
||||
}
|
||||
}
|
||||
#else
|
||||
// Loading without libadrenotools
|
||||
Console.WriteLn(Color_StrongGreen, "Vulkan: Attempting to load custom driver from: %s", custom_driver_path.c_str());
|
||||
if (s_vulkan_library.Open(custom_driver_path.c_str(), error))
|
||||
{
|
||||
Console.WriteLn(Color_StrongGreen, "Vulkan: Successfully loaded custom driver");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Warning("Vulkan: Failed to load custom driver from '%s', falling back to system driver", custom_driver_path.c_str());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
// Check if a path to a specific Vulkan library has been specified.
|
||||
char* libvulkan_env = getenv("LIBVULKAN_PATH");
|
||||
if (libvulkan_env)
|
||||
s_vulkan_library.Open(libvulkan_env, error);
|
||||
// On macOS, try MoltenVK if custom driver failed or wasn't specified
|
||||
if (!s_vulkan_library.IsOpen() &&
|
||||
!s_vulkan_library.Open(DynamicLibrary::GetVersionedFilename("MoltenVK").c_str(), error))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
// try versioned first, then unversioned.
|
||||
if (!s_vulkan_library.Open(DynamicLibrary::GetVersionedFilename("vulkan", 1).c_str(), error) &&
|
||||
!s_vulkan_library.Open(DynamicLibrary::GetVersionedFilename("vulkan").c_str(), error))
|
||||
// On other platforms, try versioned first, then unversioned system libraries
|
||||
if (!s_vulkan_library.IsOpen())
|
||||
{
|
||||
return false;
|
||||
#if defined(__ANDROID__)
|
||||
const char* android_native_lib_dir = getenv("ANDROID_NATIVE_LIB_DIR");
|
||||
if (android_native_lib_dir)
|
||||
{
|
||||
std::string custom_lib_path = std::string(android_native_lib_dir) + "/libvulkan.so";
|
||||
if (s_vulkan_library.Open(custom_lib_path.c_str(), error))
|
||||
{
|
||||
Console.WriteLn(Color_StrongGreen, "Vulkan: Loaded custom driver from app directory");
|
||||
}
|
||||
}
|
||||
|
||||
if (!s_vulkan_library.IsOpen())
|
||||
{
|
||||
if (!s_vulkan_library.Open("libvulkan.so", error))
|
||||
{
|
||||
if (!s_vulkan_library.Open(DynamicLibrary::GetVersionedFilename("vulkan", 1).c_str(), error) &&
|
||||
!s_vulkan_library.Open(DynamicLibrary::GetVersionedFilename("vulkan").c_str(), error))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (!s_vulkan_library.Open(DynamicLibrary::GetVersionedFilename("vulkan", 1).c_str(), error) &&
|
||||
!s_vulkan_library.Open(DynamicLibrary::GetVersionedFilename("vulkan").c_str(), error))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -59,6 +59,10 @@ bool VKStreamBuffer::Create(VkBufferUsageFlags usage, u32 size)
|
||||
|
||||
VmaAllocationCreateInfo aci = {};
|
||||
aci.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
|
||||
#ifdef VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT
|
||||
// Hint the allocator that we write sequentially from CPU to GPU
|
||||
aci.flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
|
||||
#endif
|
||||
aci.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
|
||||
aci.preferredFlags = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
|
||||
@@ -84,6 +88,10 @@ bool VKStreamBuffer::Create(VkBufferUsageFlags usage, u32 size)
|
||||
m_allocation = new_allocation;
|
||||
m_buffer = new_buffer;
|
||||
m_host_pointer = static_cast<u8*>(ai.pMappedData);
|
||||
// Cache coherency so we can avoid redundant flushes on HOST_COHERENT memory
|
||||
VkMemoryPropertyFlags mem_props = 0;
|
||||
vmaGetAllocationMemoryProperties(GSDeviceVK::GetInstance()->GetAllocator(), m_allocation, &mem_props);
|
||||
m_allocation_is_coherent = (mem_props & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -181,7 +189,8 @@ void VKStreamBuffer::CommitMemory(u32 final_num_bytes)
|
||||
pxAssert(final_num_bytes <= m_current_space);
|
||||
|
||||
// For non-coherent mappings, flush the memory range
|
||||
vmaFlushAllocation(GSDeviceVK::GetInstance()->GetAllocator(), m_allocation, m_current_offset, final_num_bytes);
|
||||
if (!m_allocation_is_coherent)
|
||||
vmaFlushAllocation(GSDeviceVK::GetInstance()->GetAllocator(), m_allocation, m_current_offset, final_num_bytes);
|
||||
|
||||
m_current_offset += final_num_bytes;
|
||||
m_current_space -= final_num_bytes;
|
||||
|
||||
@@ -52,6 +52,7 @@ private:
|
||||
VmaAllocation m_allocation = VK_NULL_HANDLE;
|
||||
VkBuffer m_buffer = VK_NULL_HANDLE;
|
||||
u8* m_host_pointer = nullptr;
|
||||
bool m_allocation_is_coherent = false;
|
||||
|
||||
// List of fences and the corresponding positions in the buffer
|
||||
std::deque<std::pair<u64, u32>> m_tracked_fences;
|
||||
|
||||
@@ -720,7 +720,7 @@ Pcsx2Config::GSOptions::GSOptions()
|
||||
OsdShowFPS = true;
|
||||
OsdShowVPS = true;
|
||||
OsdShowCPU = true;
|
||||
OsdShowGPU = true;
|
||||
OsdShowGPU = false;
|
||||
OsdShowResolution = true;
|
||||
OsdShowGSStats = false;
|
||||
OsdShowIndicators = true;
|
||||
@@ -867,6 +867,7 @@ bool Pcsx2Config::GSOptions::OptionsAreEqual(const GSOptions& right) const
|
||||
OpEqu(AudioCaptureBitrate) &&
|
||||
|
||||
OpEqu(Adapter) &&
|
||||
OpEqu(CustomDriverPath) &&
|
||||
|
||||
OpEqu(HWDumpDirectory) &&
|
||||
OpEqu(SWDumpDirectory));
|
||||
@@ -881,6 +882,7 @@ bool Pcsx2Config::GSOptions::RestartOptionsAreEqual(const GSOptions& right) cons
|
||||
{
|
||||
return OpEqu(Renderer) &&
|
||||
OpEqu(Adapter) &&
|
||||
OpEqu(CustomDriverPath) &&
|
||||
OpEqu(UseDebugDevice) &&
|
||||
OpEqu(UseBlitSwapChain) &&
|
||||
OpEqu(DisableShaderCache) &&
|
||||
@@ -1054,6 +1056,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
|
||||
SettingsWrapBitfieldEx(AudioCaptureBitrate, "AudioCaptureBitrate");
|
||||
|
||||
SettingsWrapEntry(Adapter);
|
||||
SettingsWrapEntry(CustomDriverPath);
|
||||
SettingsWrapEntry(HWDumpDirectory);
|
||||
if (!HWDumpDirectory.empty() && !Path::IsAbsolute(HWDumpDirectory))
|
||||
HWDumpDirectory = Path::Combine(EmuFolders::DataRoot, HWDumpDirectory);
|
||||
|
||||
Reference in New Issue
Block a user