NV: Expose the nvdisp_disp0 device and a weak reference to the nvdrv:a service.
NVFlinger will call into the nvdisp_disp0 device to perform screen flips, bypassing the ioctl interface. We now have the address of the framebuffer to draw, we just need to actually put it on the screen.pull/1/head
parent
e21fbd9ae5
commit
34ae2ec644
|
|
@ -8,9 +8,13 @@
|
|||
namespace Service {
|
||||
namespace NVDRV {
|
||||
|
||||
std::weak_ptr<NVDRV_A> nvdrv_a;
|
||||
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager) {
|
||||
std::make_shared<NVDRV_A>()->InstallAsService(service_manager);
|
||||
auto nvdrv = std::make_shared<NVDRV_A>();
|
||||
nvdrv->InstallAsService(service_manager);
|
||||
nvdrv_a = nvdrv;
|
||||
}
|
||||
|
||||
} // namespace nvdrv
|
||||
} // namespace NVDRV
|
||||
} // namespace Service
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
|
@ -18,6 +20,98 @@ public:
|
|||
virtual u32 ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) = 0;
|
||||
};
|
||||
|
||||
class nvmap : public nvdevice {
|
||||
public:
|
||||
/// Returns the allocated address of an nvmap object given its handle.
|
||||
VAddr GetObjectAddress(u32 handle) const;
|
||||
|
||||
u32 ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||
private:
|
||||
// Represents an nvmap object.
|
||||
struct Object {
|
||||
enum class Status { Created, Allocated };
|
||||
u32 id;
|
||||
u32 size;
|
||||
u32 flags;
|
||||
u32 align;
|
||||
u8 kind;
|
||||
VAddr addr;
|
||||
Status status;
|
||||
};
|
||||
|
||||
u32 next_handle = 1;
|
||||
u32 next_id = 1;
|
||||
std::unordered_map<u32, std::shared_ptr<Object>> handles;
|
||||
|
||||
enum IoctlCommands {
|
||||
IocCreateCommand = 0xC0080101,
|
||||
IocFromIdCommand = 0xC0080103,
|
||||
IocAllocCommand = 0xC0200104,
|
||||
IocParamCommand = 0xC00C0109,
|
||||
IocGetIdCommand = 0xC008010E
|
||||
};
|
||||
|
||||
struct IocCreateParams {
|
||||
// Input
|
||||
u32_le size;
|
||||
// Output
|
||||
u32_le handle;
|
||||
};
|
||||
|
||||
struct IocAllocParams {
|
||||
// Input
|
||||
u32_le handle;
|
||||
u32_le heap_mask;
|
||||
u32_le flags;
|
||||
u32_le align;
|
||||
u8 kind;
|
||||
INSERT_PADDING_BYTES(7);
|
||||
u64_le addr;
|
||||
};
|
||||
|
||||
struct IocGetIdParams {
|
||||
// Output
|
||||
u32_le id;
|
||||
// Input
|
||||
u32_le handle;
|
||||
};
|
||||
|
||||
struct IocFromIdParams {
|
||||
// Input
|
||||
u32_le id;
|
||||
// Output
|
||||
u32_le handle;
|
||||
};
|
||||
|
||||
struct IocParamParams {
|
||||
// Input
|
||||
u32_le handle;
|
||||
u32_le type;
|
||||
// Output
|
||||
u32_le value;
|
||||
};
|
||||
|
||||
u32 IocCreate(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 IocAlloc(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 IocGetId(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 IocFromId(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 IocParam(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
};
|
||||
|
||||
class nvdisp_disp0 : public nvdevice {
|
||||
public:
|
||||
nvdisp_disp0(std::shared_ptr<nvmap> nvmap_dev) : nvdevice(), nvmap_dev(std::move(nvmap_dev)) {}
|
||||
~nvdisp_disp0() = default;
|
||||
|
||||
u32 ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||
|
||||
/// Performs a screen flip, drawing the buffer pointed to by the handle.
|
||||
void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride);
|
||||
|
||||
private:
|
||||
std::shared_ptr<nvmap> nvmap_dev;
|
||||
};
|
||||
|
||||
/// Registers all NVDRV services with the specified service manager.
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager);
|
||||
|
||||
|
|
|
|||
|
|
@ -18,9 +18,16 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class nvmap : public nvdevice {
|
||||
public:
|
||||
u32 ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) override {
|
||||
VAddr nvmap::GetObjectAddress(u32 handle) const {
|
||||
auto itr = handles.find(handle);
|
||||
ASSERT(itr != handles.end());
|
||||
|
||||
auto object = itr->second;
|
||||
ASSERT(object->status == Object::Status::Allocated);
|
||||
return object->addr;
|
||||
}
|
||||
|
||||
u32 nvmap::ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
switch (command) {
|
||||
case IocCreateCommand:
|
||||
return IocCreate(input, output);
|
||||
|
|
@ -35,74 +42,9 @@ public:
|
|||
}
|
||||
|
||||
ASSERT(false, "Unimplemented");
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Represents an nvmap object.
|
||||
struct Object {
|
||||
enum class Status { Created, Allocated };
|
||||
u32 id;
|
||||
u32 size;
|
||||
u32 flags;
|
||||
u32 align;
|
||||
u8 kind;
|
||||
u64 addr;
|
||||
Status status;
|
||||
};
|
||||
|
||||
u32 next_handle = 1;
|
||||
u32 next_id = 1;
|
||||
std::unordered_map<u32, std::shared_ptr<Object>> handles;
|
||||
|
||||
enum IoctlCommands {
|
||||
IocCreateCommand = 0xC0080101,
|
||||
IocFromIdCommand = 0xC0080103,
|
||||
IocAllocCommand = 0xC0200104,
|
||||
IocParamCommand = 0xC00C0109,
|
||||
IocGetIdCommand = 0xC008010E
|
||||
};
|
||||
|
||||
struct IocCreateParams {
|
||||
// Input
|
||||
u32_le size;
|
||||
// Output
|
||||
u32_le handle;
|
||||
};
|
||||
|
||||
struct IocAllocParams {
|
||||
// Input
|
||||
u32_le handle;
|
||||
u32_le heap_mask;
|
||||
u32_le flags;
|
||||
u32_le align;
|
||||
u8 kind;
|
||||
INSERT_PADDING_BYTES(7);
|
||||
u64_le addr;
|
||||
};
|
||||
|
||||
struct IocGetIdParams {
|
||||
// Output
|
||||
u32_le id;
|
||||
// Input
|
||||
u32_le handle;
|
||||
};
|
||||
|
||||
struct IocFromIdParams {
|
||||
// Input
|
||||
u32_le id;
|
||||
// Output
|
||||
u32_le handle;
|
||||
};
|
||||
|
||||
struct IocParamParams {
|
||||
// Input
|
||||
u32_le handle;
|
||||
u32_le type;
|
||||
// Output
|
||||
u32_le value;
|
||||
};
|
||||
|
||||
u32 IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IocCreateParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
|
||||
|
|
@ -121,9 +63,9 @@ private:
|
|||
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
u32 IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IocAllocParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
|
||||
|
|
@ -141,9 +83,9 @@ private:
|
|||
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
u32 IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IocGetIdParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
|
||||
|
|
@ -156,9 +98,9 @@ private:
|
|||
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
u32 IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IocFromIdParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
|
||||
|
|
@ -176,9 +118,9 @@ private:
|
|||
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
u32 IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 };
|
||||
|
||||
IocParamParams params;
|
||||
|
|
@ -212,8 +154,20 @@ private:
|
|||
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
u32 nvdisp_disp0::ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
ASSERT(false, "Unimplemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height,
|
||||
u32 stride) {
|
||||
VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle);
|
||||
LOG_WARNING(Service,
|
||||
"Drawing from address %llx offset %08X Width %u Height %u Stride %u Format %u",
|
||||
addr, offset, width, height, stride, format);
|
||||
}
|
||||
|
||||
void NVDRV_A::Open(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service, "(STUBBED) called");
|
||||
|
|
@ -275,8 +229,10 @@ NVDRV_A::NVDRV_A() : ServiceFramework("nvdrv:a") {
|
|||
};
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto nvmap_dev = std::make_shared<nvmap>();
|
||||
devices["/dev/nvhost-as-gpu"] = std::make_shared<nvhost_as_gpu>();
|
||||
devices["/dev/nvmap"] = std::make_shared<nvmap>();
|
||||
devices["/dev/nvmap"] = nvmap_dev;
|
||||
devices["/dev/nvdisp_disp0"] = std::make_shared<nvdisp_disp0>(nvmap_dev);
|
||||
}
|
||||
|
||||
} // namespace NVDRV
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
#include <memory>
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/nvdrv/nvdrv.h"
|
||||
|
||||
namespace Service {
|
||||
namespace NVDRV {
|
||||
|
|
@ -15,6 +16,15 @@ public:
|
|||
NVDRV_A();
|
||||
~NVDRV_A() = default;
|
||||
|
||||
/// Returns a pointer to one of the available devices, identified by its name.
|
||||
template <typename T>
|
||||
std::shared_ptr<T> GetDevice(std::string name) {
|
||||
auto itr = devices.find(name);
|
||||
if (itr == devices.end())
|
||||
return nullptr;
|
||||
return std::static_pointer_cast<T>(itr->second);
|
||||
}
|
||||
|
||||
private:
|
||||
void Open(Kernel::HLERequestContext& ctx);
|
||||
void Ioctl(Kernel::HLERequestContext& ctx);
|
||||
|
|
@ -26,5 +36,7 @@ private:
|
|||
std::unordered_map<std::string, std::shared_ptr<nvdevice>> devices;
|
||||
};
|
||||
|
||||
extern std::weak_ptr<NVDRV_A> nvdrv_a;
|
||||
|
||||
} // namespace NVDRV
|
||||
} // namespace Service
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include "common/scope_exit.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/service/nvdrv/nvdrv_a.h"
|
||||
#include "core/hle/service/vi/vi.h"
|
||||
#include "core/hle/service/vi/vi_m.h"
|
||||
|
||||
|
|
@ -743,7 +744,19 @@ void NVFlinger::Compose() {
|
|||
continue;
|
||||
}
|
||||
|
||||
// TODO(Subv): Send the buffer to the GPU for drawing.
|
||||
auto& igbp_buffer = buffer->igbp_buffer;
|
||||
|
||||
// Now send the buffer to the GPU for drawing.
|
||||
auto nvdrv = NVDRV::nvdrv_a.lock();
|
||||
ASSERT(nvdrv);
|
||||
|
||||
// TODO(Subv): Support more than just disp0. The display device selection is probably based
|
||||
// on which display we're drawing (Default, Internal, External, etc)
|
||||
auto nvdisp = nvdrv->GetDevice<NVDRV::nvdisp_disp0>("/dev/nvdisp_disp0");
|
||||
ASSERT(nvdisp);
|
||||
|
||||
nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.format,
|
||||
igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride);
|
||||
|
||||
buffer_queue->ReleaseBuffer(buffer->slot);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@ struct IGBPBuffer {
|
|||
u32_le gpu_buffer_id;
|
||||
INSERT_PADDING_WORDS(17);
|
||||
u32_le nvmap_handle;
|
||||
INSERT_PADDING_WORDS(61);
|
||||
u32_le offset;
|
||||
INSERT_PADDING_WORDS(60);
|
||||
};
|
||||
|
||||
static_assert(sizeof(IGBPBuffer) == 0x16C, "IGBPBuffer has wrong size");
|
||||
|
|
|
|||
Loading…
Reference in New Issue