diff options
| -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 a2d55eaee..7923e1c0d 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 a8f305d33..fd59c1dba 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 af6b7f7aa..cede4a883 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 09522a486..af1017881 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 67d82c2bf..56aafe6bf 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 576c4ce32..9604bd1c2 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");  | 
