nv_services: Correct buffer queue fencing and GPFifo fencing

This commit is contained in:
Fernando Sahmkow 2019-06-07 11:34:55 -04:00 committed by FernandoS27
parent ceb5f5079c
commit 737e978f5b
8 changed files with 70 additions and 57 deletions

View file

@ -369,6 +369,7 @@ add_library(core STATIC
hle/service/nvdrv/devices/nvmap.h hle/service/nvdrv/devices/nvmap.h
hle/service/nvdrv/interface.cpp hle/service/nvdrv/interface.cpp
hle/service/nvdrv/interface.h hle/service/nvdrv/interface.h
hle/service/nvdrv/nvdata.h
hle/service/nvdrv/nvdrv.cpp hle/service/nvdrv/nvdrv.cpp
hle/service/nvdrv/nvdrv.h hle/service/nvdrv/nvdrv.h
hle/service/nvdrv/nvmemp.cpp hle/service/nvdrv/nvmemp.cpp

View file

@ -155,8 +155,8 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp
Core::System::GetInstance().GPU().PushGPUEntries(std::move(entries)); Core::System::GetInstance().GPU().PushGPUEntries(std::move(entries));
params.fence_out.id = 0; // TODO(Blinkhawk): Figure how thoios fence is set
params.fence_out.value = 0; // params.fence_out.value = 0;
std::memcpy(output.data(), &params, sizeof(IoctlSubmitGpfifo)); std::memcpy(output.data(), &params, sizeof(IoctlSubmitGpfifo));
return 0; return 0;
} }
@ -176,8 +176,8 @@ u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output)
Core::System::GetInstance().GPU().PushGPUEntries(std::move(entries)); Core::System::GetInstance().GPU().PushGPUEntries(std::move(entries));
params.fence_out.id = 0; // TODO(Blinkhawk): Figure how thoios fence is set
params.fence_out.value = 0; // params.fence_out.value = 0;
std::memcpy(output.data(), &params, output.size()); std::memcpy(output.data(), &params, output.size());
return 0; return 0;
} }

View file

@ -113,11 +113,11 @@ private:
static_assert(sizeof(IoctlGetErrorNotification) == 16, static_assert(sizeof(IoctlGetErrorNotification) == 16,
"IoctlGetErrorNotification is incorrect size"); "IoctlGetErrorNotification is incorrect size");
struct IoctlFence { struct Fence {
u32_le id; u32_le id;
u32_le value; u32_le value;
}; };
static_assert(sizeof(IoctlFence) == 8, "IoctlFence is incorrect size"); static_assert(sizeof(Fence) == 8, "Fence is incorrect size");
struct IoctlAllocGpfifoEx { struct IoctlAllocGpfifoEx {
u32_le num_entries; u32_le num_entries;
@ -132,13 +132,13 @@ private:
static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size"); static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size");
struct IoctlAllocGpfifoEx2 { struct IoctlAllocGpfifoEx2 {
u32_le num_entries; // in u32_le num_entries; // in
u32_le flags; // in u32_le flags; // in
u32_le unk0; // in (1 works) u32_le unk0; // in (1 works)
IoctlFence fence_out; // out Fence fence_out; // out
u32_le unk1; // in u32_le unk1; // in
u32_le unk2; // in u32_le unk2; // in
u32_le unk3; // in u32_le unk3; // in
}; };
static_assert(sizeof(IoctlAllocGpfifoEx2) == 32, "IoctlAllocGpfifoEx2 is incorrect size"); static_assert(sizeof(IoctlAllocGpfifoEx2) == 32, "IoctlAllocGpfifoEx2 is incorrect size");
@ -154,9 +154,9 @@ private:
u64_le address; // pointer to gpfifo entry structs u64_le address; // pointer to gpfifo entry structs
u32_le num_entries; // number of fence objects being submitted u32_le num_entries; // number of fence objects being submitted
u32_le flags; 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"); "IoctlSubmitGpfifo is incorrect size");
struct IoctlGetWaitbase { struct IoctlGetWaitbase {

View file

@ -0,0 +1,25 @@
#pragma once
#include <array>
#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<Fence, 4> fences;
};
enum class NvResult : u32 {
Success = 0,
TryAgain = 11,
};
} // namespace Service::Nvidia

View file

@ -8,6 +8,7 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include "common/common_types.h" #include "common/common_types.h"
#include "core/hle/service/nvdrv/nvdata.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
namespace Service::NVFlinger { namespace Service::NVFlinger {
@ -20,13 +21,6 @@ namespace Devices {
class nvdevice; class nvdevice;
} }
struct IoctlFence {
u32 id;
u32 value;
};
static_assert(sizeof(IoctlFence) == 8, "IoctlFence has wrong size");
class Module final { class Module final {
public: public:
Module(); Module();

View file

@ -34,7 +34,8 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer)
buffer_wait_event.writable->Signal(); buffer_wait_event.writable->Signal();
} }
std::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) { std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> BufferQueue::DequeueBuffer(u32 width,
u32 height) {
auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) { 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 // Only consider free buffers. Buffers become free once again after they've been Acquired
// and Released by the compositor, see the NVFlinger::Compose method. // and Released by the compositor, see the NVFlinger::Compose method.
@ -51,7 +52,7 @@ std::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) {
} }
itr->status = Buffer::Status::Dequeued; itr->status = Buffer::Status::Dequeued;
return itr->slot; return {{itr->slot, &itr->multi_fence}};
} }
const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const { 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, void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform,
const Common::Rectangle<int>& crop_rect, u32 swap_interval) { const Common::Rectangle<int>& crop_rect, u32 swap_interval,
Service::Nvidia::MultiFence& multi_fence) {
auto itr = std::find_if(queue.begin(), queue.end(), auto itr = std::find_if(queue.begin(), queue.end(),
[&](const Buffer& buffer) { return buffer.slot == slot; }); [&](const Buffer& buffer) { return buffer.slot == slot; });
ASSERT(itr != queue.end()); ASSERT(itr != queue.end());
@ -72,6 +74,7 @@ void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform,
itr->transform = transform; itr->transform = transform;
itr->crop_rect = crop_rect; itr->crop_rect = crop_rect;
itr->swap_interval = swap_interval; itr->swap_interval = swap_interval;
itr->multi_fence = multi_fence;
} }
std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() { std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() {

View file

@ -12,6 +12,7 @@
#include "common/swap.h" #include "common/swap.h"
#include "core/hle/kernel/object.h" #include "core/hle/kernel/object.h"
#include "core/hle/kernel/writable_event.h" #include "core/hle/kernel/writable_event.h"
#include "core/hle/service/nvdrv/nvdata.h"
namespace Service::NVFlinger { namespace Service::NVFlinger {
@ -69,13 +70,16 @@ public:
BufferTransformFlags transform; BufferTransformFlags transform;
Common::Rectangle<int> crop_rect; Common::Rectangle<int> crop_rect;
u32 swap_interval; u32 swap_interval;
Service::Nvidia::MultiFence multi_fence;
}; };
void SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer); void SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer);
std::optional<u32> DequeueBuffer(u32 width, u32 height); std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> DequeueBuffer(u32 width,
u32 height);
const IGBPBuffer& RequestBuffer(u32 slot) const; const IGBPBuffer& RequestBuffer(u32 slot) const;
void QueueBuffer(u32 slot, BufferTransformFlags transform, void QueueBuffer(u32 slot, BufferTransformFlags transform,
const Common::Rectangle<int>& crop_rect, u32 swap_interval); const Common::Rectangle<int>& crop_rect, u32 swap_interval,
Service::Nvidia::MultiFence& multi_fence);
std::optional<std::reference_wrapper<const Buffer>> AcquireBuffer(); std::optional<std::reference_wrapper<const Buffer>> AcquireBuffer();
void ReleaseBuffer(u32 slot); void ReleaseBuffer(u32 slot);
u32 Query(QueryType type); u32 Query(QueryType type);

View file

@ -21,6 +21,7 @@
#include "core/hle/kernel/readable_event.h" #include "core/hle/kernel/readable_event.h"
#include "core/hle/kernel/thread.h" #include "core/hle/kernel/thread.h"
#include "core/hle/kernel/writable_event.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/nvdrv/nvdrv.h"
#include "core/hle/service/nvflinger/buffer_queue.h" #include "core/hle/service/nvflinger/buffer_queue.h"
#include "core/hle/service/nvflinger/nvflinger.h" #include "core/hle/service/nvflinger/nvflinger.h"
@ -328,32 +329,22 @@ public:
Data data; Data data;
}; };
struct BufferProducerFence {
u32 is_valid;
std::array<Nvidia::IoctlFence, 4> fences;
};
static_assert(sizeof(BufferProducerFence) == 36, "BufferProducerFence has wrong size");
class IGBPDequeueBufferResponseParcel : public Parcel { class IGBPDequeueBufferResponseParcel : public Parcel {
public: 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; ~IGBPDequeueBufferResponseParcel() override = default;
protected: protected:
void SerializeData() override { 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(slot);
Write<u32_le>(1); Write<u32_le>(1);
WriteObject(fence); WriteObject(multi_fence);
Write<u32_le>(0); Write<u32_le>(0);
} }
u32_le slot; u32_le slot;
Service::Nvidia::MultiFence multi_fence;
}; };
class IGBPRequestBufferRequestParcel : public Parcel { class IGBPRequestBufferRequestParcel : public Parcel {
@ -400,12 +391,6 @@ public:
data = Read<Data>(); data = Read<Data>();
} }
struct Fence {
u32_le id;
u32_le value;
};
static_assert(sizeof(Fence) == 8, "Fence has wrong size");
struct Data { struct Data {
u32_le slot; u32_le slot;
INSERT_PADDING_WORDS(3); INSERT_PADDING_WORDS(3);
@ -420,14 +405,13 @@ public:
u32_le sticky_transform; u32_le sticky_transform;
INSERT_PADDING_WORDS(1); INSERT_PADDING_WORDS(1);
u32_le swap_interval; u32_le swap_interval;
u32_le fence_is_valid; Service::Nvidia::MultiFence multi_fence;
std::array<Fence, 2> fences;
Common::Rectangle<int> GetCropRect() const { Common::Rectangle<int> GetCropRect() const {
return {crop_left, crop_top, crop_right, crop_bottom}; 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; Data data;
}; };
@ -548,11 +532,11 @@ private:
IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()}; IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()};
const u32 width{request.data.width}; const u32 width{request.data.width};
const u32 height{request.data.height}; const u32 height{request.data.height};
std::optional<u32> slot = buffer_queue.DequeueBuffer(width, height); auto result = buffer_queue.DequeueBuffer(width, height);
if (slot) { if (result) {
// Buffer is available // Buffer is available
IGBPDequeueBufferResponseParcel response{*slot}; IGBPDequeueBufferResponseParcel response{(*result).first, *(*result).second};
ctx.WriteBuffer(response.Serialize()); ctx.WriteBuffer(response.Serialize());
} else { } else {
// Wait the current thread until a buffer becomes available // Wait the current thread until a buffer becomes available
@ -562,10 +546,11 @@ private:
Kernel::ThreadWakeupReason reason) { Kernel::ThreadWakeupReason reason) {
// Repeat TransactParcel DequeueBuffer when a buffer is available // Repeat TransactParcel DequeueBuffer when a buffer is available
auto& buffer_queue = nv_flinger->FindBufferQueue(id); auto& buffer_queue = nv_flinger->FindBufferQueue(id);
std::optional<u32> slot = buffer_queue.DequeueBuffer(width, height); auto result = buffer_queue.DequeueBuffer(width, height);
ASSERT_MSG(slot != std::nullopt, "Could not dequeue buffer."); ASSERT_MSG(result != std::nullopt, "Could not dequeue buffer.");
IGBPDequeueBufferResponseParcel response{*slot}; IGBPDequeueBufferResponseParcel response{(*result).first,
*(*result).second};
ctx.WriteBuffer(response.Serialize()); ctx.WriteBuffer(response.Serialize());
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
@ -583,7 +568,8 @@ private:
IGBPQueueBufferRequestParcel request{ctx.ReadBuffer()}; IGBPQueueBufferRequestParcel request{ctx.ReadBuffer()};
buffer_queue.QueueBuffer(request.data.slot, request.data.transform, 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}; IGBPQueueBufferResponseParcel response{1280, 720};
ctx.WriteBuffer(response.Serialize()); ctx.WriteBuffer(response.Serialize());