early-access version 3213
This commit is contained in:
		| @@ -1,7 +1,7 @@ | ||||
| yuzu emulator early access | ||||
| ============= | ||||
|  | ||||
| This is the source code for early-access 3212. | ||||
| This is the source code for early-access 3213. | ||||
|  | ||||
| ## Legal Notice | ||||
|  | ||||
|   | ||||
| @@ -131,6 +131,10 @@ public: | ||||
|         return active_config; | ||||
|     } | ||||
|  | ||||
|     bool StrictContextRequired() const { | ||||
|         return strict_context_required; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Requests the internal configuration to be replaced by the specified argument at some point in | ||||
|      * the future. | ||||
| @@ -207,6 +211,8 @@ protected: | ||||
|  | ||||
|     WindowSystemInfo window_info; | ||||
|  | ||||
|     bool strict_context_required = false; | ||||
|  | ||||
| private: | ||||
|     /** | ||||
|      * Handler called when the minimal client area was requested to be changed via SetConfig. | ||||
|   | ||||
| @@ -461,7 +461,7 @@ void EmitSetSampleMask(EmitContext& ctx, Id value) { | ||||
| } | ||||
|  | ||||
| void EmitSetFragDepth(EmitContext& ctx, Id value) { | ||||
|     if (!ctx.runtime_info.convert_depth_mode) { | ||||
|     if (!ctx.runtime_info.convert_depth_mode || ctx.profile.support_native_ndc) { | ||||
|         ctx.OpStore(ctx.frag_depth, value); | ||||
|         return; | ||||
|     } | ||||
|   | ||||
| @@ -116,7 +116,8 @@ void EmitPrologue(EmitContext& ctx) { | ||||
| } | ||||
|  | ||||
| void EmitEpilogue(EmitContext& ctx) { | ||||
|     if (ctx.stage == Stage::VertexB && ctx.runtime_info.convert_depth_mode) { | ||||
|     if (ctx.stage == Stage::VertexB && ctx.runtime_info.convert_depth_mode && | ||||
|         !ctx.profile.support_native_ndc) { | ||||
|         ConvertDepthMode(ctx); | ||||
|     } | ||||
|     if (ctx.stage == Stage::Fragment) { | ||||
| @@ -125,7 +126,7 @@ void EmitEpilogue(EmitContext& ctx) { | ||||
| } | ||||
|  | ||||
| void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) { | ||||
|     if (ctx.runtime_info.convert_depth_mode) { | ||||
|     if (ctx.runtime_info.convert_depth_mode && !ctx.profile.support_native_ndc) { | ||||
|         ConvertDepthMode(ctx); | ||||
|     } | ||||
|     if (stream.IsImmediate()) { | ||||
|   | ||||
| @@ -35,6 +35,7 @@ struct Profile { | ||||
|     bool support_int64_atomics{}; | ||||
|     bool support_derivative_control{}; | ||||
|     bool support_geometry_shader_passthrough{}; | ||||
|     bool support_native_ndc{}; | ||||
|     bool support_gl_nv_gpu_shader_5{}; | ||||
|     bool support_gl_amd_gpu_shader_half_float{}; | ||||
|     bool support_gl_texture_shadow_lod{}; | ||||
|   | ||||
| @@ -223,8 +223,6 @@ struct GPU::Impl { | ||||
|     /// core timing events. | ||||
|     void Start() { | ||||
|         gpu_thread.StartThread(*renderer, renderer->Context(), *scheduler); | ||||
|         cpu_context = renderer->GetRenderWindow().CreateSharedContext(); | ||||
|         cpu_context->MakeCurrent(); | ||||
|     } | ||||
|  | ||||
|     void NotifyShutdown() { | ||||
| @@ -235,6 +233,9 @@ struct GPU::Impl { | ||||
|  | ||||
|     /// Obtain the CPU Context | ||||
|     void ObtainContext() { | ||||
|         if (!cpu_context) { | ||||
|             cpu_context = renderer->GetRenderWindow().CreateSharedContext(); | ||||
|         } | ||||
|         cpu_context->MakeCurrent(); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -112,7 +112,7 @@ bool IsASTCSupported() { | ||||
| } | ||||
| } // Anonymous namespace | ||||
|  | ||||
| Device::Device() { | ||||
| Device::Device(Core::Frontend::EmuWindow& emu_window) { | ||||
|     if (!GLAD_GL_VERSION_4_6) { | ||||
|         LOG_ERROR(Render_OpenGL, "OpenGL 4.6 is not available"); | ||||
|         throw std::runtime_error{"Insufficient version"}; | ||||
| @@ -126,9 +126,9 @@ Device::Device() { | ||||
|     const bool is_intel = vendor_name == "Intel"; | ||||
|  | ||||
| #ifdef __unix__ | ||||
|     const bool is_linux = true; | ||||
|     constexpr bool is_linux = true; | ||||
| #else | ||||
|     const bool is_linux = false; | ||||
|     constexpr bool is_linux = false; | ||||
| #endif | ||||
|  | ||||
|     bool disable_fast_buffer_sub_data = false; | ||||
| @@ -193,9 +193,11 @@ Device::Device() { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     strict_context_required = emu_window.StrictContextRequired(); | ||||
|     // Blocks AMD and Intel OpenGL drivers on Windows from using asynchronous shader compilation. | ||||
|     // Blocks EGL on Wayland from using asynchronous shader compilation. | ||||
|     use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue() && | ||||
|                                !(is_amd || (is_intel && !is_linux)); | ||||
|                                !(is_amd || (is_intel && !is_linux)) && !strict_context_required; | ||||
|     use_driver_cache = is_nvidia; | ||||
|  | ||||
|     LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi); | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
|  | ||||
| #include <cstddef> | ||||
| #include "common/common_types.h" | ||||
| #include "core/frontend/emu_window.h" | ||||
| #include "shader_recompiler/stage.h" | ||||
|  | ||||
| namespace Settings { | ||||
| @@ -15,7 +16,7 @@ namespace OpenGL { | ||||
|  | ||||
| class Device { | ||||
| public: | ||||
|     explicit Device(); | ||||
|     explicit Device(Core::Frontend::EmuWindow& emu_window); | ||||
|  | ||||
|     [[nodiscard]] std::string GetVendorName() const; | ||||
|  | ||||
| @@ -173,6 +174,10 @@ public: | ||||
|         return can_report_memory; | ||||
|     } | ||||
|  | ||||
|     bool StrictContextRequired() const { | ||||
|         return strict_context_required; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     static bool TestVariableAoffi(); | ||||
|     static bool TestPreciseBug(); | ||||
| @@ -216,6 +221,7 @@ private: | ||||
|     bool has_cbuf_ftou_bug{}; | ||||
|     bool has_bool_ref_bug{}; | ||||
|     bool can_report_memory{}; | ||||
|     bool strict_context_required{}; | ||||
|  | ||||
|     std::string vendor_name; | ||||
| }; | ||||
|   | ||||
| @@ -174,6 +174,7 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo | ||||
|       texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, program_manager{program_manager_}, | ||||
|       state_tracker{state_tracker_}, shader_notify{shader_notify_}, | ||||
|       use_asynchronous_shaders{device.UseAsynchronousShaders()}, | ||||
|       strict_context_required{device.StrictContextRequired()}, | ||||
|       profile{ | ||||
|           .supported_spirv = 0x00010000, | ||||
|  | ||||
| @@ -203,6 +204,7 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo | ||||
|           .support_int64_atomics = false, | ||||
|           .support_derivative_control = device.HasDerivativeControl(), | ||||
|           .support_geometry_shader_passthrough = device.HasGeometryShaderPassthrough(), | ||||
|           .support_native_ndc = true, | ||||
|           .support_gl_nv_gpu_shader_5 = device.HasNvGpuShader5(), | ||||
|           .support_gl_amd_gpu_shader_half_float = device.HasAmdShaderHalfFloat(), | ||||
|           .support_gl_texture_shadow_lod = device.HasTextureShadowLod(), | ||||
| @@ -255,9 +257,14 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading, | ||||
|     } | ||||
|     shader_cache_filename = base_dir / "opengl.bin"; | ||||
|  | ||||
|     if (!workers) { | ||||
|     if (!workers && !strict_context_required) { | ||||
|         workers = CreateWorkers(); | ||||
|     } | ||||
|     std::optional<Context> strict_context; | ||||
|     if (strict_context_required) { | ||||
|         strict_context.emplace(emu_window); | ||||
|     } | ||||
|  | ||||
|     struct { | ||||
|         std::mutex mutex; | ||||
|         size_t total{}; | ||||
| @@ -265,44 +272,49 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading, | ||||
|         bool has_loaded{}; | ||||
|     } state; | ||||
|  | ||||
|     const auto queue_work{[&](Common::UniqueFunction<void, Context*>&& work) { | ||||
|         if (strict_context_required) { | ||||
|             work(&strict_context.value()); | ||||
|         } else { | ||||
|             workers->QueueWork(std::move(work)); | ||||
|         } | ||||
|     }}; | ||||
|     const auto load_compute{[&](std::ifstream& file, FileEnvironment env) { | ||||
|         ComputePipelineKey key; | ||||
|         file.read(reinterpret_cast<char*>(&key), sizeof(key)); | ||||
|         workers->QueueWork( | ||||
|             [this, key, env = std::move(env), &state, &callback](Context* ctx) mutable { | ||||
|                 ctx->pools.ReleaseContents(); | ||||
|                 auto pipeline{CreateComputePipeline(ctx->pools, key, env)}; | ||||
|                 std::scoped_lock lock{state.mutex}; | ||||
|                 if (pipeline) { | ||||
|                     compute_cache.emplace(key, std::move(pipeline)); | ||||
|                 } | ||||
|                 ++state.built; | ||||
|                 if (state.has_loaded) { | ||||
|                     callback(VideoCore::LoadCallbackStage::Build, state.built, state.total); | ||||
|                 } | ||||
|             }); | ||||
|         queue_work([this, key, env = std::move(env), &state, &callback](Context* ctx) mutable { | ||||
|             ctx->pools.ReleaseContents(); | ||||
|             auto pipeline{CreateComputePipeline(ctx->pools, key, env)}; | ||||
|             std::scoped_lock lock{state.mutex}; | ||||
|             if (pipeline) { | ||||
|                 compute_cache.emplace(key, std::move(pipeline)); | ||||
|             } | ||||
|             ++state.built; | ||||
|             if (state.has_loaded) { | ||||
|                 callback(VideoCore::LoadCallbackStage::Build, state.built, state.total); | ||||
|             } | ||||
|         }); | ||||
|         ++state.total; | ||||
|     }}; | ||||
|     const auto load_graphics{[&](std::ifstream& file, std::vector<FileEnvironment> envs) { | ||||
|         GraphicsPipelineKey key; | ||||
|         file.read(reinterpret_cast<char*>(&key), sizeof(key)); | ||||
|         workers->QueueWork( | ||||
|             [this, key, envs = std::move(envs), &state, &callback](Context* ctx) mutable { | ||||
|                 boost::container::static_vector<Shader::Environment*, 5> env_ptrs; | ||||
|                 for (auto& env : envs) { | ||||
|                     env_ptrs.push_back(&env); | ||||
|                 } | ||||
|                 ctx->pools.ReleaseContents(); | ||||
|                 auto pipeline{CreateGraphicsPipeline(ctx->pools, key, MakeSpan(env_ptrs), false)}; | ||||
|                 std::scoped_lock lock{state.mutex}; | ||||
|                 if (pipeline) { | ||||
|                     graphics_cache.emplace(key, std::move(pipeline)); | ||||
|                 } | ||||
|                 ++state.built; | ||||
|                 if (state.has_loaded) { | ||||
|                     callback(VideoCore::LoadCallbackStage::Build, state.built, state.total); | ||||
|                 } | ||||
|             }); | ||||
|         queue_work([this, key, envs = std::move(envs), &state, &callback](Context* ctx) mutable { | ||||
|             boost::container::static_vector<Shader::Environment*, 5> env_ptrs; | ||||
|             for (auto& env : envs) { | ||||
|                 env_ptrs.push_back(&env); | ||||
|             } | ||||
|             ctx->pools.ReleaseContents(); | ||||
|             auto pipeline{CreateGraphicsPipeline(ctx->pools, key, MakeSpan(env_ptrs), false)}; | ||||
|             std::scoped_lock lock{state.mutex}; | ||||
|             if (pipeline) { | ||||
|                 graphics_cache.emplace(key, std::move(pipeline)); | ||||
|             } | ||||
|             ++state.built; | ||||
|             if (state.has_loaded) { | ||||
|                 callback(VideoCore::LoadCallbackStage::Build, state.built, state.total); | ||||
|             } | ||||
|         }); | ||||
|         ++state.total; | ||||
|     }}; | ||||
|     LoadPipelines(stop_loading, shader_cache_filename, CACHE_VERSION, load_compute, load_graphics); | ||||
| @@ -314,6 +326,9 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading, | ||||
|     state.has_loaded = true; | ||||
|     lock.unlock(); | ||||
|  | ||||
|     if (strict_context_required) { | ||||
|         return; | ||||
|     } | ||||
|     workers->WaitForRequests(stop_loading); | ||||
|     if (!use_asynchronous_shaders) { | ||||
|         workers.reset(); | ||||
|   | ||||
| @@ -69,6 +69,7 @@ private: | ||||
|     StateTracker& state_tracker; | ||||
|     VideoCore::ShaderNotify& shader_notify; | ||||
|     const bool use_asynchronous_shaders; | ||||
|     const bool strict_context_required; | ||||
|  | ||||
|     GraphicsPipelineKey graphics_key{}; | ||||
|     GraphicsPipeline* current_pipeline{}; | ||||
|   | ||||
| @@ -140,8 +140,8 @@ RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_, | ||||
|                                Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_, | ||||
|                                std::unique_ptr<Core::Frontend::GraphicsContext> context_) | ||||
|     : RendererBase{emu_window_, std::move(context_)}, telemetry_session{telemetry_session_}, | ||||
|       emu_window{emu_window_}, cpu_memory{cpu_memory_}, gpu{gpu_}, state_tracker{}, | ||||
|       program_manager{device}, | ||||
|       emu_window{emu_window_}, cpu_memory{cpu_memory_}, gpu{gpu_}, device{emu_window_}, | ||||
|       state_tracker{}, program_manager{device}, | ||||
|       rasterizer(emu_window, gpu, cpu_memory, device, screen_info, program_manager, state_tracker) { | ||||
|     if (Settings::values.renderer_debug && GLAD_GL_KHR_debug) { | ||||
|         glEnable(GL_DEBUG_OUTPUT); | ||||
|   | ||||
| @@ -139,23 +139,25 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | ||||
|     RenderScreenshot(*framebuffer, use_accelerated); | ||||
|  | ||||
|     bool has_been_recreated = false; | ||||
|     const auto recreate_swapchain = [&] { | ||||
|     const auto recreate_swapchain = [&](u32 width, u32 height) { | ||||
|         if (!has_been_recreated) { | ||||
|             has_been_recreated = true; | ||||
|             scheduler.Finish(); | ||||
|         } | ||||
|         const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout(); | ||||
|         swapchain.Create(layout.width, layout.height, is_srgb); | ||||
|         swapchain.Create(width, height, is_srgb); | ||||
|     }; | ||||
|     if (swapchain.NeedsRecreation(is_srgb)) { | ||||
|         recreate_swapchain(); | ||||
|  | ||||
|     const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout(); | ||||
|     if (swapchain.NeedsRecreation(is_srgb) || swapchain.GetWidth() != layout.width || | ||||
|         swapchain.GetHeight() != layout.height) { | ||||
|         recreate_swapchain(layout.width, layout.height); | ||||
|     } | ||||
|     bool is_outdated; | ||||
|     do { | ||||
|         swapchain.AcquireNextImage(); | ||||
|         is_outdated = swapchain.IsOutDated(); | ||||
|         if (is_outdated) { | ||||
|             recreate_swapchain(); | ||||
|             recreate_swapchain(layout.width, layout.height); | ||||
|         } | ||||
|     } while (is_outdated); | ||||
|     if (has_been_recreated) { | ||||
|   | ||||
| @@ -640,23 +640,33 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { | ||||
|     }; | ||||
|     std::array<VkViewportSwizzleNV, Maxwell::NumViewports> swizzles; | ||||
|     std::ranges::transform(key.state.viewport_swizzles, swizzles.begin(), UnpackViewportSwizzle); | ||||
|     const VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci{ | ||||
|     VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci{ | ||||
|         .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV, | ||||
|         .pNext = nullptr, | ||||
|         .flags = 0, | ||||
|         .viewportCount = Maxwell::NumViewports, | ||||
|         .pViewportSwizzles = swizzles.data(), | ||||
|     }; | ||||
|     const VkPipelineViewportStateCreateInfo viewport_ci{ | ||||
|     VkPipelineViewportDepthClipControlCreateInfoEXT ndc_info{ | ||||
|         .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT, | ||||
|         .pNext = nullptr, | ||||
|         .negativeOneToOne = key.state.ndc_minus_one_to_one.Value() != 0 ? VK_TRUE : VK_FALSE, | ||||
|     }; | ||||
|     VkPipelineViewportStateCreateInfo viewport_ci{ | ||||
|         .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, | ||||
|         .pNext = device.IsNvViewportSwizzleSupported() ? &swizzle_ci : nullptr, | ||||
|         .pNext = nullptr, | ||||
|         .flags = 0, | ||||
|         .viewportCount = Maxwell::NumViewports, | ||||
|         .pViewports = nullptr, | ||||
|         .scissorCount = Maxwell::NumViewports, | ||||
|         .pScissors = nullptr, | ||||
|     }; | ||||
|  | ||||
|     if (device.IsNvViewportSwizzleSupported()) { | ||||
|         swizzle_ci.pNext = std::exchange(viewport_ci.pNext, &swizzle_ci); | ||||
|     } | ||||
|     if (device.IsExtDepthClipControlSupported()) { | ||||
|         ndc_info.pNext = std::exchange(viewport_ci.pNext, &ndc_info); | ||||
|     } | ||||
|     VkPipelineRasterizationStateCreateInfo rasterization_ci{ | ||||
|         .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, | ||||
|         .pNext = nullptr, | ||||
|   | ||||
| @@ -321,6 +321,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device | ||||
|         .support_int64_atomics = device.IsExtShaderAtomicInt64Supported(), | ||||
|         .support_derivative_control = true, | ||||
|         .support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(), | ||||
|         .support_native_ndc = device.IsExtDepthClipControlSupported(), | ||||
|  | ||||
|         .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(), | ||||
|  | ||||
|   | ||||
| @@ -67,17 +67,19 @@ VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, u32 wi | ||||
|  | ||||
| } // Anonymous namespace | ||||
|  | ||||
| Swapchain::Swapchain(VkSurfaceKHR surface_, const Device& device_, Scheduler& scheduler_, u32 width, | ||||
|                      u32 height, bool srgb) | ||||
| Swapchain::Swapchain(VkSurfaceKHR surface_, const Device& device_, Scheduler& scheduler_, | ||||
|                      u32 width_, u32 height_, bool srgb) | ||||
|     : surface{surface_}, device{device_}, scheduler{scheduler_} { | ||||
|     Create(width, height, srgb); | ||||
|     Create(width_, height_, srgb); | ||||
| } | ||||
|  | ||||
| Swapchain::~Swapchain() = default; | ||||
|  | ||||
| void Swapchain::Create(u32 width, u32 height, bool srgb) { | ||||
| void Swapchain::Create(u32 width_, u32 height_, bool srgb) { | ||||
|     is_outdated = false; | ||||
|     is_suboptimal = false; | ||||
|     width = width_; | ||||
|     height = height_; | ||||
|  | ||||
|     const auto physical_device = device.GetPhysical(); | ||||
|     const auto capabilities{physical_device.GetSurfaceCapabilitiesKHR(surface)}; | ||||
| @@ -88,7 +90,7 @@ void Swapchain::Create(u32 width, u32 height, bool srgb) { | ||||
|     device.GetLogical().WaitIdle(); | ||||
|     Destroy(); | ||||
|  | ||||
|     CreateSwapchain(capabilities, width, height, srgb); | ||||
|     CreateSwapchain(capabilities, srgb); | ||||
|     CreateSemaphores(); | ||||
|     CreateImageViews(); | ||||
|  | ||||
| @@ -148,8 +150,7 @@ void Swapchain::Present(VkSemaphore render_semaphore) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, u32 width, u32 height, | ||||
|                                 bool srgb) { | ||||
| void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb) { | ||||
|     const auto physical_device{device.GetPhysical()}; | ||||
|     const auto formats{physical_device.GetSurfaceFormatsKHR(surface)}; | ||||
|     const auto present_modes{physical_device.GetSurfacePresentModesKHR(surface)}; | ||||
|   | ||||
| @@ -80,9 +80,16 @@ public: | ||||
|         return *present_semaphores[frame_index]; | ||||
|     } | ||||
|  | ||||
|     u32 GetWidth() const { | ||||
|         return width; | ||||
|     } | ||||
|  | ||||
|     u32 GetHeight() const { | ||||
|         return height; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     void CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, u32 width, u32 height, | ||||
|                          bool srgb); | ||||
|     void CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb); | ||||
|     void CreateSemaphores(); | ||||
|     void CreateImageViews(); | ||||
|  | ||||
| @@ -105,6 +112,9 @@ private: | ||||
|     std::vector<u64> resource_ticks; | ||||
|     std::vector<vk::Semaphore> present_semaphores; | ||||
|  | ||||
|     u32 width; | ||||
|     u32 height; | ||||
|  | ||||
|     u32 image_index{}; | ||||
|     u32 frame_index{}; | ||||
|  | ||||
|   | ||||
| @@ -660,6 +660,16 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR | ||||
|         LOG_INFO(Render_Vulkan, "Device doesn't support depth range unrestricted"); | ||||
|     } | ||||
|  | ||||
|     VkPhysicalDeviceDepthClipControlFeaturesEXT depth_clip_control_features; | ||||
|     if (ext_depth_clip_control) { | ||||
|         depth_clip_control_features = { | ||||
|             .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT, | ||||
|             .pNext = nullptr, | ||||
|             .depthClipControl = VK_TRUE, | ||||
|         }; | ||||
|         SetNext(next, depth_clip_control_features); | ||||
|     } | ||||
|  | ||||
|     VkDeviceDiagnosticsConfigCreateInfoNV diagnostics_nv; | ||||
|     if (Settings::values.enable_nsight_aftermath && nv_device_diagnostics_config) { | ||||
|         nsight_aftermath_tracker = std::make_unique<NsightAftermathTracker>(); | ||||
| @@ -1083,6 +1093,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) { | ||||
|     bool has_ext_vertex_input_dynamic_state{}; | ||||
|     bool has_ext_line_rasterization{}; | ||||
|     bool has_ext_primitive_topology_list_restart{}; | ||||
|     bool has_ext_depth_clip_control{}; | ||||
|     for (const std::string& extension : supported_extensions) { | ||||
|         const auto test = [&](std::optional<std::reference_wrapper<bool>> status, const char* name, | ||||
|                               bool push) { | ||||
| @@ -1116,6 +1127,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) { | ||||
|         test(ext_shader_stencil_export, VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME, true); | ||||
|         test(ext_conservative_rasterization, VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME, | ||||
|              true); | ||||
|         test(has_ext_depth_clip_control, VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME, false); | ||||
|         test(has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, false); | ||||
|         test(has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, false); | ||||
|         test(has_ext_extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false); | ||||
| @@ -1279,6 +1291,19 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) { | ||||
|             ext_line_rasterization = true; | ||||
|         } | ||||
|     } | ||||
|     if (has_ext_depth_clip_control) { | ||||
|         VkPhysicalDeviceDepthClipControlFeaturesEXT depth_clip_control_features; | ||||
|         depth_clip_control_features.sType = | ||||
|             VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT; | ||||
|         depth_clip_control_features.pNext = nullptr; | ||||
|         features.pNext = &depth_clip_control_features; | ||||
|         physical.GetFeatures2(features); | ||||
|  | ||||
|         if (depth_clip_control_features.depthClipControl) { | ||||
|             extensions.push_back(VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME); | ||||
|             ext_depth_clip_control = true; | ||||
|         } | ||||
|     } | ||||
|     if (has_khr_workgroup_memory_explicit_layout) { | ||||
|         VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR layout; | ||||
|         layout.sType = | ||||
|   | ||||
| @@ -256,6 +256,11 @@ public: | ||||
|         return ext_depth_range_unrestricted; | ||||
|     } | ||||
|  | ||||
|     /// Returns true if the device supports VK_EXT_depth_clip_control. | ||||
|     bool IsExtDepthClipControlSupported() const { | ||||
|         return ext_depth_clip_control; | ||||
|     } | ||||
|  | ||||
|     /// Returns true if the device supports VK_EXT_shader_viewport_index_layer. | ||||
|     bool IsExtShaderViewportIndexLayerSupported() const { | ||||
|         return ext_shader_viewport_index_layer; | ||||
| @@ -454,6 +459,7 @@ private: | ||||
|     bool khr_swapchain_mutable_format{};         ///< Support for VK_KHR_swapchain_mutable_format. | ||||
|     bool ext_index_type_uint8{};                 ///< Support for VK_EXT_index_type_uint8. | ||||
|     bool ext_sampler_filter_minmax{};            ///< Support for VK_EXT_sampler_filter_minmax. | ||||
|     bool ext_depth_clip_control{};               ///< Support for VK_EXT_depth_clip_control | ||||
|     bool ext_depth_range_unrestricted{};         ///< Support for VK_EXT_depth_range_unrestricted. | ||||
|     bool ext_shader_viewport_index_layer{}; ///< Support for VK_EXT_shader_viewport_index_layer. | ||||
|     bool ext_tooling_info{};                ///< Support for VK_EXT_tooling_info. | ||||
|   | ||||
| @@ -61,8 +61,6 @@ void EmuThread::run() { | ||||
|  | ||||
|     // Main process has been loaded. Make the context current to this thread and begin GPU and CPU | ||||
|     // execution. | ||||
|     gpu.Start(); | ||||
|  | ||||
|     gpu.ObtainContext(); | ||||
|  | ||||
|     emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); | ||||
| @@ -77,6 +75,7 @@ void EmuThread::run() { | ||||
|     emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0); | ||||
|  | ||||
|     gpu.ReleaseContext(); | ||||
|     gpu.Start(); | ||||
|  | ||||
|     system.GetCpuManager().OnGpuReady(); | ||||
|  | ||||
| @@ -229,6 +228,7 @@ class RenderWidget : public QWidget { | ||||
| public: | ||||
|     explicit RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) { | ||||
|         setAttribute(Qt::WA_NativeWindow); | ||||
|         setAttribute(Qt::WA_DontCreateNativeAncestors); | ||||
|         setAttribute(Qt::WA_PaintOnScreen); | ||||
|     } | ||||
|  | ||||
| @@ -319,6 +319,8 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_, | ||||
|     input_subsystem->Initialize(); | ||||
|     this->setMouseTracking(true); | ||||
|  | ||||
|     strict_context_required = QGuiApplication::platformName() == QStringLiteral("wayland"); | ||||
|  | ||||
|     connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete); | ||||
|     connect(this, &GRenderWindow::ExecuteProgramSignal, parent, &GMainWindow::OnExecuteProgram, | ||||
|             Qt::QueuedConnection); | ||||
| @@ -957,6 +959,12 @@ void GRenderWindow::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal | ||||
|  | ||||
| bool GRenderWindow::InitializeOpenGL() { | ||||
| #ifdef HAS_OPENGL | ||||
|     if (!QOpenGLContext::supportsThreadedOpenGL()) { | ||||
|         QMessageBox::warning(this, tr("OpenGL not available!"), | ||||
|                              tr("OpenGL shared contexts are not supported.")); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, | ||||
|     // WA_DontShowOnScreen, WA_DeleteOnClose | ||||
|     auto child = new OpenGLRenderWidget(this); | ||||
|   | ||||
| @@ -2915,9 +2915,14 @@ static QScreen* GuessCurrentScreen(QWidget* window) { | ||||
|         }); | ||||
| } | ||||
|  | ||||
| bool GMainWindow::UsingExclusiveFullscreen() { | ||||
|     return Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive || | ||||
|            QGuiApplication::platformName() == QStringLiteral("wayland"); | ||||
| } | ||||
|  | ||||
| void GMainWindow::ShowFullscreen() { | ||||
|     const auto show_fullscreen = [](QWidget* window) { | ||||
|         if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) { | ||||
|     const auto show_fullscreen = [this](QWidget* window) { | ||||
|         if (UsingExclusiveFullscreen()) { | ||||
|             window->showFullScreen(); | ||||
|             return; | ||||
|         } | ||||
| @@ -2945,7 +2950,7 @@ void GMainWindow::ShowFullscreen() { | ||||
|  | ||||
| void GMainWindow::HideFullscreen() { | ||||
|     if (ui->action_Single_Window_Mode->isChecked()) { | ||||
|         if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) { | ||||
|         if (UsingExclusiveFullscreen()) { | ||||
|             showNormal(); | ||||
|             restoreGeometry(UISettings::values.geometry); | ||||
|         } else { | ||||
| @@ -2959,7 +2964,7 @@ void GMainWindow::HideFullscreen() { | ||||
|         statusBar()->setVisible(ui->action_Show_Status_Bar->isChecked()); | ||||
|         ui->menubar->show(); | ||||
|     } else { | ||||
|         if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) { | ||||
|         if (UsingExclusiveFullscreen()) { | ||||
|             render_window->showNormal(); | ||||
|             render_window->restoreGeometry(UISettings::values.renderwindow_geometry); | ||||
|         } else { | ||||
|   | ||||
| @@ -320,6 +320,7 @@ private slots: | ||||
|     void OnDisplayTitleBars(bool); | ||||
|     void InitializeHotkeys(); | ||||
|     void ToggleFullscreen(); | ||||
|     bool UsingExclusiveFullscreen(); | ||||
|     void ShowFullscreen(); | ||||
|     void HideFullscreen(); | ||||
|     void ToggleWindowMode(); | ||||
|   | ||||
| @@ -115,7 +115,7 @@ bool EmuWindow_SDL2::IsShown() const { | ||||
|  | ||||
| void EmuWindow_SDL2::OnResize() { | ||||
|     int width, height; | ||||
|     SDL_GetWindowSize(render_window, &width, &height); | ||||
|     SDL_GL_GetDrawableSize(render_window, &width, &height); | ||||
|     UpdateCurrentFramebufferLayout(width, height); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -104,6 +104,8 @@ EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsyste | ||||
|         exit(1); | ||||
|     } | ||||
|  | ||||
|     strict_context_required = strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0; | ||||
|  | ||||
|     SetWindowIcon(); | ||||
|  | ||||
|     if (fullscreen) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user