tmp: fix android raii
Some checks failed
eden-build / source (pull_request) Has been skipped
eden-build / linux (pull_request) Successful in 25m23s
eden-build / android (pull_request) Has been cancelled
eden-build / windows (msvc) (pull_request) Has been cancelled
eden-license / license-header (pull_request_target) Has been cancelled

- update some translations
- fix glasm-spirv mixup.
- temporarily remove raii fixes on android, fixes black screen but
  causes soft crashes

Signed-off-by: swurl <swurl@swurl.xyz>
This commit is contained in:
swurl 2025-05-11 01:45:54 -04:00
parent 4965c8d51c
commit 205a895367
Signed by: crueter
GPG key ID: A5A7629F109C8FD1
10 changed files with 216 additions and 63 deletions

View file

@ -87,8 +87,8 @@
<string-array name="rendererShaderNames"> <string-array name="rendererShaderNames">
<item>@string/shader_backend_glsl</item> <item>@string/shader_backend_glsl</item>
<item>@string/shader_backend_spirv</item>
<item>@string/shader_backend_glasm</item> <item>@string/shader_backend_glasm</item>
<item>@string/shader_backend_spirv</item>
</string-array> </string-array>
<integer-array name="rendererShaderValues"> <integer-array name="rendererShaderValues">

View file

@ -23,9 +23,9 @@
<string name="show_speed">Show Speed</string> <string name="show_speed">Show Speed</string>
<string name="show_speed_description">Display current emulation speed percentage</string> <string name="show_speed_description">Display current emulation speed percentage</string>
<string name="show_app_ram_usage">Show App Memory Usage</string> <string name="show_app_ram_usage">Show App Memory Usage</string>
<string name="show_app_ram_usage_description">Display the amount of RAM getting used by the emulator</string> <string name="show_app_ram_usage_description">Display the amount of RAM the emulator is using</string>
<string name="show_system_ram_usage">Show System Memory Usage</string> <string name="show_system_ram_usage">Show System Memory Usage</string>
<string name="show_system_ram_usage_description">Display the amount of RAM getting used by the system</string> <string name="show_system_ram_usage_description">Display the amount of RAM used by the system</string>
<string name="show_bat_temperature">Show Battery Temperature</string> <string name="show_bat_temperature">Show Battery Temperature</string>
<string name="show_bat_temperature_description">Display current Battery temperature in Celsius and Fahrenheit</string> <string name="show_bat_temperature_description">Display current Battery temperature in Celsius and Fahrenheit</string>
<string name="overlay_position">Overlay Position</string> <string name="overlay_position">Overlay Position</string>
@ -49,7 +49,7 @@
<string name="dyna_state3">EDS3 + VertexInputDynamicState</string> <string name="dyna_state3">EDS3 + VertexInputDynamicState</string>
<string name="dyna_state3_description">Improves performance on newer devices. Only supported on Vulkan 1.3+ GPUs.</string> <string name="dyna_state3_description">Improves performance on newer devices. Only supported on Vulkan 1.3+ GPUs.</string>
<string name="use_sync_core">Synchronize Core Speed</string> <string name="use_sync_core">Synchronize Core Speed</string>
<string name="use_sync_core_description">Synchronize the core tick speed to the maximum speed percentage to improve performance without altering the games actual speed.</string> <string name="use_sync_core_description">Synchronize the core tick speed to the maximum speed percentage to improve performance without altering the game\'s actual speed.</string>
<string name="use_auto_stub">Use Auto Stub</string> <string name="use_auto_stub">Use Auto Stub</string>
<string name="use_auto_stub_description">Automatically stub missing services and functions. This may improve compatibility but can cause crashes and stability issues.</string> <string name="use_auto_stub_description">Automatically stub missing services and functions. This may improve compatibility but can cause crashes and stability issues.</string>
<string name="uninstall_firmware">Uninstall firmware</string> <string name="uninstall_firmware">Uninstall firmware</string>
@ -389,7 +389,7 @@
<string name="renderer_optimize_spirv_output">Optimize SPIRV output</string> <string name="renderer_optimize_spirv_output">Optimize SPIRV output</string>
<string name="renderer_optimize_spirv_output_description">Optimizes compiled shader to improve GPU efficiency.</string> <string name="renderer_optimize_spirv_output_description">Optimizes compiled shader to improve GPU efficiency.</string>
<string name="renderer_asynchronous_shaders">Use asynchronous shaders</string> <string name="renderer_asynchronous_shaders">Use asynchronous shaders</string>
<string name="renderer_asynchronous_shaders_description">Compiles shaders asynchronously, reducing stutter but may introduce glitches.</string> <string name="renderer_asynchronous_shaders_description">Compiles shaders asynchronously. This may reduce stutters but may also introduce glitches.</string>
<string name="use_fast_gpu_time">Use Fast GPU Time</string> <string name="use_fast_gpu_time">Use Fast GPU Time</string>
<string name="use_fast_gpu_time_description">Forces most games to run at their highest native resolution. This option is hacky and may cause issues.</string> <string name="use_fast_gpu_time_description">Forces most games to run at their highest native resolution. This option is hacky and may cause issues.</string>
<string name="renderer_reactive_flushing">Use reactive flushing</string> <string name="renderer_reactive_flushing">Use reactive flushing</string>

View file

@ -1,6 +1,9 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: Copyright 2025 eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <cstring> #include <cstring>
@ -99,52 +102,91 @@ Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dl
} }
RendererVulkan::RendererVulkan(Core::Frontend::EmuWindow& emu_window, RendererVulkan::RendererVulkan(Core::Frontend::EmuWindow& emu_window,
Tegra::MaxwellDeviceMemoryManager& device_memory_, Tegra::GPU& gpu_, Tegra::MaxwellDeviceMemoryManager& device_memory_,
std::unique_ptr<Core::Frontend::GraphicsContext> context_) try Tegra::GPU& gpu_,
: RendererBase(emu_window, std::move(context_)), device_memory(device_memory_), gpu(gpu_), std::unique_ptr<Core::Frontend::GraphicsContext> context_)
library(OpenLibrary(context.get())), try
// Create raw Vulkan instance first : RendererBase(emu_window, std::move(context_))
instance(CreateInstance(*library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type, , device_memory(device_memory_)
Settings::values.renderer_debug.GetValue())), , gpu(gpu_)
// Now create RAII wrappers for the resources in the correct order , library(OpenLibrary(context.get()))
managed_instance(MakeManagedInstance(instance, dld)), ,
// Create debug messenger if debug is enabled // Create raw Vulkan instance first
debug_messenger(Settings::values.renderer_debug ? CreateDebugUtilsCallback(instance) instance(CreateInstance(*library,
: vk::DebugUtilsMessenger{}), dld,
managed_debug_messenger(Settings::values.renderer_debug VK_API_VERSION_1_1,
? MakeManagedDebugUtilsMessenger(debug_messenger, instance, dld) render_window.GetWindowInfo().type,
: ManagedDebugUtilsMessenger{}), Settings::values.renderer_debug.GetValue()))
// Create surface ,
surface(CreateSurface(instance, render_window.GetWindowInfo())), // Now create RAII wrappers for the resources in the correct order
managed_surface(MakeManagedSurface(surface, instance, dld)), managed_instance(MakeManagedInstance(instance, dld))
device(CreateDevice(instance, dld, *surface)), ,
memory_allocator(device), state_tracker(), // Create debug messenger if debug is enabled
scheduler(device, state_tracker), debug_messenger(Settings::values.renderer_debug ? CreateDebugUtilsCallback(instance)
swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width, : vk::DebugUtilsMessenger{})
render_window.GetFramebufferLayout().height), , managed_debug_messenger(Settings::values.renderer_debug
present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain, ? MakeManagedDebugUtilsMessenger(debug_messenger, instance, dld)
*surface), : ManagedDebugUtilsMessenger{})
blit_swapchain(device_memory, device, memory_allocator, present_manager, scheduler, ,
PresentFiltersForDisplay), // Create surface
blit_capture(device_memory, device, memory_allocator, present_manager, scheduler, surface(CreateSurface(instance, render_window.GetWindowInfo()))
PresentFiltersForDisplay), , managed_surface(MakeManagedSurface(surface, instance, dld))
blit_applet(device_memory, device, memory_allocator, present_manager, scheduler, , device(CreateDevice(instance, dld, *surface))
PresentFiltersForAppletCapture), , memory_allocator(device)
rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker, , state_tracker()
scheduler), , scheduler(device, state_tracker)
applet_frame() { , swapchain(*surface,
device,
scheduler,
render_window.GetFramebufferLayout().width,
render_window.GetFramebufferLayout().height)
, present_manager(instance,
render_window,
device,
memory_allocator,
scheduler,
swapchain,
#ifdef ANDROID
surface)
,
#else
*surface)
,
#endif
blit_swapchain(device_memory,
device,
memory_allocator,
present_manager,
scheduler,
PresentFiltersForDisplay)
, blit_capture(device_memory,
device,
memory_allocator,
present_manager,
scheduler,
PresentFiltersForDisplay)
, blit_applet(device_memory,
device,
memory_allocator,
present_manager,
scheduler,
PresentFiltersForAppletCapture)
, rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker, scheduler)
, applet_frame() {
if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) { if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) {
turbo_mode.emplace(instance, dld); turbo_mode.emplace(instance, dld);
scheduler.RegisterOnSubmit([this] { turbo_mode->QueueSubmitted(); }); scheduler.RegisterOnSubmit([this] { turbo_mode->QueueSubmitted(); });
} }
#ifndef ANDROID
// Release ownership from the old instance and surface // Release ownership from the old instance and surface
instance.release(); instance.release();
surface.release(); surface.release();
if (Settings::values.renderer_debug) { if (Settings::values.renderer_debug) {
debug_messenger.release(); debug_messenger.release();
} }
#endif
Report(); Report();
} catch (const vk::Exception& exception) { } catch (const vk::Exception& exception) {

View file

@ -95,15 +95,31 @@ bool CanBlitToSwapchain(const vk::PhysicalDevice& physical_device, VkFormat form
} // Anonymous namespace } // Anonymous namespace
PresentManager::PresentManager(const vk::Instance& instance_, Core::Frontend::EmuWindow& render_window_, PresentManager::PresentManager(const vk::Instance& instance_,
const Device& device_, MemoryAllocator& memory_allocator_, Scheduler& scheduler_, Core::Frontend::EmuWindow& render_window_,
Swapchain& swapchain_, VkSurfaceKHR_T* surface_handle_) const Device& device_,
: instance{instance_}, render_window{render_window_}, device{device_}, MemoryAllocator& memory_allocator_,
memory_allocator{memory_allocator_}, scheduler{scheduler_}, swapchain{swapchain_}, Scheduler& scheduler_,
surface_handle{surface_handle_}, Swapchain& swapchain_,
blit_supported{CanBlitToSwapchain(device.GetPhysical(), #ifdef ANDROID
swapchain.GetImageViewFormat())}, vk::SurfaceKHR& surface_)
use_present_thread{Settings::values.async_presentation.GetValue()} { #else
VkSurfaceKHR_T* surface_handle_)
#endif
: instance{instance_}
, render_window{render_window_}
, device{device_}
, memory_allocator{memory_allocator_}
, scheduler{scheduler_}
, swapchain{swapchain_}
#ifdef ANDROID
, surface{surface_}
#else
, surface_handle{surface_handle_}
#endif
, blit_supported{CanBlitToSwapchain(device.GetPhysical(), swapchain.GetImageViewFormat())}
, use_present_thread{Settings::values.async_presentation.GetValue()}
{
SetImageCount(); SetImageCount();
auto& dld = device.GetLogical(); auto& dld = device.GetLogical();
@ -289,7 +305,11 @@ void PresentManager::PresentThread(std::stop_token token) {
} }
void PresentManager::RecreateSwapchain(Frame* frame) { void PresentManager::RecreateSwapchain(Frame* frame) {
#ifndef ANDROID
swapchain.Create(surface_handle, frame->width, frame->height); // Pass raw pointer swapchain.Create(surface_handle, frame->width, frame->height); // Pass raw pointer
#else
swapchain.Create(*surface, frame->width, frame->height); // Pass raw pointer
#endif
SetImageCount(); SetImageCount();
} }
@ -307,6 +327,9 @@ void PresentManager::CopyToSwapchain(Frame* frame) {
try { try {
// Recreate surface and swapchain if needed. // Recreate surface and swapchain if needed.
if (requires_recreation) { if (requires_recreation) {
#ifdef ANDROID
surface = CreateSurface(instance, render_window.GetWindowInfo());
#endif
RecreateSwapchain(frame); RecreateSwapchain(frame);
} }

View file

@ -37,9 +37,17 @@ struct Frame {
class PresentManager { class PresentManager {
public: public:
PresentManager(const vk::Instance& instance, Core::Frontend::EmuWindow& render_window, PresentManager(const vk::Instance& instance,
const Device& device, MemoryAllocator& memory_allocator, Scheduler& scheduler, Core::Frontend::EmuWindow& render_window,
Swapchain& swapchain, VkSurfaceKHR_T* surface_handle); const Device& device,
MemoryAllocator& memory_allocator,
Scheduler& scheduler,
Swapchain& swapchain,
#ifdef ANDROID
vk::SurfaceKHR& surface);
#else
VkSurfaceKHR_T* surface_handle);
#endif
~PresentManager(); ~PresentManager();
/// Returns the last used presentation frame /// Returns the last used presentation frame
@ -73,7 +81,11 @@ private:
MemoryAllocator& memory_allocator; MemoryAllocator& memory_allocator;
Scheduler& scheduler; Scheduler& scheduler;
Swapchain& swapchain; Swapchain& swapchain;
#ifdef ANDROID
vk::SurfaceKHR& surface;
#else
VkSurfaceKHR_T* surface_handle; VkSurfaceKHR_T* surface_handle;
#endif
vk::CommandPool cmdpool; vk::CommandPool cmdpool;
std::vector<Frame> frames; std::vector<Frame> frames;
std::queue<Frame*> present_queue; std::queue<Frame*> present_queue;

View file

@ -105,23 +105,58 @@ VkCompositeAlphaFlagBitsKHR ChooseAlphaFlags(const VkSurfaceCapabilitiesKHR& cap
} // Anonymous namespace } // Anonymous namespace
Swapchain::Swapchain(VkSurfaceKHR_T* surface_handle_, const Device& device_, Scheduler& scheduler_, Swapchain::Swapchain(
u32 width_, u32 height_) #ifdef ANDROID
: surface_handle{surface_handle_}, device{device_}, scheduler{scheduler_} { VkSurfaceKHR surface_,
#else
VkSurfaceKHR_T* surface_handle_,
#endif
const Device& device_,
Scheduler& scheduler_,
u32 width_,
u32 height_)
#ifdef ANDROID
: surface(surface_)
#else
: surface_handle{surface_handle_}
#endif
, device{device_}
, scheduler{scheduler_}
{
#ifdef ANDROID
Create(surface, width_, height_);
#else
Create(surface_handle, width_, height_); Create(surface_handle, width_, height_);
#endif
} }
Swapchain::~Swapchain() = default; Swapchain::~Swapchain() = default;
void Swapchain::Create(VkSurfaceKHR_T* surface_handle_, u32 width_, u32 height_) { void Swapchain::Create(
#ifdef ANDROID
VkSurfaceKHR surface_,
#else
VkSurfaceKHR_T* surface_handle_,
#endif
u32 width_,
u32 height_)
{
is_outdated = false; is_outdated = false;
is_suboptimal = false; is_suboptimal = false;
width = width_; width = width_;
height = height_; height = height_;
#ifdef ANDROID
surface = surface_;
#else
surface_handle = surface_handle_; surface_handle = surface_handle_;
#endif
const auto physical_device = device.GetPhysical(); const auto physical_device = device.GetPhysical();
#ifdef ANDROID
const auto capabilities{physical_device.GetSurfaceCapabilitiesKHR(surface)};
#else
const auto capabilities{physical_device.GetSurfaceCapabilitiesKHR(surface_handle)}; const auto capabilities{physical_device.GetSurfaceCapabilitiesKHR(surface_handle)};
#endif
if (capabilities.maxImageExtent.width == 0 || capabilities.maxImageExtent.height == 0) { if (capabilities.maxImageExtent.width == 0 || capabilities.maxImageExtent.height == 0) {
return; return;
} }
@ -199,10 +234,17 @@ void Swapchain::Present(VkSemaphore render_semaphore) {
void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) { void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) {
const auto physical_device{device.GetPhysical()}; const auto physical_device{device.GetPhysical()};
#ifdef ANDROID
const auto formats{physical_device.GetSurfaceFormatsKHR(surface)};
const auto present_modes = physical_device.GetSurfacePresentModesKHR(surface);
#else
const auto formats{physical_device.GetSurfaceFormatsKHR(surface_handle)}; const auto formats{physical_device.GetSurfaceFormatsKHR(surface_handle)};
const auto present_modes = physical_device.GetSurfacePresentModesKHR(surface_handle); const auto present_modes = physical_device.GetSurfacePresentModesKHR(surface_handle);
has_mailbox = std::find(present_modes.begin(), present_modes.end(), #endif
VK_PRESENT_MODE_MAILBOX_KHR) != present_modes.end();
has_mailbox = std::find(present_modes.begin(), present_modes.end(), VK_PRESENT_MODE_MAILBOX_KHR)
!= present_modes.end();
has_imm = std::find(present_modes.begin(), present_modes.end(), has_imm = std::find(present_modes.begin(), present_modes.end(),
VK_PRESENT_MODE_IMMEDIATE_KHR) != present_modes.end(); VK_PRESENT_MODE_IMMEDIATE_KHR) != present_modes.end();
has_fifo_relaxed = std::find(present_modes.begin(), present_modes.end(), has_fifo_relaxed = std::find(present_modes.begin(), present_modes.end(),
@ -228,7 +270,11 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) {
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
.pNext = nullptr, .pNext = nullptr,
.flags = 0, .flags = 0,
#ifdef ANDROID
.surface = surface,
#else
.surface = surface_handle, .surface = surface_handle,
#endif
.minImageCount = requested_image_count, .minImageCount = requested_image_count,
.imageFormat = surface_format.format, .imageFormat = surface_format.format,
.imageColorSpace = surface_format.colorSpace, .imageColorSpace = surface_format.colorSpace,
@ -269,7 +315,11 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) {
swapchain_ci.flags |= VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR; swapchain_ci.flags |= VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR;
} }
// Request the size again to reduce the possibility of a TOCTOU race condition. // Request the size again to reduce the possibility of a TOCTOU race condition.
#ifdef ANDROID
const auto updated_capabilities = physical_device.GetSurfaceCapabilitiesKHR(surface);
#else
const auto updated_capabilities = physical_device.GetSurfaceCapabilitiesKHR(surface_handle); const auto updated_capabilities = physical_device.GetSurfaceCapabilitiesKHR(surface_handle);
#endif
swapchain_ci.imageExtent = ChooseSwapExtent(updated_capabilities, width, height); swapchain_ci.imageExtent = ChooseSwapExtent(updated_capabilities, width, height);
// Don't add code within this and the swapchain creation. // Don't add code within this and the swapchain creation.
swapchain = device.GetLogical().CreateSwapchainKHR(swapchain_ci); swapchain = device.GetLogical().CreateSwapchainKHR(swapchain_ci);

View file

@ -21,12 +21,27 @@ class Scheduler;
class Swapchain { class Swapchain {
public: public:
explicit Swapchain(VkSurfaceKHR_T* surface_handle, const Device& device, Scheduler& scheduler, u32 width, explicit Swapchain(
u32 height); #ifdef ANDROID
VkSurfaceKHR surface,
#else
VkSurfaceKHR_T* surface_handle,
#endif
const Device& device,
Scheduler& scheduler,
u32 width,
u32 height);
~Swapchain(); ~Swapchain();
/// Creates (or recreates) the swapchain with a given size. /// Creates (or recreates) the swapchain with a given size.
void Create(VkSurfaceKHR_T* surface_handle, u32 width, u32 height); void Create(
#ifdef ANDROID
VkSurfaceKHR surface,
#else
VkSurfaceKHR_T* surface_handle,
#endif
u32 width,
u32 height);
/// Acquires the next image in the swapchain, waits as needed. /// Acquires the next image in the swapchain, waits as needed.
bool AcquireNextImage(); bool AcquireNextImage();
@ -110,7 +125,12 @@ private:
bool NeedsPresentModeUpdate() const; bool NeedsPresentModeUpdate() const;
#ifdef ANDROID
VkSurfaceKHR surface;
#else
VkSurfaceKHR_T* surface_handle; VkSurfaceKHR_T* surface_handle;
#endif
const Device& device; const Device& device;
Scheduler& scheduler; Scheduler& scheduler;

View file

@ -430,6 +430,7 @@ public:
return handle != nullptr; return handle != nullptr;
} }
#ifndef ANDROID
/** /**
* Releases ownership of the managed handle. * Releases ownership of the managed handle.
* The caller is responsible for managing the lifetime of the returned handle. * The caller is responsible for managing the lifetime of the returned handle.
@ -438,6 +439,7 @@ public:
Type release() noexcept { Type release() noexcept {
return std::exchange(handle, nullptr); return std::exchange(handle, nullptr);
} }
#endif
protected: protected:
Type handle = nullptr; Type handle = nullptr;
@ -510,6 +512,7 @@ public:
return handle != nullptr; return handle != nullptr;
} }
#ifndef ANDROID
/** /**
* Releases ownership of the managed handle. * Releases ownership of the managed handle.
* The caller is responsible for managing the lifetime of the returned handle. * The caller is responsible for managing the lifetime of the returned handle.
@ -518,6 +521,7 @@ public:
Type release() noexcept { Type release() noexcept {
return std::exchange(handle, nullptr); return std::exchange(handle, nullptr);
} }
#endif
protected: protected:
Type handle = nullptr; Type handle = nullptr;

View file

@ -544,7 +544,9 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {
{ {
PAIR(MemoryLayout, Memory_4Gb, tr("4GB DRAM (Default)")), PAIR(MemoryLayout, Memory_4Gb, tr("4GB DRAM (Default)")),
PAIR(MemoryLayout, Memory_6Gb, tr("6GB DRAM (Unsafe)")), PAIR(MemoryLayout, Memory_6Gb, tr("6GB DRAM (Unsafe)")),
PAIR(MemoryLayout, Memory_8Gb, tr("8GB DRAM (Unsafe)")), PAIR(MemoryLayout, Memory_8Gb, tr("8GB DRAM")),
PAIR(MemoryLayout, Memory_10Gb, tr("10GB DRAM (Unsafe)")),
PAIR(MemoryLayout, Memory_12Gb, tr("12GB DRAM (Unsafe)")),
}}); }});
translations->insert({Settings::EnumMetadata<Settings::ConsoleMode>::Index(), translations->insert({Settings::EnumMetadata<Settings::ConsoleMode>::Index(),
{ {

View file

@ -374,7 +374,7 @@ GameList::GameList(FileSys::VirtualFilesystem vfs_, FileSys::ManualContentProvid
warning_layout = new QHBoxLayout; warning_layout = new QHBoxLayout;
pre_alpha_warning = new QLabel; pre_alpha_warning = new QLabel;
pre_alpha_warning->setText( pre_alpha_warning->setText(
tr("IMPORTANT: Eden is PRE-ALPHA SOFTWARE." tr("IMPORTANT: Eden is PRE-ALPHA SOFTWARE. "
"Bugs and unfinished features are expected to be present at this stage.")); "Bugs and unfinished features are expected to be present at this stage."));
pre_alpha_warning->setWordWrap(true); pre_alpha_warning->setWordWrap(true);
pre_alpha_warning->setOpenExternalLinks(true); pre_alpha_warning->setOpenExternalLinks(true);