Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
8a11b3c
mbedTLS fix for cURL 8.8.0
Lpsd May 24, 2024
181bf0f
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd May 24, 2024
6728cbe
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd May 25, 2024
0b989ac
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd May 26, 2024
9c19509
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Jun 2, 2024
75c36ed
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Jun 19, 2024
96dd1ee
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Oct 2, 2024
f9eaf3f
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Oct 8, 2024
54bd11b
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Oct 10, 2024
ddee2d0
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Oct 19, 2024
288b8db
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Oct 21, 2024
b30a4a2
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Oct 22, 2024
27b9eae
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Dec 17, 2024
3731d81
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Jan 14, 2025
b50a68c
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Jan 22, 2025
58ae23f
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Feb 19, 2025
f3645b8
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Mar 4, 2025
e62d9f4
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Mar 14, 2025
3346e9c
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Mar 16, 2025
95dfc97
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Sep 6, 2025
3307dc6
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Sep 14, 2025
f091a85
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Sep 24, 2025
c66e5de
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Nov 7, 2025
c132ae1
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Nov 9, 2025
5739ef0
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Jan 7, 2026
4e8d1c0
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Jan 7, 2026
27d7fd7
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Jan 13, 2026
ee4475e
External begin frame scheduling
Lpsd Jan 13, 2026
d728302
Optimize dirty rect handling
Lpsd Jan 13, 2026
a84d11c
Use D3DPOOL_DEFAULT with D3DUSAGE_DYNAMIC
Lpsd Jan 13, 2026
ab0bcbf
Browser lazy loading
Lpsd Jan 13, 2026
7d5c788
Video decode acceleration & gpu compositing
Lpsd Jan 14, 2026
0ff9e41
Mouse input throttling & dirty rect optimizations
Lpsd Jan 14, 2026
eefc173
Lazy loading fixes
Lpsd Jan 14, 2026
701b0a9
Remove outdated wine comment
Lpsd Jan 14, 2026
3388945
Revert OnPaint dirty rect optimization from 0ff9e41d5
Lpsd Jan 14, 2026
2090d12
Improve CWebView::UpdateTexture edge cases
Lpsd Jan 14, 2026
624f063
Remove dirty rect processing & improve restore
Lpsd Jan 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions Client/cefweb/CWebApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ namespace
// Prevent Chromium from dropping privileges; required for elevated launches (see chromium/3960)
commandLine->AppendSwitch("do-not-de-elevate");

// Must apply essential CEF switches regardless of WebCore availability
commandLine->AppendSwitch("disable-gpu-compositing");
// Enable external begin frame scheduling for MTA-controlled rendering
commandLine->AppendSwitch("enable-begin-frame-scheduling");
// Explicitly block account sign-in to avoid crashes when Google API keys are registered on the system
commandLine->AppendSwitchWithValue("allow-browser-signin", "false");
Expand All @@ -77,6 +76,7 @@ namespace
}

bool disableGpu = false;
bool enableVideoAccel = true;
if (g_pCore && IsReadablePointer(g_pCore, sizeof(void*)))
{
auto* cvars = g_pCore->GetCVars();
Expand All @@ -85,6 +85,8 @@ namespace
bool gpuEnabled = true;
cvars->Get("browser_enable_gpu", gpuEnabled);
disableGpu = !gpuEnabled;

cvars->Get("browser_enable_video_acceleration", enableVideoAccel);
}
}

Expand All @@ -98,20 +100,29 @@ namespace
else
{
// In Wine, we generally want to try GPU (DXVK handles it well)
// But disable-gpu-compositing is already set above which is key
// If user hasn't explicitly disabled GPU in cvars, let it run
}
}

if (disableGpu)
{
commandLine->AppendSwitch("disable-gpu");
// Also disable GPU compositing when GPU is disabled
commandLine->AppendSwitch("disable-gpu-compositing");
}

// Hardware video decoding - enable when GPU is enabled and video acceleration is requested
if (!disableGpu && enableVideoAccel)
{
commandLine->AppendSwitch("enable-accelerated-video-decode");
}
}
} // namespace

[[nodiscard]] CefRefPtr<CefResourceHandler> CWebApp::HandleError(const SString& strError, unsigned int uiError)
{
auto stream = CefStreamReader::CreateForData(
(void*)strError.c_str(),
(void*)strError.c_str(),
strError.length()
);
if (!stream)
Expand All @@ -131,7 +142,7 @@ void CWebApp::OnBeforeChildProcessLaunch(CefRefPtr<CefCommandLine> command_line)

const CefString processType = command_line->GetSwitchValue("type");
ConfigureCommandLineSwitches(command_line, processType);

// Attach IPC validation code for render processes
// This runs in browser process context where g_pCore and webCore are valid
// The auth code is generated in CWebCore constructor and passed to subprocesses
Expand Down Expand Up @@ -325,7 +336,7 @@ CefRefPtr<CefResourceHandler> CWebApp::Create(CefRefPtr<CefBrowser> browser, Cef
static constexpr unsigned int CODE_404 = 404;
return HandleError(ERROR_404, CODE_404);
}

return CefRefPtr<CefResourceHandler>(new CefStreamResourceHandler(mimeType, stream));
}
}
Expand Down
69 changes: 41 additions & 28 deletions Client/cefweb/CWebCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,28 +77,28 @@ bool CWebCore::Initialise(bool gpuEnabled)
// CefInitialize() can only be called once per process lifetime
// Do not call this function again or recreate CWebCore if initialization fails
// Repeated calls cause "Timeout of new browser info response for frame" errors

m_bGPUEnabled = gpuEnabled;

// Get MTA base directory
SString strBaseDir = SharedUtil::GetMTAProcessBaseDir();

if (strBaseDir.empty())
{
g_pCore->GetConsole()->Printf("CEF initialization skipped - Unable to determine MTA base directory");
AddReportLog(8000, "CEF initialization skipped - Unable to determine MTA base directory");
m_bInitialised = false;
return false;
}

SString strMTADir = PathJoin(strBaseDir, "MTA");

#ifndef MTA_DEBUG
SString strLauncherPath = PathJoin(strMTADir, "CEF", "CEFLauncher.exe");
#else
SString strLauncherPath = PathJoin(strMTADir, "CEF", "CEFLauncher_d.exe");
#endif

// Set DLL directory for CEFLauncher subprocess to locate required libraries
SString strCEFDir = PathJoin(strMTADir, "CEF");
#ifdef _WIN32
Expand All @@ -110,23 +110,23 @@ bool CWebCore::Initialise(bool gpuEnabled)
if (existingPath) {
newPath = SString("%s:%s", strCEFDir.c_str(), existingPath);
}
// Note: setenv is not available in MSVC, but _putenv is.
// Note: setenv is not available in MSVC, but _putenv is.
// However, since we are compiling for Windows (running on Wine), we use Windows APIs.
// Wine maps Windows environment variables.
// But LD_LIBRARY_PATH is a Linux variable.
// If we are in Wine, we might want to set PATH instead or as well.
// SetDllDirectoryW handles the Windows loader.

// Log for debugging
if (std::getenv("WINE") || std::getenv("WINEPREFIX")) {
g_pCore->GetConsole()->Printf("DEBUG: CEF library path set via SetDllDirectoryW: %s", strCEFDir.c_str());
}
#endif

// Read GTA path from registry to pass to CEF subprocess
int iRegistryResult = 0;
const SString strGTAPath = GetCommonRegistryValue("", "GTA:SA Path", &iRegistryResult);

// Check if process is running with elevated privileges
// CEF subprocesses may have communication issues when running elevated
const bool bIsElevated = []() -> bool {
Expand All @@ -140,34 +140,34 @@ bool CWebCore::Initialise(bool gpuEnabled)
HANDLE hToken = nullptr;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
return false;

// RAII wrapper for token handle
const std::unique_ptr<void, decltype(&CloseHandle)> tokenGuard(hToken, &CloseHandle);

TOKEN_ELEVATION elevation{};
DWORD dwSize = sizeof(elevation);
if (!GetTokenInformation(hToken, TokenElevation, &elevation, sizeof(elevation), &dwSize))
return false;

return elevation.TokenIsElevated != 0;
}();

if (bIsElevated && !std::getenv("WINE"))
{
AddReportLog(8021, "WARNING: Process is running with elevated privileges (Administrator)");
AddReportLog(8022, "CEF browser features may not work correctly when running as Administrator");
AddReportLog(8023, "Consider running MTA without Administrator privileges for full browser functionality");
g_pCore->GetConsole()->Printf("WARNING: Running as Administrator - browser features may be limited");
}

// Verify CEFLauncher can run in current environment
auto CanExecuteCEFLauncher = []() -> bool {
#ifdef _WIN32
// On Windows, we know it works
if (!std::getenv("WINE") && !std::getenv("WINEPREFIX") && !std::getenv("PROTON_VERSION"))
return true;
#endif

// Check if Wine can execute the launcher
// This is a basic check - if we are in Wine, we assume it works unless proven otherwise
// But we can log if we are in a mixed environment
Expand All @@ -192,7 +192,7 @@ bool CWebCore::Initialise(bool gpuEnabled)
// Ensure cache directory can be created
const SString strCachePath = PathJoin(strMTADir, "CEF", "cache");
MakeSureDirExists(strCachePath);

// Verify locales directory exists
const SString strLocalesPath = PathJoin(strMTADir, "CEF", "locales");
if (!DirectoryExists(strLocalesPath))
Expand All @@ -215,7 +215,7 @@ bool CWebCore::Initialise(bool gpuEnabled)
m_bInitialised = false;
return false;
}

// RAII scope guard to restore CWD, even if CefInitialize throws or returns early
struct CwdGuard {
fs::path savedPath;
Expand All @@ -225,7 +225,7 @@ bool CWebCore::Initialise(bool gpuEnabled)
fs::current_path(savedPath, restoreEc);
}
} cwdGuard(savedCwd);

// Temporarily change CWD to MTA directory for CefInitialize
// CEFLauncher.exe requires this to locate CEF dependencies
fs::current_path(fs::path(FromUTF8(strMTADir)), ec);
Expand All @@ -235,7 +235,7 @@ bool CWebCore::Initialise(bool gpuEnabled)
m_bInitialised = false;
return false;
}

CefMainArgs mainArgs;
void* sandboxInfo = nullptr;

Expand Down Expand Up @@ -278,7 +278,7 @@ bool CWebCore::Initialise(bool gpuEnabled)
}

// CWD will be restored by cwdGuard destructor when this function returns

if (m_bInitialised)
{
// Register custom scheme handler factory only if initialization succeeded
Expand All @@ -290,7 +290,7 @@ bool CWebCore::Initialise(bool gpuEnabled)
g_pCore->GetConsole()->Printf("CefInitialize failed - CEF features will be disabled");
AddReportLog(8004, "CefInitialize failed - CEF features will be disabled");
}

return m_bInitialised;
}

Expand All @@ -315,18 +315,18 @@ void CWebCore::DestroyWebView(CWebViewInterface* pWebViewInterface)
{
// Mark as being destroyed to prevent new events/tasks
pWebView->SetBeingDestroyed(true);

// Ensure that no attached events or tasks are in the queue
RemoveWebViewEvents(pWebView.get());
RemoveWebViewTasks(pWebView.get());

// Remove from list before closing to break reference cycles early
m_WebViews.remove(pWebView);

// CloseBrowser will eventually trigger OnBeforeClose which clears m_pWebView
// This breaks the circular reference: CWebView -> CefBrowser -> CWebView
pWebView->CloseBrowser();

// Note: Do not call Release() - let CefRefPtr manage the lifecycle
// The circular reference is broken via OnBeforeClose setting m_pWebView = nullptr
}
Expand Down Expand Up @@ -382,7 +382,7 @@ void CWebCore::AddEventToEventQueue(std::function<void()> event, CWebView* pWebV
{
// Log warning even in release builds as this indicates a serious issue
g_pCore->GetConsole()->Printf("WARNING: Browser event queue size limit reached (%d), dropping oldest events", MAX_EVENT_QUEUE_SIZE);

// Remove oldest 10% of events to make room
auto removeCount = static_cast<size_t>(MAX_EVENT_QUEUE_SIZE / 10);
for (auto i = size_t{0}; i < removeCount && !m_EventQueue.empty(); ++i)
Expand Down Expand Up @@ -426,7 +426,20 @@ void CWebCore::DoEventQueuePulse()
event.callback();
}

// Invoke paint method if necessary on the main thread
// Request new frames from CEF using external begin frame scheduling
// This synchronizes CEF rendering with MTA's render loop, eliminating
// the previous 250ms blocking wait in OnPaint
for (auto& view : m_WebViews)
{
if (view->IsBeingDestroyed() || view->GetRenderingPaused())
continue;

auto browser = view->GetCefBrowser();
if (browser)
browser->GetHost()->SendExternalBeginFrame();
}

// Copy rendered data to D3D textures on the main thread
for (auto& view : m_WebViews)
{
view->UpdateTexture();
Expand All @@ -444,7 +457,7 @@ void CWebCore::WaitForTask(std::function<void(bool)> task, CWebView* webView)
std::future<void> result;
{
std::scoped_lock lock(m_TaskQueueMutex);

// Prevent unbounded queue growth - abort new task if queue is too large
if (m_TaskQueue.size() >= MAX_TASK_QUEUE_SIZE) [[unlikely]]
{
Expand All @@ -457,7 +470,7 @@ void CWebCore::WaitForTask(std::function<void(bool)> task, CWebView* webView)
task(true);
return;
}

m_TaskQueue.emplace_back(TaskEntry{task, webView});
result = m_TaskQueue.back().task.get_future();
}
Expand Down
Loading
Loading