diff options
author | Subv <subv2112@gmail.com> | 2018-01-08 21:30:22 -0500 |
---|---|---|
committer | bunnei <bunneidev@gmail.com> | 2018-01-10 23:28:29 -0500 |
commit | 34ae2ec644f49b04d6c6b82742812b6a8a3ef8b5 (patch) | |
tree | b3b01b63dd0fa4fdc240a549257b685595f277cf /src | |
parent | e21fbd9ae5d8139d585019228e1fb1a6229f244c (diff) |
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.
Diffstat (limited to 'src')
-rw-r--r-- | src/core/hle/service/nvdrv/nvdrv.cpp | 8 | ||||
-rw-r--r-- | src/core/hle/service/nvdrv/nvdrv.h | 94 | ||||
-rw-r--r-- | src/core/hle/service/nvdrv/nvdrv_a.cpp | 290 | ||||
-rw-r--r-- | src/core/hle/service/nvdrv/nvdrv_a.h | 14 | ||||
-rw-r--r-- | src/core/hle/service/vi/vi.cpp | 15 | ||||
-rw-r--r-- | src/core/hle/service/vi/vi.h | 3 |
6 files changed, 252 insertions, 172 deletions
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index a2d55eaeec..7923e1c0d3 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -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 diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index a8f305d331..fd59c1dba7 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -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); diff --git a/src/core/hle/service/nvdrv/nvdrv_a.cpp b/src/core/hle/service/nvdrv/nvdrv_a.cpp index af6b7f7aaa..cede4a883f 100644 --- a/src/core/hle/service/nvdrv/nvdrv_a.cpp +++ b/src/core/hle/service/nvdrv/nvdrv_a.cpp @@ -18,202 +18,156 @@ public: } }; -class nvmap : public nvdevice { -public: - u32 ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) override { - switch (command) { - case IocCreateCommand: - return IocCreate(input, output); - case IocAllocCommand: - return IocAlloc(input, output); - case IocGetIdCommand: - return IocGetId(input, output); - case IocFromIdCommand: - return IocFromId(input, output); - case IocParamCommand: - return IocParam(input, output); - } +VAddr nvmap::GetObjectAddress(u32 handle) const { + auto itr = handles.find(handle); + ASSERT(itr != handles.end()); - ASSERT(false, "Unimplemented"); + 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); + case IocAllocCommand: + return IocAlloc(input, output); + case IocGetIdCommand: + return IocGetId(input, output); + case IocFromIdCommand: + return IocFromId(input, output); + case IocParamCommand: + return IocParam(input, output); } -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; - }; + ASSERT(false, "Unimplemented"); +} - u32 next_handle = 1; - u32 next_id = 1; - std::unordered_map<u32, std::shared_ptr<Object>> handles; +u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { + IocCreateParams params; + std::memcpy(¶ms, input.data(), sizeof(params)); - enum IoctlCommands { - IocCreateCommand = 0xC0080101, - IocFromIdCommand = 0xC0080103, - IocAllocCommand = 0xC0200104, - IocParamCommand = 0xC00C0109, - IocGetIdCommand = 0xC008010E - }; + // Create a new nvmap object and obtain a handle to it. + auto object = std::make_shared<Object>(); + object->id = next_id++; + object->size = params.size; + object->status = Object::Status::Created; - struct IocCreateParams { - // Input - u32_le size; - // Output - u32_le handle; - }; + u32 handle = next_handle++; + handles[handle] = std::move(object); - 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; - }; + LOG_WARNING(Service, "(STUBBED) size 0x%08X", params.size); - struct IocGetIdParams { - // Output - u32_le id; - // Input - u32_le handle; - }; + params.handle = handle; - struct IocFromIdParams { - // Input - u32_le id; - // Output - u32_le handle; - }; + std::memcpy(output.data(), ¶ms, sizeof(params)); + return 0; +} - struct IocParamParams { - // Input - u32_le handle; - u32_le type; - // Output - u32_le value; - }; +u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { + IocAllocParams params; + std::memcpy(¶ms, input.data(), sizeof(params)); - u32 IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { - IocCreateParams params; - std::memcpy(¶ms, input.data(), sizeof(params)); + auto itr = handles.find(params.handle); + ASSERT(itr != handles.end()); - // Create a new nvmap object and obtain a handle to it. - auto object = std::make_shared<Object>(); - object->id = next_id++; - object->size = params.size; - object->status = Object::Status::Created; + auto object = itr->second; + object->flags = params.flags; + object->align = params.align; + object->kind = params.kind; + object->addr = params.addr; + object->status = Object::Status::Allocated; - u32 handle = next_handle++; - handles[handle] = std::move(object); + LOG_WARNING(Service, "(STUBBED) Allocated address 0x%llx", params.addr); - LOG_WARNING(Service, "(STUBBED) size 0x%08X", params.size); + std::memcpy(output.data(), ¶ms, sizeof(params)); + return 0; +} - params.handle = handle; +u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) { + IocGetIdParams params; + std::memcpy(¶ms, input.data(), sizeof(params)); - std::memcpy(output.data(), ¶ms, sizeof(params)); - return 0; - } + LOG_WARNING(Service, "called"); - u32 IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { - IocAllocParams params; - std::memcpy(¶ms, input.data(), sizeof(params)); + auto itr = handles.find(params.handle); + ASSERT(itr != handles.end()); - auto itr = handles.find(params.handle); - ASSERT(itr != handles.end()); + params.id = itr->second->id; - auto object = itr->second; - object->flags = params.flags; - object->align = params.align; - object->kind = params.kind; - object->addr = params.addr; - object->status = Object::Status::Allocated; + std::memcpy(output.data(), ¶ms, sizeof(params)); + return 0; +} - LOG_WARNING(Service, "(STUBBED) Allocated address 0x%llx", params.addr); +u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { + IocFromIdParams params; + std::memcpy(¶ms, input.data(), sizeof(params)); - std::memcpy(output.data(), ¶ms, sizeof(params)); - return 0; - } + LOG_WARNING(Service, "(STUBBED) called"); - u32 IocGetId(const std::vector<u8>& input, std::vector<u8>& output) { - IocGetIdParams params; - std::memcpy(¶ms, input.data(), sizeof(params)); + auto itr = std::find_if(handles.begin(), handles.end(), + [&](const auto& entry) { return entry.second->id == params.id; }); + ASSERT(itr != handles.end()); - LOG_WARNING(Service, "called"); + // Make a new handle for the object + u32 handle = next_handle++; + handles[handle] = itr->second; - auto itr = handles.find(params.handle); - ASSERT(itr != handles.end()); + params.handle = handle; - params.id = itr->second->id; + std::memcpy(output.data(), ¶ms, sizeof(params)); + return 0; +} - std::memcpy(output.data(), ¶ms, sizeof(params)); - return 0; +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; + std::memcpy(¶ms, input.data(), sizeof(params)); + + LOG_WARNING(Service, "(STUBBED) called type=%u", params.type); + + auto itr = handles.find(params.handle); + ASSERT(itr != handles.end()); + + auto object = itr->second; + ASSERT(object->status == Object::Status::Allocated); + + switch (static_cast<ParamTypes>(params.type)) { + case ParamTypes::Size: + params.value = object->size; + break; + case ParamTypes::Alignment: + params.value = object->align; + break; + case ParamTypes::Heap: + // TODO(Subv): Seems to be a hardcoded value? + params.value = 0x40000000; + break; + case ParamTypes::Kind: + params.value = object->kind; + break; + default: + ASSERT(false, "Unimplemented"); } - u32 IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { - IocFromIdParams params; - std::memcpy(¶ms, input.data(), sizeof(params)); - - LOG_WARNING(Service, "(STUBBED) called"); - - auto itr = std::find_if(handles.begin(), handles.end(), - [&](const auto& entry) { return entry.second->id == params.id; }); - ASSERT(itr != handles.end()); - - // Make a new handle for the object - u32 handle = next_handle++; - handles[handle] = itr->second; - - params.handle = handle; + std::memcpy(output.data(), ¶ms, sizeof(params)); + return 0; +} - 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; +} - u32 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; - std::memcpy(¶ms, input.data(), sizeof(params)); - - LOG_WARNING(Service, "(STUBBED) called type=%u", params.type); - - auto itr = handles.find(params.handle); - ASSERT(itr != handles.end()); - - auto object = itr->second; - ASSERT(object->status == Object::Status::Allocated); - - switch (static_cast<ParamTypes>(params.type)) { - case ParamTypes::Size: - params.value = object->size; - break; - case ParamTypes::Alignment: - params.value = object->align; - break; - case ParamTypes::Heap: - // TODO(Subv): Seems to be a hardcoded value? - params.value = 0x40000000; - break; - case ParamTypes::Kind: - params.value = object->kind; - break; - default: - ASSERT(false, "Unimplemented"); - } - - std::memcpy(output.data(), ¶ms, sizeof(params)); - 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 diff --git a/src/core/hle/service/nvdrv/nvdrv_a.h b/src/core/hle/service/nvdrv/nvdrv_a.h index 09522a4869..af10178816 100644 --- a/src/core/hle/service/nvdrv/nvdrv_a.h +++ b/src/core/hle/service/nvdrv/nvdrv_a.h @@ -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 diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 67d82c2bf7..56aafe6bf2 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -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); } diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h index 576c4ce32b..9604bd1c29 100644 --- a/src/core/hle/service/vi/vi.h +++ b/src/core/hle/service/vi/vi.h @@ -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"); |