nv_services: Correct buffer queue fencing and GPFifo fencing
This commit is contained in:
parent
ceb5f5079c
commit
737e978f5b
8 changed files with 70 additions and 57 deletions
|
@ -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
|
||||||
|
|
|
@ -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(), ¶ms, sizeof(IoctlSubmitGpfifo));
|
std::memcpy(output.data(), ¶ms, 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(), ¶ms, output.size());
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -135,7 +135,7 @@ private:
|
||||||
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
|
||||||
|
@ -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 {
|
||||||
|
|
25
src/core/hle/service/nvdrv/nvdata.h
Normal file
25
src/core/hle/service/nvdrv/nvdata.h
Normal 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
|
|
@ -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();
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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());
|
||||||
|
|
Loading…
Reference in a new issue