diff options
| -rw-r--r-- | src/core/hle/service/vi/vi.cpp | 199 | ||||
| -rw-r--r-- | src/core/hle/service/vi/vi.h | 98 | ||||
| -rw-r--r-- | src/core/hle/service/vi/vi_m.cpp | 3 | ||||
| -rw-r--r-- | src/core/hle/service/vi/vi_m.h | 2 |
4 files changed, 261 insertions, 41 deletions
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index fa7d08176..1f218a4f5 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp | |||
| @@ -10,24 +10,6 @@ | |||
| 10 | namespace Service { | 10 | namespace Service { |
| 11 | namespace VI { | 11 | namespace VI { |
| 12 | 12 | ||
| 13 | struct IGBPBuffer { | ||
| 14 | u32_le magic; | ||
| 15 | u32_le width; | ||
| 16 | u32_le height; | ||
| 17 | u32_le stride; | ||
| 18 | u32_le format; | ||
| 19 | u32_le usage; | ||
| 20 | INSERT_PADDING_WORDS(1); | ||
| 21 | u32_le index; | ||
| 22 | INSERT_PADDING_WORDS(3); | ||
| 23 | u32_le gpu_buffer_id; | ||
| 24 | INSERT_PADDING_WORDS(17); | ||
| 25 | u32_le nvmap_handle; | ||
| 26 | INSERT_PADDING_WORDS(61); | ||
| 27 | }; | ||
| 28 | |||
| 29 | static_assert(sizeof(IGBPBuffer) == 0x16C, "IGBPBuffer has wrong size"); | ||
| 30 | |||
| 31 | class Parcel { | 13 | class Parcel { |
| 32 | public: | 14 | public: |
| 33 | // This default size was chosen arbitrarily. | 15 | // This default size was chosen arbitrarily. |
| @@ -363,7 +345,8 @@ private: | |||
| 363 | 345 | ||
| 364 | class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> { | 346 | class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> { |
| 365 | public: | 347 | public: |
| 366 | IHOSBinderDriver() : ServiceFramework("IHOSBinderDriver") { | 348 | IHOSBinderDriver(std::shared_ptr<NVFlinger> nv_flinger) |
| 349 | : ServiceFramework("IHOSBinderDriver"), nv_flinger(std::move(nv_flinger)) { | ||
| 367 | static const FunctionInfo functions[] = { | 350 | static const FunctionInfo functions[] = { |
| 368 | {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"}, | 351 | {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"}, |
| 369 | {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"}, | 352 | {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"}, |
| @@ -404,6 +387,8 @@ private: | |||
| 404 | 387 | ||
| 405 | auto& output_buffer = ctx.BufferDescriptorB()[0]; | 388 | auto& output_buffer = ctx.BufferDescriptorB()[0]; |
| 406 | 389 | ||
| 390 | auto buffer_queue = nv_flinger->GetBufferQueue(id); | ||
| 391 | |||
| 407 | if (transaction == TransactionId::Connect) { | 392 | if (transaction == TransactionId::Connect) { |
| 408 | IGBPConnectRequestParcel request{input_data}; | 393 | IGBPConnectRequestParcel request{input_data}; |
| 409 | IGBPConnectResponseParcel response{1280, 720}; | 394 | IGBPConnectResponseParcel response{1280, 720}; |
| @@ -413,8 +398,7 @@ private: | |||
| 413 | } else if (transaction == TransactionId::SetPreallocatedBuffer) { | 398 | } else if (transaction == TransactionId::SetPreallocatedBuffer) { |
| 414 | IGBPSetPreallocatedBufferRequestParcel request{input_data}; | 399 | IGBPSetPreallocatedBufferRequestParcel request{input_data}; |
| 415 | 400 | ||
| 416 | LOG_WARNING(Service, "Adding graphics buffer %u", request.data.slot); | 401 | buffer_queue->SetPreallocatedBuffer(request.data.slot, request.buffer); |
| 417 | graphic_buffers.push_back(request.buffer); | ||
| 418 | 402 | ||
| 419 | IGBPSetPreallocatedBufferResponseParcel response{}; | 403 | IGBPSetPreallocatedBufferResponseParcel response{}; |
| 420 | auto response_buffer = response.Serialize(); | 404 | auto response_buffer = response.Serialize(); |
| @@ -423,14 +407,18 @@ private: | |||
| 423 | } else if (transaction == TransactionId::DequeueBuffer) { | 407 | } else if (transaction == TransactionId::DequeueBuffer) { |
| 424 | IGBPDequeueBufferRequestParcel request{input_data}; | 408 | IGBPDequeueBufferRequestParcel request{input_data}; |
| 425 | 409 | ||
| 426 | IGBPDequeueBufferResponseParcel response{0}; | 410 | u32 slot = buffer_queue->DequeueBuffer(request.data.pixel_format, request.data.width, |
| 411 | request.data.height); | ||
| 412 | |||
| 413 | IGBPDequeueBufferResponseParcel response{slot}; | ||
| 427 | auto response_buffer = response.Serialize(); | 414 | auto response_buffer = response.Serialize(); |
| 428 | Memory::WriteBlock(output_buffer.Address(), response_buffer.data(), | 415 | Memory::WriteBlock(output_buffer.Address(), response_buffer.data(), |
| 429 | output_buffer.Size()); | 416 | output_buffer.Size()); |
| 430 | } else if (transaction == TransactionId::RequestBuffer) { | 417 | } else if (transaction == TransactionId::RequestBuffer) { |
| 431 | IGBPRequestBufferRequestParcel request{input_data}; | 418 | IGBPRequestBufferRequestParcel request{input_data}; |
| 432 | 419 | ||
| 433 | auto& buffer = graphic_buffers[request.slot]; | 420 | auto& buffer = buffer_queue->RequestBuffer(request.slot); |
| 421 | |||
| 434 | IGBPRequestBufferResponseParcel response{buffer}; | 422 | IGBPRequestBufferResponseParcel response{buffer}; |
| 435 | auto response_buffer = response.Serialize(); | 423 | auto response_buffer = response.Serialize(); |
| 436 | Memory::WriteBlock(output_buffer.Address(), response_buffer.data(), | 424 | Memory::WriteBlock(output_buffer.Address(), response_buffer.data(), |
| @@ -438,12 +426,12 @@ private: | |||
| 438 | } else if (transaction == TransactionId::QueueBuffer) { | 426 | } else if (transaction == TransactionId::QueueBuffer) { |
| 439 | IGBPQueueBufferRequestParcel request{input_data}; | 427 | IGBPQueueBufferRequestParcel request{input_data}; |
| 440 | 428 | ||
| 429 | buffer_queue->QueueBuffer(request.data.slot); | ||
| 430 | |||
| 441 | IGBPQueueBufferResponseParcel response{1280, 720}; | 431 | IGBPQueueBufferResponseParcel response{1280, 720}; |
| 442 | auto response_buffer = response.Serialize(); | 432 | auto response_buffer = response.Serialize(); |
| 443 | Memory::WriteBlock(output_buffer.Address(), response_buffer.data(), | 433 | Memory::WriteBlock(output_buffer.Address(), response_buffer.data(), |
| 444 | output_buffer.Size()); | 434 | output_buffer.Size()); |
| 445 | |||
| 446 | // TODO(Subv): Start drawing here? | ||
| 447 | } else { | 435 | } else { |
| 448 | ASSERT_MSG(false, "Unimplemented"); | 436 | ASSERT_MSG(false, "Unimplemented"); |
| 449 | } | 437 | } |
| @@ -464,7 +452,7 @@ private: | |||
| 464 | rb.Push(RESULT_SUCCESS); | 452 | rb.Push(RESULT_SUCCESS); |
| 465 | } | 453 | } |
| 466 | 454 | ||
| 467 | std::vector<IGBPBuffer> graphic_buffers; | 455 | std::shared_ptr<NVFlinger> nv_flinger; |
| 468 | }; | 456 | }; |
| 469 | 457 | ||
| 470 | class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> { | 458 | class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> { |
| @@ -492,7 +480,8 @@ private: | |||
| 492 | 480 | ||
| 493 | class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { | 481 | class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { |
| 494 | public: | 482 | public: |
| 495 | IManagerDisplayService() : ServiceFramework("IManagerDisplayService") { | 483 | IManagerDisplayService(std::shared_ptr<NVFlinger> nv_flinger) |
| 484 | : ServiceFramework("IManagerDisplayService"), nv_flinger(std::move(nv_flinger)) { | ||
| 496 | static const FunctionInfo functions[] = { | 485 | static const FunctionInfo functions[] = { |
| 497 | {1102, nullptr, "GetDisplayResolution"}, | 486 | {1102, nullptr, "GetDisplayResolution"}, |
| 498 | {2010, &IManagerDisplayService::CreateManagedLayer, "CreateManagedLayer"}, | 487 | {2010, &IManagerDisplayService::CreateManagedLayer, "CreateManagedLayer"}, |
| @@ -511,9 +500,11 @@ private: | |||
| 511 | u64 display = rp.Pop<u64>(); | 500 | u64 display = rp.Pop<u64>(); |
| 512 | u64 aruid = rp.Pop<u64>(); | 501 | u64 aruid = rp.Pop<u64>(); |
| 513 | 502 | ||
| 503 | u64 layer_id = nv_flinger->CreateLayer(display); | ||
| 504 | |||
| 514 | IPC::RequestBuilder rb = rp.MakeBuilder(4, 0, 0, 0); | 505 | IPC::RequestBuilder rb = rp.MakeBuilder(4, 0, 0, 0); |
| 515 | rb.Push(RESULT_SUCCESS); | 506 | rb.Push(RESULT_SUCCESS); |
| 516 | rb.Push<u64>(1); // LayerId | 507 | rb.Push(layer_id); |
| 517 | } | 508 | } |
| 518 | 509 | ||
| 519 | void AddToLayerStack(Kernel::HLERequestContext& ctx) { | 510 | void AddToLayerStack(Kernel::HLERequestContext& ctx) { |
| @@ -525,6 +516,8 @@ private: | |||
| 525 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0, 0, 0); | 516 | IPC::RequestBuilder rb = rp.MakeBuilder(2, 0, 0, 0); |
| 526 | rb.Push(RESULT_SUCCESS); | 517 | rb.Push(RESULT_SUCCESS); |
| 527 | } | 518 | } |
| 519 | |||
| 520 | std::shared_ptr<NVFlinger> nv_flinger; | ||
| 528 | }; | 521 | }; |
| 529 | 522 | ||
| 530 | void IApplicationDisplayService::GetRelayService(Kernel::HLERequestContext& ctx) { | 523 | void IApplicationDisplayService::GetRelayService(Kernel::HLERequestContext& ctx) { |
| @@ -532,7 +525,7 @@ void IApplicationDisplayService::GetRelayService(Kernel::HLERequestContext& ctx) | |||
| 532 | 525 | ||
| 533 | IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; | 526 | IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; |
| 534 | rb.Push(RESULT_SUCCESS); | 527 | rb.Push(RESULT_SUCCESS); |
| 535 | rb.PushIpcInterface<IHOSBinderDriver>(); | 528 | rb.PushIpcInterface<IHOSBinderDriver>(nv_flinger); |
| 536 | } | 529 | } |
| 537 | 530 | ||
| 538 | void IApplicationDisplayService::GetSystemDisplayService(Kernel::HLERequestContext& ctx) { | 531 | void IApplicationDisplayService::GetSystemDisplayService(Kernel::HLERequestContext& ctx) { |
| @@ -548,38 +541,47 @@ void IApplicationDisplayService::GetManagerDisplayService(Kernel::HLERequestCont | |||
| 548 | 541 | ||
| 549 | IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; | 542 | IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; |
| 550 | rb.Push(RESULT_SUCCESS); | 543 | rb.Push(RESULT_SUCCESS); |
| 551 | rb.PushIpcInterface<IManagerDisplayService>(); | 544 | rb.PushIpcInterface<IManagerDisplayService>(nv_flinger); |
| 552 | } | 545 | } |
| 553 | 546 | ||
| 554 | void IApplicationDisplayService::OpenDisplay(Kernel::HLERequestContext& ctx) { | 547 | void IApplicationDisplayService::OpenDisplay(Kernel::HLERequestContext& ctx) { |
| 555 | LOG_WARNING(Service, "(STUBBED) called"); | 548 | LOG_WARNING(Service, "(STUBBED) called"); |
| 556 | IPC::RequestParser rp{ctx}; | 549 | IPC::RequestParser rp{ctx}; |
| 557 | auto data = rp.PopRaw<std::array<u8, 0x40>>(); | 550 | auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); |
| 558 | std::string display_name(data.begin(), data.end()); | 551 | auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); |
| 552 | |||
| 553 | std::string name(name_buf.begin(), end); | ||
| 554 | |||
| 555 | ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet"); | ||
| 559 | 556 | ||
| 560 | IPC::RequestBuilder rb = rp.MakeBuilder(4, 0, 0, 0); | 557 | IPC::RequestBuilder rb = rp.MakeBuilder(4, 0, 0, 0); |
| 561 | rb.Push(RESULT_SUCCESS); | 558 | rb.Push(RESULT_SUCCESS); |
| 562 | rb.Push<u64>(9); // DisplayId | 559 | rb.Push<u64>(nv_flinger->OpenDisplay(name)); |
| 563 | } | 560 | } |
| 564 | 561 | ||
| 565 | void IApplicationDisplayService::OpenLayer(Kernel::HLERequestContext& ctx) { | 562 | void IApplicationDisplayService::OpenLayer(Kernel::HLERequestContext& ctx) { |
| 566 | LOG_WARNING(Service, "(STUBBED) called"); | 563 | LOG_WARNING(Service, "(STUBBED) called"); |
| 567 | IPC::RequestParser rp{ctx}; | 564 | IPC::RequestParser rp{ctx}; |
| 568 | auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); | 565 | auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); |
| 566 | auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); | ||
| 567 | |||
| 568 | std::string display_name(name_buf.begin(), end); | ||
| 569 | |||
| 569 | u64 layer_id = rp.Pop<u64>(); | 570 | u64 layer_id = rp.Pop<u64>(); |
| 570 | u64 aruid = rp.Pop<u64>(); | 571 | u64 aruid = rp.Pop<u64>(); |
| 571 | 572 | ||
| 572 | std::string display_name(name_buf.begin(), name_buf.end()); | ||
| 573 | |||
| 574 | auto& buffer = ctx.BufferDescriptorB()[0]; | 573 | auto& buffer = ctx.BufferDescriptorB()[0]; |
| 575 | 574 | ||
| 576 | NativeWindow native_window{1}; | 575 | u64 display_id = nv_flinger->OpenDisplay(display_name); |
| 576 | u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id); | ||
| 577 | |||
| 578 | NativeWindow native_window{buffer_queue_id}; | ||
| 577 | auto data = native_window.Serialize(); | 579 | auto data = native_window.Serialize(); |
| 578 | Memory::WriteBlock(buffer.Address(), data.data(), data.size()); | 580 | Memory::WriteBlock(buffer.Address(), data.data(), data.size()); |
| 579 | 581 | ||
| 580 | IPC::RequestBuilder rb = rp.MakeBuilder(4, 0, 0, 0); | 582 | IPC::RequestBuilder rb = rp.MakeBuilder(4, 0, 0, 0); |
| 581 | rb.Push(RESULT_SUCCESS); | 583 | rb.Push(RESULT_SUCCESS); |
| 582 | rb.Push<u64>(1280 * 720); // NativeWindowSize | 584 | rb.Push<u64>(data.size()); |
| 583 | } | 585 | } |
| 584 | 586 | ||
| 585 | void IApplicationDisplayService::SetLayerScalingMode(Kernel::HLERequestContext& ctx) { | 587 | void IApplicationDisplayService::SetLayerScalingMode(Kernel::HLERequestContext& ctx) { |
| @@ -602,8 +604,8 @@ void IApplicationDisplayService::GetDisplayVsyncEvent(Kernel::HLERequestContext& | |||
| 602 | rb.PushCopyObjects(vsync_event); | 604 | rb.PushCopyObjects(vsync_event); |
| 603 | } | 605 | } |
| 604 | 606 | ||
| 605 | IApplicationDisplayService::IApplicationDisplayService() | 607 | IApplicationDisplayService::IApplicationDisplayService(std::shared_ptr<NVFlinger> nv_flinger) |
| 606 | : ServiceFramework("IApplicationDisplayService") { | 608 | : ServiceFramework("IApplicationDisplayService"), nv_flinger(std::move(nv_flinger)) { |
| 607 | static const FunctionInfo functions[] = { | 609 | static const FunctionInfo functions[] = { |
| 608 | {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"}, | 610 | {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"}, |
| 609 | {101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"}, | 611 | {101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"}, |
| @@ -624,5 +626,124 @@ void InstallInterfaces(SM::ServiceManager& service_manager) { | |||
| 624 | std::make_shared<VI_M>()->InstallAsService(service_manager); | 626 | std::make_shared<VI_M>()->InstallAsService(service_manager); |
| 625 | } | 627 | } |
| 626 | 628 | ||
| 629 | NVFlinger::NVFlinger() { | ||
| 630 | // Add the different displays to the list of displays. | ||
| 631 | Display default_{"Default", 0}; | ||
| 632 | Display external{"External", 1}; | ||
| 633 | Display edid{"Edid", 2}; | ||
| 634 | Display internal{"Internal", 3}; | ||
| 635 | |||
| 636 | displays.emplace_back(default_); | ||
| 637 | displays.emplace_back(external); | ||
| 638 | displays.emplace_back(edid); | ||
| 639 | displays.emplace_back(internal); | ||
| 640 | } | ||
| 641 | |||
| 642 | u64 NVFlinger::OpenDisplay(const std::string& name) { | ||
| 643 | LOG_WARNING(Service, "Opening display %s", name.c_str()); | ||
| 644 | |||
| 645 | // TODO(Subv): Currently we only support the Default display. | ||
| 646 | ASSERT(name == "Default"); | ||
| 647 | |||
| 648 | auto itr = std::find_if(displays.begin(), displays.end(), | ||
| 649 | [&](const Display& display) { return display.name == name; }); | ||
| 650 | |||
| 651 | ASSERT(itr != displays.end()); | ||
| 652 | |||
| 653 | return itr->id; | ||
| 654 | } | ||
| 655 | |||
| 656 | u64 NVFlinger::CreateLayer(u64 display_id) { | ||
| 657 | auto& display = GetDisplay(display_id); | ||
| 658 | |||
| 659 | ASSERT_MSG(display.layers.empty(), "Only one layer is supported per display at the moment"); | ||
| 660 | |||
| 661 | u64 layer_id = next_layer_id++; | ||
| 662 | u32 buffer_queue_id = next_buffer_queue_id++; | ||
| 663 | auto buffer_queue = std::make_shared<BufferQueue>(buffer_queue_id, layer_id); | ||
| 664 | display.layers.emplace_back(layer_id, buffer_queue); | ||
| 665 | buffer_queues.emplace_back(std::move(buffer_queue)); | ||
| 666 | return layer_id; | ||
| 667 | } | ||
| 668 | |||
| 669 | u32 NVFlinger::GetBufferQueueId(u64 display_id, u64 layer_id) { | ||
| 670 | auto& layer = GetLayer(display_id, layer_id); | ||
| 671 | return layer.buffer_queue->GetId(); | ||
| 672 | } | ||
| 673 | |||
| 674 | std::shared_ptr<BufferQueue> NVFlinger::GetBufferQueue(u32 id) { | ||
| 675 | auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(), | ||
| 676 | [&](const auto& queue) { return queue->GetId() == id; }); | ||
| 677 | |||
| 678 | ASSERT(itr != buffer_queues.end()); | ||
| 679 | return *itr; | ||
| 680 | } | ||
| 681 | |||
| 682 | Display& NVFlinger::GetDisplay(u64 display_id) { | ||
| 683 | auto itr = std::find_if(displays.begin(), displays.end(), | ||
| 684 | [&](const Display& display) { return display.id == display_id; }); | ||
| 685 | |||
| 686 | ASSERT(itr != displays.end()); | ||
| 687 | return *itr; | ||
| 688 | } | ||
| 689 | |||
| 690 | Layer& NVFlinger::GetLayer(u64 display_id, u64 layer_id) { | ||
| 691 | auto& display = GetDisplay(display_id); | ||
| 692 | |||
| 693 | auto itr = std::find_if(display.layers.begin(), display.layers.end(), | ||
| 694 | [&](const Layer& layer) { return layer.id == layer_id; }); | ||
| 695 | |||
| 696 | ASSERT(itr != display.layers.end()); | ||
| 697 | return *itr; | ||
| 698 | } | ||
| 699 | |||
| 700 | BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) {} | ||
| 701 | |||
| 702 | void BufferQueue::SetPreallocatedBuffer(u32 slot, IGBPBuffer& igbp_buffer) { | ||
| 703 | Buffer buffer{}; | ||
| 704 | buffer.slot = slot; | ||
| 705 | buffer.igbp_buffer = igbp_buffer; | ||
| 706 | buffer.status = Buffer::Status::Queued; | ||
| 707 | |||
| 708 | LOG_WARNING(Service, "Adding graphics buffer %u", slot); | ||
| 709 | |||
| 710 | queue.emplace_back(buffer); | ||
| 711 | } | ||
| 712 | |||
| 713 | u32 BufferQueue::DequeueBuffer(u32 pixel_format, u32 width, u32 height) { | ||
| 714 | auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) { | ||
| 715 | // Only consider enqueued buffers | ||
| 716 | if (buffer.status != Buffer::Status::Queued) | ||
| 717 | return false; | ||
| 718 | |||
| 719 | // Make sure that the parameters match. | ||
| 720 | auto& igbp_buffer = buffer.igbp_buffer; | ||
| 721 | return igbp_buffer.format == pixel_format && igbp_buffer.width == width && | ||
| 722 | igbp_buffer.height == height; | ||
| 723 | }); | ||
| 724 | ASSERT(itr != queue.end()); | ||
| 725 | |||
| 726 | itr->status = Buffer::Status::Dequeued; | ||
| 727 | return itr->slot; | ||
| 728 | } | ||
| 729 | |||
| 730 | const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const { | ||
| 731 | auto itr = std::find_if(queue.begin(), queue.end(), | ||
| 732 | [&](const Buffer& buffer) { return buffer.slot == slot; }); | ||
| 733 | ASSERT(itr != queue.end()); | ||
| 734 | ASSERT(itr->status == Buffer::Status::Dequeued); | ||
| 735 | return itr->igbp_buffer; | ||
| 736 | } | ||
| 737 | |||
| 738 | void BufferQueue::QueueBuffer(u32 slot) { | ||
| 739 | auto itr = std::find_if(queue.begin(), queue.end(), | ||
| 740 | [&](const Buffer& buffer) { return buffer.slot == slot; }); | ||
| 741 | ASSERT(itr != queue.end()); | ||
| 742 | ASSERT(itr->status == Buffer::Status::Dequeued); | ||
| 743 | itr->status = Buffer::Status::Queued; | ||
| 744 | } | ||
| 745 | |||
| 746 | Layer::Layer(u64 id, std::shared_ptr<BufferQueue> queue) : id(id), buffer_queue(std::move(queue)) {} | ||
| 747 | |||
| 627 | } // namespace VI | 748 | } // namespace VI |
| 628 | } // namespace Service | 749 | } // namespace Service |
diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h index fbc86498f..a83cd4902 100644 --- a/src/core/hle/service/vi/vi.h +++ b/src/core/hle/service/vi/vi.h | |||
| @@ -4,15 +4,110 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <memory> | ||
| 7 | #include "core/hle/kernel/event.h" | 8 | #include "core/hle/kernel/event.h" |
| 8 | #include "core/hle/service/service.h" | 9 | #include "core/hle/service/service.h" |
| 9 | 10 | ||
| 10 | namespace Service { | 11 | namespace Service { |
| 11 | namespace VI { | 12 | namespace VI { |
| 12 | 13 | ||
| 14 | struct IGBPBuffer { | ||
| 15 | u32_le magic; | ||
| 16 | u32_le width; | ||
| 17 | u32_le height; | ||
| 18 | u32_le stride; | ||
| 19 | u32_le format; | ||
| 20 | u32_le usage; | ||
| 21 | INSERT_PADDING_WORDS(1); | ||
| 22 | u32_le index; | ||
| 23 | INSERT_PADDING_WORDS(3); | ||
| 24 | u32_le gpu_buffer_id; | ||
| 25 | INSERT_PADDING_WORDS(17); | ||
| 26 | u32_le nvmap_handle; | ||
| 27 | INSERT_PADDING_WORDS(61); | ||
| 28 | }; | ||
| 29 | |||
| 30 | static_assert(sizeof(IGBPBuffer) == 0x16C, "IGBPBuffer has wrong size"); | ||
| 31 | |||
| 32 | class BufferQueue { | ||
| 33 | public: | ||
| 34 | BufferQueue(u32 id, u64 layer_id); | ||
| 35 | ~BufferQueue() = default; | ||
| 36 | |||
| 37 | void SetPreallocatedBuffer(u32 slot, IGBPBuffer& buffer); | ||
| 38 | u32 DequeueBuffer(u32 pixel_format, u32 width, u32 height); | ||
| 39 | const IGBPBuffer& RequestBuffer(u32 slot) const; | ||
| 40 | void QueueBuffer(u32 slot); | ||
| 41 | |||
| 42 | u32 GetId() const { return id; } | ||
| 43 | |||
| 44 | private: | ||
| 45 | u32 id; | ||
| 46 | u64 layer_id; | ||
| 47 | |||
| 48 | struct Buffer { | ||
| 49 | enum class Status { None = 0, Queued = 1, Dequeued = 2 }; | ||
| 50 | |||
| 51 | u32 slot; | ||
| 52 | Status status = Status::None; | ||
| 53 | IGBPBuffer igbp_buffer; | ||
| 54 | }; | ||
| 55 | |||
| 56 | std::vector<Buffer> queue; | ||
| 57 | }; | ||
| 58 | |||
| 59 | struct Layer { | ||
| 60 | Layer(u64 id, std::shared_ptr<BufferQueue> queue); | ||
| 61 | ~Layer() = default; | ||
| 62 | |||
| 63 | u64 id; | ||
| 64 | std::shared_ptr<BufferQueue> buffer_queue; | ||
| 65 | }; | ||
| 66 | |||
| 67 | struct Display { | ||
| 68 | std::string name; | ||
| 69 | u64 id; | ||
| 70 | |||
| 71 | std::vector<Layer> layers; | ||
| 72 | }; | ||
| 73 | |||
| 74 | class NVFlinger { | ||
| 75 | public: | ||
| 76 | NVFlinger(); | ||
| 77 | ~NVFlinger() = default; | ||
| 78 | |||
| 79 | /// Opens the specified display and returns the id. | ||
| 80 | u64 OpenDisplay(const std::string& name); | ||
| 81 | |||
| 82 | /// Creates a layer on the specified display and returns the layer id. | ||
| 83 | u64 CreateLayer(u64 display_id); | ||
| 84 | |||
| 85 | /// Gets the buffer queue id of the specified layer in the specified display. | ||
| 86 | u32 GetBufferQueueId(u64 display_id, u64 layer_id); | ||
| 87 | |||
| 88 | /// Obtains a buffer queue identified by the id. | ||
| 89 | std::shared_ptr<BufferQueue> GetBufferQueue(u32 id); | ||
| 90 | |||
| 91 | private: | ||
| 92 | /// Returns the display identified by the specified id. | ||
| 93 | Display& GetDisplay(u64 display_id); | ||
| 94 | |||
| 95 | /// Returns the layer identified by the specified id in the desired display. | ||
| 96 | Layer& GetLayer(u64 display_id, u64 layer_id); | ||
| 97 | |||
| 98 | std::vector<Display> displays; | ||
| 99 | std::vector<std::shared_ptr<BufferQueue>> buffer_queues; | ||
| 100 | |||
| 101 | /// Id to use for the next layer that is created, this counter is shared among all displays. | ||
| 102 | u64 next_layer_id = 1; | ||
| 103 | /// Id to use for the next buffer queue that is created, this counter is shared among all | ||
| 104 | /// layers. | ||
| 105 | u32 next_buffer_queue_id = 1; | ||
| 106 | }; | ||
| 107 | |||
| 13 | class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { | 108 | class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { |
| 14 | public: | 109 | public: |
| 15 | IApplicationDisplayService(); | 110 | IApplicationDisplayService(std::shared_ptr<NVFlinger> nv_flinger); |
| 16 | ~IApplicationDisplayService() = default; | 111 | ~IApplicationDisplayService() = default; |
| 17 | 112 | ||
| 18 | private: | 113 | private: |
| @@ -25,6 +120,7 @@ private: | |||
| 25 | void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx); | 120 | void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx); |
| 26 | 121 | ||
| 27 | Kernel::SharedPtr<Kernel::Event> vsync_event; | 122 | Kernel::SharedPtr<Kernel::Event> vsync_event; |
| 123 | std::shared_ptr<NVFlinger> nv_flinger; | ||
| 28 | }; | 124 | }; |
| 29 | 125 | ||
| 30 | /// Registers all VI services with the specified service manager. | 126 | /// Registers all VI services with the specified service manager. |
diff --git a/src/core/hle/service/vi/vi_m.cpp b/src/core/hle/service/vi/vi_m.cpp index a883ba572..930f5e908 100644 --- a/src/core/hle/service/vi/vi_m.cpp +++ b/src/core/hle/service/vi/vi_m.cpp | |||
| @@ -14,7 +14,7 @@ void VI_M::GetDisplayService(Kernel::HLERequestContext& ctx) { | |||
| 14 | LOG_WARNING(Service, "(STUBBED) called"); | 14 | LOG_WARNING(Service, "(STUBBED) called"); |
| 15 | 15 | ||
| 16 | IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; | 16 | IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; |
| 17 | rb.PushIpcInterface<IApplicationDisplayService>(); | 17 | rb.PushIpcInterface<IApplicationDisplayService>(nv_flinger); |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | VI_M::VI_M() : ServiceFramework("vi:m") { | 20 | VI_M::VI_M() : ServiceFramework("vi:m") { |
| @@ -23,6 +23,7 @@ VI_M::VI_M() : ServiceFramework("vi:m") { | |||
| 23 | {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, | 23 | {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, |
| 24 | }; | 24 | }; |
| 25 | RegisterHandlers(functions); | 25 | RegisterHandlers(functions); |
| 26 | nv_flinger = std::make_shared<NVFlinger>(); | ||
| 26 | } | 27 | } |
| 27 | 28 | ||
| 28 | } // namespace VI | 29 | } // namespace VI |
diff --git a/src/core/hle/service/vi/vi_m.h b/src/core/hle/service/vi/vi_m.h index bfc8c8121..755924d03 100644 --- a/src/core/hle/service/vi/vi_m.h +++ b/src/core/hle/service/vi/vi_m.h | |||
| @@ -17,6 +17,8 @@ public: | |||
| 17 | 17 | ||
| 18 | private: | 18 | private: |
| 19 | void GetDisplayService(Kernel::HLERequestContext& ctx); | 19 | void GetDisplayService(Kernel::HLERequestContext& ctx); |
| 20 | |||
| 21 | std::shared_ptr<NVFlinger> nv_flinger; | ||
| 20 | }; | 22 | }; |
| 21 | 23 | ||
| 22 | } // namespace VI | 24 | } // namespace VI |