Merge branch 'yuzu-emu:master' into cinematic-fix-pr
This commit is contained in:
commit
4e33e59dd9
11 changed files with 121 additions and 13 deletions
2
externals/cubeb
vendored
2
externals/cubeb
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 2d817de7c58b33a7c045edf873f3f9c98e4a2082
|
||||
Subproject commit 48689ae7a73caeb747953f9ed664dc71d2f918d8
|
|
@ -380,13 +380,16 @@ void InputEngine::TriggerOnMotionChange(const PadIdentifier& identifier, int mot
|
|||
if (!configuring || !mapping_callback.on_data) {
|
||||
return;
|
||||
}
|
||||
const auto old_value = GetMotion(identifier, motion);
|
||||
bool is_active = false;
|
||||
if (std::abs(value.accel_x) > 1.5f || std::abs(value.accel_y) > 1.5f ||
|
||||
std::abs(value.accel_z) > 1.5f) {
|
||||
if (std::abs(value.accel_x - old_value.accel_x) > 1.5f ||
|
||||
std::abs(value.accel_y - old_value.accel_y) > 1.5f ||
|
||||
std::abs(value.accel_z - old_value.accel_z) > 1.5f) {
|
||||
is_active = true;
|
||||
}
|
||||
if (std::abs(value.gyro_x) > 0.6f || std::abs(value.gyro_y) > 0.6f ||
|
||||
std::abs(value.gyro_z) > 0.6f) {
|
||||
if (std::abs(value.gyro_x - old_value.gyro_x) > 0.6f ||
|
||||
std::abs(value.gyro_y - old_value.gyro_y) > 0.6f ||
|
||||
std::abs(value.gyro_z - old_value.gyro_z) > 0.6f) {
|
||||
is_active = true;
|
||||
}
|
||||
if (!is_active) {
|
||||
|
|
|
@ -144,6 +144,10 @@ public:
|
|||
return state_tracker;
|
||||
}
|
||||
|
||||
void BarrierFeedbackLoop() const noexcept {
|
||||
// OpenGL does not require a barrier for attachment feedback loops.
|
||||
}
|
||||
|
||||
private:
|
||||
struct StagingBuffers {
|
||||
explicit StagingBuffers(GLenum storage_flags_, GLenum map_flags_);
|
||||
|
|
|
@ -481,12 +481,13 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
|||
if constexpr (Spec::enabled_stages[4]) {
|
||||
prepare_stage(4);
|
||||
}
|
||||
texture_cache.UpdateRenderTargets(false);
|
||||
texture_cache.CheckFeedbackLoop(views);
|
||||
ConfigureDraw(rescaling, render_area);
|
||||
}
|
||||
|
||||
void GraphicsPipeline::ConfigureDraw(const RescalingPushConstant& rescaling,
|
||||
const RenderAreaPushConstant& render_area) {
|
||||
texture_cache.UpdateRenderTargets(false);
|
||||
scheduler.RequestRenderpass(texture_cache.GetFramebuffer());
|
||||
|
||||
if (!is_built.load(std::memory_order::relaxed)) {
|
||||
|
|
|
@ -10,11 +10,16 @@
|
|||
|
||||
namespace Vulkan {
|
||||
|
||||
constexpr u64 FENCE_RESERVE_SIZE = 8;
|
||||
|
||||
MasterSemaphore::MasterSemaphore(const Device& device_) : device(device_) {
|
||||
if (!device.HasTimelineSemaphore()) {
|
||||
static constexpr VkFenceCreateInfo fence_ci{
|
||||
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .pNext = nullptr, .flags = 0};
|
||||
fence = device.GetLogical().CreateFence(fence_ci);
|
||||
free_queue.resize(FENCE_RESERVE_SIZE);
|
||||
std::ranges::generate(free_queue,
|
||||
[&] { return device.GetLogical().CreateFence(fence_ci); });
|
||||
wait_thread = std::jthread([this](std::stop_token token) { WaitThread(token); });
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -167,16 +172,53 @@ VkResult MasterSemaphore::SubmitQueueFence(vk::CommandBuffer& cmdbuf, VkSemaphor
|
|||
.pSignalSemaphores = &signal_semaphore,
|
||||
};
|
||||
|
||||
auto fence = GetFreeFence();
|
||||
auto result = device.GetGraphicsQueue().Submit(submit_info, *fence);
|
||||
|
||||
if (result == VK_SUCCESS) {
|
||||
fence.Wait();
|
||||
fence.Reset();
|
||||
gpu_tick.store(host_tick);
|
||||
gpu_tick.notify_all();
|
||||
std::scoped_lock lock{wait_mutex};
|
||||
wait_queue.emplace(host_tick, std::move(fence));
|
||||
wait_cv.notify_one();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void MasterSemaphore::WaitThread(std::stop_token token) {
|
||||
while (!token.stop_requested()) {
|
||||
u64 host_tick;
|
||||
vk::Fence fence;
|
||||
{
|
||||
std::unique_lock lock{wait_mutex};
|
||||
Common::CondvarWait(wait_cv, lock, token, [this] { return !wait_queue.empty(); });
|
||||
if (token.stop_requested()) {
|
||||
return;
|
||||
}
|
||||
std::tie(host_tick, fence) = std::move(wait_queue.front());
|
||||
wait_queue.pop();
|
||||
}
|
||||
|
||||
fence.Wait();
|
||||
fence.Reset();
|
||||
gpu_tick.store(host_tick);
|
||||
gpu_tick.notify_all();
|
||||
|
||||
std::scoped_lock lock{free_mutex};
|
||||
free_queue.push_front(std::move(fence));
|
||||
}
|
||||
}
|
||||
|
||||
vk::Fence MasterSemaphore::GetFreeFence() {
|
||||
std::scoped_lock lock{free_mutex};
|
||||
if (free_queue.empty()) {
|
||||
static constexpr VkFenceCreateInfo fence_ci{
|
||||
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .pNext = nullptr, .flags = 0};
|
||||
return device.GetLogical().CreateFence(fence_ci);
|
||||
}
|
||||
|
||||
auto fence = std::move(free_queue.back());
|
||||
free_queue.pop_back();
|
||||
return fence;
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
|
|
@ -5,8 +5,10 @@
|
|||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <deque>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <queue>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/polyfill_thread.h"
|
||||
|
@ -17,6 +19,8 @@ namespace Vulkan {
|
|||
class Device;
|
||||
|
||||
class MasterSemaphore {
|
||||
using Waitable = std::pair<u64, vk::Fence>;
|
||||
|
||||
public:
|
||||
explicit MasterSemaphore(const Device& device);
|
||||
~MasterSemaphore();
|
||||
|
@ -57,13 +61,22 @@ private:
|
|||
VkResult SubmitQueueFence(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore,
|
||||
VkSemaphore wait_semaphore, u64 host_tick);
|
||||
|
||||
void WaitThread(std::stop_token token);
|
||||
|
||||
vk::Fence GetFreeFence();
|
||||
|
||||
private:
|
||||
const Device& device; ///< Device.
|
||||
vk::Fence fence; ///< Fence.
|
||||
vk::Semaphore semaphore; ///< Timeline semaphore.
|
||||
std::atomic<u64> gpu_tick{0}; ///< Current known GPU tick.
|
||||
std::atomic<u64> current_tick{1}; ///< Current logical tick.
|
||||
std::mutex wait_mutex;
|
||||
std::mutex free_mutex;
|
||||
std::condition_variable_any wait_cv;
|
||||
std::queue<Waitable> wait_queue; ///< Queue for the fences to be waited on by the wait thread.
|
||||
std::deque<vk::Fence> free_queue; ///< Holds available fences for submission.
|
||||
std::jthread debug_thread; ///< Debug thread to workaround validation layer bugs.
|
||||
std::jthread wait_thread; ///< Helper thread that waits for submitted fences.
|
||||
};
|
||||
|
||||
} // namespace Vulkan
|
||||
|
|
|
@ -861,6 +861,10 @@ VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) {
|
|||
return *buffers[level];
|
||||
}
|
||||
|
||||
void TextureCacheRuntime::BarrierFeedbackLoop() {
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
}
|
||||
|
||||
void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src,
|
||||
std::span<const VideoCommon::ImageCopy> copies) {
|
||||
std::vector<VkBufferImageCopy> vk_in_copies(copies.size());
|
||||
|
|
|
@ -103,6 +103,8 @@ public:
|
|||
|
||||
[[nodiscard]] VkBuffer GetTemporaryBuffer(size_t needed_size);
|
||||
|
||||
void BarrierFeedbackLoop();
|
||||
|
||||
const Device& device;
|
||||
Scheduler& scheduler;
|
||||
MemoryAllocator& memory_allocator;
|
||||
|
|
|
@ -183,6 +183,42 @@ void TextureCache<P>::FillComputeImageViews(std::span<ImageViewInOut> views) {
|
|||
views);
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void TextureCache<P>::CheckFeedbackLoop(std::span<const ImageViewInOut> views) {
|
||||
const bool requires_barrier = [&] {
|
||||
for (const auto& view : views) {
|
||||
if (!view.id) {
|
||||
continue;
|
||||
}
|
||||
auto& image_view = slot_image_views[view.id];
|
||||
|
||||
// Check color targets
|
||||
for (const auto& ct_view_id : render_targets.color_buffer_ids) {
|
||||
if (ct_view_id) {
|
||||
auto& ct_view = slot_image_views[ct_view_id];
|
||||
if (image_view.image_id == ct_view.image_id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check zeta target
|
||||
if (render_targets.depth_buffer_id) {
|
||||
auto& zt_view = slot_image_views[render_targets.depth_buffer_id];
|
||||
if (image_view.image_id == zt_view.image_id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}();
|
||||
|
||||
if (requires_barrier) {
|
||||
runtime.BarrierFeedbackLoop();
|
||||
}
|
||||
}
|
||||
|
||||
template <class P>
|
||||
typename P::Sampler* TextureCache<P>::GetGraphicsSampler(u32 index) {
|
||||
if (index > channel_state->graphics_sampler_table.Limit()) {
|
||||
|
|
|
@ -148,6 +148,9 @@ public:
|
|||
/// Fill image_view_ids with the compute images in indices
|
||||
void FillComputeImageViews(std::span<ImageViewInOut> views);
|
||||
|
||||
/// Handle feedback loops during draws.
|
||||
void CheckFeedbackLoop(std::span<const ImageViewInOut> views);
|
||||
|
||||
/// Get the sampler from the graphics descriptor table in the specified index
|
||||
Sampler* GetGraphicsSampler(u32 index);
|
||||
|
||||
|
|
|
@ -1034,7 +1034,7 @@ void Device::CollectPhysicalMemoryInfo() {
|
|||
}
|
||||
const s64 available_memory = static_cast<s64>(device_access_memory - device_initial_usage);
|
||||
device_access_memory = static_cast<u64>(std::max<s64>(
|
||||
std::min<s64>(available_memory - 8_GiB, 4_GiB), static_cast<s64>(local_memory)));
|
||||
std::min<s64>(available_memory - 8_GiB, 4_GiB), std::min<s64>(local_memory, 4_GiB)));
|
||||
}
|
||||
|
||||
void Device::CollectToolingInfo() {
|
||||
|
|
Loading…
Add table
Reference in a new issue