From 737e978f5b1440a044ef90f346c8616c2de49a81 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 7 Jun 2019 11:34:55 -0400 Subject: nv_services: Correct buffer queue fencing and GPFifo fencing --- src/core/CMakeLists.txt | 1 + src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 8 ++-- src/core/hle/service/nvdrv/devices/nvhost_gpu.h | 22 +++++------ src/core/hle/service/nvdrv/nvdata.h | 25 ++++++++++++ src/core/hle/service/nvdrv/nvdrv.h | 8 +--- src/core/hle/service/nvflinger/buffer_queue.cpp | 9 +++-- src/core/hle/service/nvflinger/buffer_queue.h | 8 +++- src/core/hle/service/vi/vi.cpp | 46 ++++++++--------------- 8 files changed, 70 insertions(+), 57 deletions(-) create mode 100644 src/core/hle/service/nvdrv/nvdata.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 30eb9d82e..c22585bfb 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -369,6 +369,7 @@ add_library(core STATIC hle/service/nvdrv/devices/nvmap.h hle/service/nvdrv/interface.cpp hle/service/nvdrv/interface.h + hle/service/nvdrv/nvdata.h hle/service/nvdrv/nvdrv.cpp hle/service/nvdrv/nvdrv.h hle/service/nvdrv/nvmemp.cpp diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 8ce7bc7a5..8a53eddb1 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -155,8 +155,8 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector& input, std::vector& outp Core::System::GetInstance().GPU().PushGPUEntries(std::move(entries)); - params.fence_out.id = 0; - params.fence_out.value = 0; + // TODO(Blinkhawk): Figure how thoios fence is set + // params.fence_out.value = 0; std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo)); return 0; } @@ -176,8 +176,8 @@ u32 nvhost_gpu::KickoffPB(const std::vector& input, std::vector& output) Core::System::GetInstance().GPU().PushGPUEntries(std::move(entries)); - params.fence_out.id = 0; - params.fence_out.value = 0; + // TODO(Blinkhawk): Figure how thoios fence is set + // params.fence_out.value = 0; std::memcpy(output.data(), ¶ms, output.size()); return 0; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index 62beb5c0c..d95cedb09 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -113,11 +113,11 @@ private: static_assert(sizeof(IoctlGetErrorNotification) == 16, "IoctlGetErrorNotification is incorrect size"); - struct IoctlFence { + struct Fence { u32_le id; u32_le value; }; - static_assert(sizeof(IoctlFence) == 8, "IoctlFence is incorrect size"); + static_assert(sizeof(Fence) == 8, "Fence is incorrect size"); struct IoctlAllocGpfifoEx { u32_le num_entries; @@ -132,13 +132,13 @@ private: static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size"); struct IoctlAllocGpfifoEx2 { - u32_le num_entries; // in - u32_le flags; // in - u32_le unk0; // in (1 works) - IoctlFence fence_out; // out - u32_le unk1; // in - u32_le unk2; // in - u32_le unk3; // in + u32_le num_entries; // in + u32_le flags; // in + u32_le unk0; // in (1 works) + Fence fence_out; // out + u32_le unk1; // in + u32_le unk2; // in + u32_le unk3; // in }; static_assert(sizeof(IoctlAllocGpfifoEx2) == 32, "IoctlAllocGpfifoEx2 is incorrect size"); @@ -154,9 +154,9 @@ private: u64_le address; // pointer to gpfifo entry structs u32_le num_entries; // number of fence objects being submitted u32_le flags; - IoctlFence fence_out; // returned new fence object for others to wait on + Fence fence_out; // returned new fence object for others to wait on }; - static_assert(sizeof(IoctlSubmitGpfifo) == 16 + sizeof(IoctlFence), + static_assert(sizeof(IoctlSubmitGpfifo) == 16 + sizeof(Fence), "IoctlSubmitGpfifo is incorrect size"); struct IoctlGetWaitbase { diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h new file mode 100644 index 000000000..7e1dce232 --- /dev/null +++ b/src/core/hle/service/nvdrv/nvdata.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include "common/common_types.h" + +namespace Service::Nvidia { + +struct Fence { + s32 id; + u32 value; +}; + +static_assert(sizeof(Fence) == 8, "Fence has wrong size"); + +struct MultiFence { + u32 num_fences; + std::array fences; +}; + +enum class NvResult : u32 { + Success = 0, + TryAgain = 11, +}; + +} // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 53564f696..bacd7cdb7 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -8,6 +8,7 @@ #include #include #include "common/common_types.h" +#include "core/hle/service/nvdrv/nvdata.h" #include "core/hle/service/service.h" namespace Service::NVFlinger { @@ -20,13 +21,6 @@ namespace Devices { class nvdevice; } -struct IoctlFence { - u32 id; - u32 value; -}; - -static_assert(sizeof(IoctlFence) == 8, "IoctlFence has wrong size"); - class Module final { public: Module(); diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp index dca75c35e..75e47b8c7 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp @@ -34,7 +34,8 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) buffer_wait_event.writable->Signal(); } -std::optional BufferQueue::DequeueBuffer(u32 width, u32 height) { +std::optional> BufferQueue::DequeueBuffer(u32 width, + u32 height) { auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) { // Only consider free buffers. Buffers become free once again after they've been Acquired // and Released by the compositor, see the NVFlinger::Compose method. @@ -51,7 +52,7 @@ std::optional BufferQueue::DequeueBuffer(u32 width, u32 height) { } itr->status = Buffer::Status::Dequeued; - return itr->slot; + return {{itr->slot, &itr->multi_fence}}; } const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const { @@ -63,7 +64,8 @@ const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const { } void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform, - const Common::Rectangle& crop_rect, u32 swap_interval) { + const Common::Rectangle& crop_rect, u32 swap_interval, + Service::Nvidia::MultiFence& multi_fence) { auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) { return buffer.slot == slot; }); ASSERT(itr != queue.end()); @@ -72,6 +74,7 @@ void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform, itr->transform = transform; itr->crop_rect = crop_rect; itr->swap_interval = swap_interval; + itr->multi_fence = multi_fence; } std::optional> BufferQueue::AcquireBuffer() { diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h index 139b98b9f..c163e565c 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.h +++ b/src/core/hle/service/nvflinger/buffer_queue.h @@ -12,6 +12,7 @@ #include "common/swap.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/writable_event.h" +#include "core/hle/service/nvdrv/nvdata.h" namespace Service::NVFlinger { @@ -69,13 +70,16 @@ public: BufferTransformFlags transform; Common::Rectangle crop_rect; u32 swap_interval; + Service::Nvidia::MultiFence multi_fence; }; void SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer); - std::optional DequeueBuffer(u32 width, u32 height); + std::optional> DequeueBuffer(u32 width, + u32 height); const IGBPBuffer& RequestBuffer(u32 slot) const; void QueueBuffer(u32 slot, BufferTransformFlags transform, - const Common::Rectangle& crop_rect, u32 swap_interval); + const Common::Rectangle& crop_rect, u32 swap_interval, + Service::Nvidia::MultiFence& multi_fence); std::optional> AcquireBuffer(); void ReleaseBuffer(u32 slot); u32 Query(QueryType type); diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 55bd252c2..894bcdc04 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -21,6 +21,7 @@ #include "core/hle/kernel/readable_event.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/writable_event.h" +#include "core/hle/service/nvdrv/nvdata.h" #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/nvflinger/buffer_queue.h" #include "core/hle/service/nvflinger/nvflinger.h" @@ -328,32 +329,22 @@ public: Data data; }; -struct BufferProducerFence { - u32 is_valid; - std::array fences; -}; -static_assert(sizeof(BufferProducerFence) == 36, "BufferProducerFence has wrong size"); - class IGBPDequeueBufferResponseParcel : public Parcel { public: - explicit IGBPDequeueBufferResponseParcel(u32 slot) : slot(slot) {} + explicit IGBPDequeueBufferResponseParcel(u32 slot, Service::Nvidia::MultiFence& multi_fence) + : slot(slot), multi_fence(multi_fence) {} ~IGBPDequeueBufferResponseParcel() override = default; protected: void SerializeData() override { - // TODO(Subv): Find out how this Fence is used. - BufferProducerFence fence = {}; - fence.is_valid = 1; - for (auto& fence_ : fence.fences) - fence_.id = -1; - Write(slot); Write(1); - WriteObject(fence); + WriteObject(multi_fence); Write(0); } u32_le slot; + Service::Nvidia::MultiFence multi_fence; }; class IGBPRequestBufferRequestParcel : public Parcel { @@ -400,12 +391,6 @@ public: data = Read(); } - struct Fence { - u32_le id; - u32_le value; - }; - static_assert(sizeof(Fence) == 8, "Fence has wrong size"); - struct Data { u32_le slot; INSERT_PADDING_WORDS(3); @@ -420,14 +405,13 @@ public: u32_le sticky_transform; INSERT_PADDING_WORDS(1); u32_le swap_interval; - u32_le fence_is_valid; - std::array fences; + Service::Nvidia::MultiFence multi_fence; Common::Rectangle GetCropRect() const { return {crop_left, crop_top, crop_right, crop_bottom}; } }; - static_assert(sizeof(Data) == 80, "ParcelData has wrong size"); + static_assert(sizeof(Data) == 96, "ParcelData has wrong size"); Data data; }; @@ -548,11 +532,11 @@ private: IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()}; const u32 width{request.data.width}; const u32 height{request.data.height}; - std::optional slot = buffer_queue.DequeueBuffer(width, height); + auto result = buffer_queue.DequeueBuffer(width, height); - if (slot) { + if (result) { // Buffer is available - IGBPDequeueBufferResponseParcel response{*slot}; + IGBPDequeueBufferResponseParcel response{(*result).first, *(*result).second}; ctx.WriteBuffer(response.Serialize()); } else { // Wait the current thread until a buffer becomes available @@ -562,10 +546,11 @@ private: Kernel::ThreadWakeupReason reason) { // Repeat TransactParcel DequeueBuffer when a buffer is available auto& buffer_queue = nv_flinger->FindBufferQueue(id); - std::optional slot = buffer_queue.DequeueBuffer(width, height); - ASSERT_MSG(slot != std::nullopt, "Could not dequeue buffer."); + auto result = buffer_queue.DequeueBuffer(width, height); + ASSERT_MSG(result != std::nullopt, "Could not dequeue buffer."); - IGBPDequeueBufferResponseParcel response{*slot}; + IGBPDequeueBufferResponseParcel response{(*result).first, + *(*result).second}; ctx.WriteBuffer(response.Serialize()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -583,7 +568,8 @@ private: IGBPQueueBufferRequestParcel request{ctx.ReadBuffer()}; buffer_queue.QueueBuffer(request.data.slot, request.data.transform, - request.data.GetCropRect(), request.data.swap_interval); + request.data.GetCropRect(), request.data.swap_interval, + request.data.multi_fence); IGBPQueueBufferResponseParcel response{1280, 720}; ctx.WriteBuffer(response.Serialize()); -- cgit v1.2.3