From 0704b645df4829eb125e43b420cf12914fb3cf28 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 18:05:37 -0800 Subject: common: logging: Add a logger for NVFlinger. --- src/common/logging/filter.cpp | 1 + src/common/logging/types.h | 1 + 2 files changed, 2 insertions(+) (limited to 'src') diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index 4afc1369a..9120cc178 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp @@ -119,6 +119,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) { SUB(Service, NPNS) \ SUB(Service, NS) \ SUB(Service, NVDRV) \ + SUB(Service, NVFlinger) \ SUB(Service, OLSC) \ SUB(Service, PCIE) \ SUB(Service, PCTL) \ diff --git a/src/common/logging/types.h b/src/common/logging/types.h index 2b6e4daa7..f803ab796 100644 --- a/src/common/logging/types.h +++ b/src/common/logging/types.h @@ -87,6 +87,7 @@ enum class Class : u8 { Service_NPNS, ///< The NPNS service Service_NS, ///< The NS services Service_NVDRV, ///< The NVDRV (Nvidia driver) service + Service_NVFlinger, ///< The NVFlinger service Service_OLSC, ///< The OLSC service Service_PCIE, ///< The PCIe service Service_PCTL, ///< The PCTL (Parental control) service -- cgit v1.2.3 From d47575f2c5b125426e9d81a10bd7ce3d7e813dbf Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 18:10:29 -0800 Subject: hle: nvflinger: Add implementation for Rect class. --- src/core/CMakeLists.txt | 1 + src/core/hle/service/nvflinger/ui/rect.h | 75 ++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 src/core/hle/service/nvflinger/ui/rect.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index a6f442316..49a49acdf 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -539,6 +539,7 @@ add_library(core STATIC hle/service/nvflinger/buffer_queue.h hle/service/nvflinger/nvflinger.cpp hle/service/nvflinger/nvflinger.h + hle/service/nvflinger/ui/rect.h hle/service/olsc/olsc.cpp hle/service/olsc/olsc.h hle/service/pcie/pcie.cpp diff --git a/src/core/hle/service/nvflinger/ui/rect.h b/src/core/hle/service/nvflinger/ui/rect.h new file mode 100644 index 000000000..847f6f4ae --- /dev/null +++ b/src/core/hle/service/nvflinger/ui/rect.h @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project +// Copyright 2006 The Android Open Source Project +// Parts of this implementation were base on: +// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/ui/Rect.h + +#pragma once + +#include +#include + +#include "common/common_types.h" + +namespace android { + +class Rect final { +public: + constexpr Rect() = default; + + constexpr Rect(s32 width_, s32 height_) : right{width_}, bottom{height_} {} + + constexpr s32 Left() const { + return left; + } + + constexpr s32 Top() const { + return top; + } + + constexpr s32 Right() const { + return right; + } + + constexpr s32 Bottom() const { + return bottom; + } + + constexpr bool IsEmpty() const { + return (GetWidth() <= 0) || (GetHeight() <= 0); + } + + constexpr s32 GetWidth() const { + return right - left; + } + + constexpr s32 GetHeight() const { + return bottom - top; + } + + constexpr bool operator==(const Rect& rhs) const { + return (left == rhs.left) && (top == rhs.top) && (right == rhs.right) && + (bottom == rhs.bottom); + } + + constexpr bool operator!=(const Rect& rhs) const { + return !operator==(rhs); + } + + constexpr bool Intersect(const Rect& with, Rect* result) const { + result->left = std::max(left, with.left); + result->top = std::max(top, with.top); + result->right = std::min(right, with.right); + result->bottom = std::min(bottom, with.bottom); + return !result->IsEmpty(); + } + +private: + s32 left{}; + s32 top{}; + s32 right{}; + s32 bottom{}; +}; +static_assert(sizeof(Rect) == 16, "Rect has wrong size"); + +} // namespace android -- cgit v1.2.3 From 8c274653250715189f1c774fd086993057c11d03 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 18:10:54 -0800 Subject: hle: nvflinger: Add implementation for Fence class. --- src/core/CMakeLists.txt | 2 ++ src/core/hle/service/nvflinger/ui/fence.h | 32 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/core/hle/service/nvflinger/ui/fence.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 49a49acdf..6cca114db 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -539,6 +539,8 @@ add_library(core STATIC hle/service/nvflinger/buffer_queue.h hle/service/nvflinger/nvflinger.cpp hle/service/nvflinger/nvflinger.h + hle/service/nvflinger/status.h + hle/service/nvflinger/ui/fence.h hle/service/nvflinger/ui/rect.h hle/service/olsc/olsc.cpp hle/service/olsc/olsc.h diff --git a/src/core/hle/service/nvflinger/ui/fence.h b/src/core/hle/service/nvflinger/ui/fence.h new file mode 100644 index 000000000..80ce98782 --- /dev/null +++ b/src/core/hle/service/nvflinger/ui/fence.h @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project +// Copyright 2012 The Android Open Source Project +// Parts of this implementation were base on: +// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/ui/Fence.h + +#pragma once + +#include + +#include "common/common_types.h" +#include "core/hle/service/nvdrv/nvdata.h" + +namespace android { + +class Fence { +public: + constexpr Fence() = default; + + static constexpr Fence NoFence() { + Fence fence; + fence.fences[0].id = -1; + return fence; + } + +public: + u32 num_fences{}; + std::array fences{}; +}; +static_assert(sizeof(Fence) == 36, "Fence has wrong size"); + +} // namespace android -- cgit v1.2.3 From 5a8b9a97062d6dbd64f4401036a3a4445ed4fe1b Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 18:11:32 -0800 Subject: hle: nvflinger: Add implementation for GraphicBuffer class. --- src/core/CMakeLists.txt | 1 + src/core/hle/service/nvflinger/ui/graphic_buffer.h | 100 +++++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 src/core/hle/service/nvflinger/ui/graphic_buffer.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 6cca114db..5e9b959a5 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -541,6 +541,7 @@ add_library(core STATIC hle/service/nvflinger/nvflinger.h hle/service/nvflinger/status.h hle/service/nvflinger/ui/fence.h + hle/service/nvflinger/ui/graphic_buffer.h hle/service/nvflinger/ui/rect.h hle/service/olsc/olsc.cpp hle/service/olsc/olsc.h diff --git a/src/core/hle/service/nvflinger/ui/graphic_buffer.h b/src/core/hle/service/nvflinger/ui/graphic_buffer.h new file mode 100644 index 000000000..c1e54d9ed --- /dev/null +++ b/src/core/hle/service/nvflinger/ui/graphic_buffer.h @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project +// Copyright 2007 The Android Open Source Project +// Parts of this implementation were base on: +// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/ui/GraphicBuffer.h + +#pragma once + +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "core/hle/service/nvflinger/pixel_format.h" + +namespace android { + +class GraphicBuffer final { +public: + constexpr GraphicBuffer() = default; + + constexpr GraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_) + : width{static_cast(width_)}, height{static_cast(height_)}, format{format_}, + usage{static_cast(usage_)} {} + + constexpr u32 Width() const { + return static_cast(width); + } + + constexpr u32 Height() const { + return static_cast(height); + } + + constexpr u32 Stride() const { + return static_cast(stride); + } + + constexpr u32 Usage() const { + return static_cast(usage); + } + + constexpr PixelFormat Format() const { + return format; + } + + constexpr u32 BufferId() const { + return buffer_id; + } + + constexpr u32 ExternalFormat() const { + return external_format; + } + + constexpr u32 Handle() const { + return handle; + } + + constexpr u32 Offset() const { + return offset; + } + + constexpr bool NeedsReallocation(u32 width_, u32 height_, PixelFormat format_, + u32 usage_) const { + if (static_cast(width_) != width) { + return true; + } + + if (static_cast(height_) != height) { + return true; + } + + if (format_ != format) { + return true; + } + + if ((static_cast(usage) & usage_) != usage_) { + return true; + } + + return false; + } + +private: + u32 magic{}; + s32 width{}; + s32 height{}; + s32 stride{}; + PixelFormat format{}; + s32 usage{}; + INSERT_PADDING_WORDS(1); + u32 index{}; + INSERT_PADDING_WORDS(3); + u32 buffer_id{}; + INSERT_PADDING_WORDS(6); + u32 external_format{}; + INSERT_PADDING_WORDS(10); + u32 handle{}; + u32 offset{}; + INSERT_PADDING_WORDS(60); +}; +static_assert(sizeof(GraphicBuffer) == 0x16C, "GraphicBuffer has wrong size"); + +} // namespace android -- cgit v1.2.3 From d456b9d554da32e4353ba6e837e1cb8690782a9d Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 18:13:35 -0800 Subject: hle: nvflinger: Move PixelFormat to its own header. --- src/core/CMakeLists.txt | 1 + src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp | 10 ++++------ src/core/hle/service/nvdrv/devices/nvdisp_disp0.h | 5 +++-- src/core/hle/service/nvflinger/pixel_format.h | 21 +++++++++++++++++++++ src/core/hle/service/nvflinger/ui/graphic_buffer.h | 4 ++-- src/video_core/framebuffer_config.h | 10 +++------- src/video_core/renderer_opengl/renderer_opengl.cpp | 8 ++++---- src/video_core/renderer_opengl/renderer_opengl.h | 4 ++-- src/video_core/renderer_vulkan/vk_blit_screen.cpp | 10 +++++----- src/video_core/surface.cpp | 8 ++++---- src/video_core/surface.h | 2 +- 11 files changed, 50 insertions(+), 33 deletions(-) create mode 100644 src/core/hle/service/nvflinger/pixel_format.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 5e9b959a5..a7afc675d 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -539,6 +539,7 @@ add_library(core STATIC hle/service/nvflinger/buffer_queue.h hle/service/nvflinger/nvflinger.cpp hle/service/nvflinger/nvflinger.h + hle/service/nvflinger/pixel_format.h hle/service/nvflinger/status.h hle/service/nvflinger/ui/fence.h hle/service/nvflinger/ui/graphic_buffer.h diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 68f1e9060..9fad45fe1 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -38,18 +38,16 @@ NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, const std::vector& void nvdisp_disp0::OnOpen(DeviceFD fd) {} void nvdisp_disp0::OnClose(DeviceFD fd) {} -void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, - u32 stride, NVFlinger::BufferQueue::BufferTransformFlags transform, +void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width, + u32 height, u32 stride, android::BufferTransformFlags transform, const Common::Rectangle& crop_rect) { const VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle); LOG_TRACE(Service, "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}", addr, offset, width, height, stride, format); - const auto pixel_format = static_cast(format); - const auto transform_flags = static_cast(transform); - const Tegra::FramebufferConfig framebuffer{addr, offset, width, height, - stride, pixel_format, transform_flags, crop_rect}; + const Tegra::FramebufferConfig framebuffer{addr, offset, width, height, + stride, format, transform, crop_rect}; system.GetPerfStats().EndSystemFrame(); system.GPU().SwapBuffers(&framebuffer); diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index de01e1d5f..53c539ce4 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h @@ -10,6 +10,7 @@ #include "common/math_util.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" #include "core/hle/service/nvflinger/buffer_queue.h" +#include "core/hle/service/nvflinger/pixel_format.h" namespace Service::Nvidia::Devices { @@ -31,8 +32,8 @@ public: void OnClose(DeviceFD fd) 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, - NVFlinger::BufferQueue::BufferTransformFlags transform, + void flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width, u32 height, + u32 stride, android::BufferTransformFlags transform, const Common::Rectangle& crop_rect); private: diff --git a/src/core/hle/service/nvflinger/pixel_format.h b/src/core/hle/service/nvflinger/pixel_format.h new file mode 100644 index 000000000..966c84775 --- /dev/null +++ b/src/core/hle/service/nvflinger/pixel_format.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project + +#pragma once + +#include "common/common_types.h" + +namespace android { + +enum class PixelFormat : u32 { + NoFormat = 0, + Rgba8888 = 1, + Rgbx8888 = 2, + Rgb888 = 3, + Rgb565 = 4, + Bgra8888 = 5, + Rgba5551 = 6, + Rgba4444 = 7, +}; + +} // namespace android diff --git a/src/core/hle/service/nvflinger/ui/graphic_buffer.h b/src/core/hle/service/nvflinger/ui/graphic_buffer.h index c1e54d9ed..2e7f251ef 100644 --- a/src/core/hle/service/nvflinger/ui/graphic_buffer.h +++ b/src/core/hle/service/nvflinger/ui/graphic_buffer.h @@ -44,7 +44,7 @@ public: return buffer_id; } - constexpr u32 ExternalFormat() const { + constexpr PixelFormat ExternalFormat() const { return external_format; } @@ -89,7 +89,7 @@ private: INSERT_PADDING_WORDS(3); u32 buffer_id{}; INSERT_PADDING_WORDS(6); - u32 external_format{}; + PixelFormat external_format{}; INSERT_PADDING_WORDS(10); u32 handle{}; u32 offset{}; diff --git a/src/video_core/framebuffer_config.h b/src/video_core/framebuffer_config.h index b1d455e30..5921d830e 100644 --- a/src/video_core/framebuffer_config.h +++ b/src/video_core/framebuffer_config.h @@ -6,18 +6,14 @@ #include "common/common_types.h" #include "common/math_util.h" +#include "core/hle/service/nvflinger/pixel_format.h" namespace Tegra { + /** * Struct describing framebuffer configuration */ struct FramebufferConfig { - enum class PixelFormat : u32 { - A8B8G8R8_UNORM = 1, - RGB565_UNORM = 4, - B8G8R8A8_UNORM = 5, - }; - enum class TransformFlags : u32 { /// No transform flags are set Unset = 0x00, @@ -38,9 +34,9 @@ struct FramebufferConfig { u32 width{}; u32 height{}; u32 stride{}; - PixelFormat pixel_format{}; TransformFlags transform_flags{}; + android::PixelFormat pixel_format{}; Common::Rectangle crop_rect; }; diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 795c97831..279421962 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -323,12 +323,12 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, GLint internal_format; switch (framebuffer.pixel_format) { - case Tegra::FramebufferConfig::PixelFormat::A8B8G8R8_UNORM: + case android::PixelFormat::Rgba8888: internal_format = GL_RGBA8; texture.gl_format = GL_RGBA; texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; break; - case Tegra::FramebufferConfig::PixelFormat::RGB565_UNORM: + case android::PixelFormat::Rgb565: internal_format = GL_RGB565; texture.gl_format = GL_RGB; texture.gl_type = GL_UNSIGNED_SHORT_5_6_5; @@ -464,8 +464,8 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { const auto& texcoords = screen_info.display_texcoords; auto left = texcoords.left; auto right = texcoords.right; - if (framebuffer_transform_flags != Tegra::FramebufferConfig::TransformFlags::Unset) { - if (framebuffer_transform_flags == Tegra::FramebufferConfig::TransformFlags::FlipV) { + if (framebuffer_transform_flags != android::BufferTransformFlags::Unset) { + if (framebuffer_transform_flags == android::BufferTransformFlags::FlipV) { // Flip the framebuffer vertically left = texcoords.right; right = texcoords.left; diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 35706cf05..e6395b900 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -46,7 +46,7 @@ struct TextureInfo { GLsizei height; GLenum gl_format; GLenum gl_type; - Tegra::FramebufferConfig::PixelFormat pixel_format; + android::PixelFormat pixel_format; }; /// Structure used for storing information about the display target for the Switch screen @@ -135,7 +135,7 @@ private: std::vector gl_framebuffer_data; /// Used for transforming the framebuffer orientation - Tegra::FramebufferConfig::TransformFlags framebuffer_transform_flags{}; + android::BufferTransformFlags framebuffer_transform_flags{}; Common::Rectangle framebuffer_crop_rect; }; diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 0ec85682b..3da16c422 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp @@ -94,11 +94,11 @@ std::size_t GetSizeInBytes(const Tegra::FramebufferConfig& framebuffer) { VkFormat GetFormat(const Tegra::FramebufferConfig& framebuffer) { switch (framebuffer.pixel_format) { - case Tegra::FramebufferConfig::PixelFormat::A8B8G8R8_UNORM: + case android::PixelFormat::Rgba8888: return VK_FORMAT_A8B8G8R8_UNORM_PACK32; - case Tegra::FramebufferConfig::PixelFormat::RGB565_UNORM: + case android::PixelFormat::Rgb565: return VK_FORMAT_R5G6B5_UNORM_PACK16; - case Tegra::FramebufferConfig::PixelFormat::B8G8R8A8_UNORM: + case android::PixelFormat::Bgra8888: return VK_FORMAT_B8G8R8A8_UNORM; default: UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}", @@ -1390,9 +1390,9 @@ void VKBlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfi auto right = texcoords.right; switch (framebuffer_transform_flags) { - case Tegra::FramebufferConfig::TransformFlags::Unset: + case android::BufferTransformFlags::Unset: break; - case Tegra::FramebufferConfig::TransformFlags::FlipV: + case android::BufferTransformFlags::FlipV: // Flip the framebuffer vertically left = texcoords.right; right = texcoords.left; diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp index a36015c8c..f7d29534e 100644 --- a/src/video_core/surface.cpp +++ b/src/video_core/surface.cpp @@ -190,13 +190,13 @@ PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) } } -PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) { +PixelFormat PixelFormatFromGPUPixelFormat(android::PixelFormat format) { switch (format) { - case Tegra::FramebufferConfig::PixelFormat::A8B8G8R8_UNORM: + case android::PixelFormat::Rgba8888: return PixelFormat::A8B8G8R8_UNORM; - case Tegra::FramebufferConfig::PixelFormat::RGB565_UNORM: + case android::PixelFormat::Rgb565: return PixelFormat::R5G6B5_UNORM; - case Tegra::FramebufferConfig::PixelFormat::B8G8R8A8_UNORM: + case android::PixelFormat::Bgra8888: return PixelFormat::B8G8R8A8_UNORM; default: UNIMPLEMENTED_MSG("Unimplemented format={}", format); diff --git a/src/video_core/surface.h b/src/video_core/surface.h index 33e8d24ab..1061b2fa7 100644 --- a/src/video_core/surface.h +++ b/src/video_core/surface.h @@ -460,7 +460,7 @@ PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format); PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format); -PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format); +PixelFormat PixelFormatFromGPUPixelFormat(android::PixelFormat format); SurfaceType GetFormatType(PixelFormat pixel_format); -- cgit v1.2.3 From 402273d91b4051f5e7220140935c0c15ae968f94 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 18:14:35 -0800 Subject: hle: nvdrv: Rename Fence to NvFence to avoid naming conflicts. --- src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 7 ++++--- src/core/hle/service/nvdrv/devices/nvhost_gpu.h | 10 +++++----- src/core/hle/service/nvdrv/nvdata.h | 10 ++-------- src/core/hle/service/nvdrv/nvdrv.h | 3 ++- 4 files changed, 13 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 0a043e386..dde5b1507 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -187,7 +187,7 @@ NvResult nvhost_gpu::AllocateObjectContext(const std::vector& input, std::ve return NvResult::Success; } -static std::vector BuildWaitCommandList(Fence fence) { +static std::vector BuildWaitCommandList(NvFence fence) { return { Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceValue, 1, Tegra::SubmissionMode::Increasing), @@ -198,7 +198,8 @@ static std::vector BuildWaitCommandList(Fence fence) { }; } -static std::vector BuildIncrementCommandList(Fence fence, u32 add_increment) { +static std::vector BuildIncrementCommandList(NvFence fence, + u32 add_increment) { std::vector result{ Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceValue, 1, Tegra::SubmissionMode::Increasing), @@ -213,7 +214,7 @@ static std::vector BuildIncrementCommandList(Fence fence, return result; } -static std::vector BuildIncrementWithWfiCommandList(Fence fence, +static std::vector BuildIncrementWithWfiCommandList(NvFence fence, u32 add_increment) { std::vector result{ Tegra::BuildCommandHeader(Tegra::BufferMethods::WaitForInterrupt, 1, diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index 3e4f3b6a7..b2e943e45 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -109,7 +109,7 @@ private: static_assert(sizeof(IoctlGetErrorNotification) == 16, "IoctlGetErrorNotification is incorrect size"); - static_assert(sizeof(Fence) == 8, "Fence is incorrect size"); + static_assert(sizeof(NvFence) == 8, "Fence is incorrect size"); struct IoctlAllocGpfifoEx { u32_le num_entries{}; @@ -127,7 +127,7 @@ private: u32_le num_entries{}; // in u32_le flags{}; // in u32_le unk0{}; // in (1 works) - Fence fence_out{}; // out + NvFence fence_out{}; // out u32_le unk1{}; // in u32_le unk2{}; // in u32_le unk3{}; // in @@ -153,13 +153,13 @@ private: BitField<4, 1, u32_le> suppress_wfi; // suppress wait for interrupt BitField<8, 1, u32_le> increment; // increment the returned fence } flags; - Fence fence_out{}; // returned new fence object for others to wait on + NvFence fence_out{}; // returned new fence object for others to wait on u32 AddIncrementValue() const { return flags.add_increment.Value() << 1; } }; - static_assert(sizeof(IoctlSubmitGpfifo) == 16 + sizeof(Fence), + static_assert(sizeof(IoctlSubmitGpfifo) == 16 + sizeof(NvFence), "IoctlSubmitGpfifo is incorrect size"); struct IoctlGetWaitbase { @@ -194,7 +194,7 @@ private: std::shared_ptr nvmap_dev; SyncpointManager& syncpoint_manager; - Fence channel_fence; + NvFence channel_fence; }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h index 5ab221fc1..33cbd8904 100644 --- a/src/core/hle/service/nvdrv/nvdata.h +++ b/src/core/hle/service/nvdrv/nvdata.h @@ -16,17 +16,11 @@ using DeviceFD = s32; constexpr DeviceFD INVALID_NVDRV_FD = -1; -struct Fence { +struct NvFence { s32 id; u32 value; }; - -static_assert(sizeof(Fence) == 8, "Fence has wrong size"); - -struct MultiFence { - u32 num_fences; - std::array fences; -}; +static_assert(sizeof(NvFence) == 8, "Fence has wrong size"); enum class NvResult : u32 { Success = 0x0, diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index a5af5b785..11cf6c0d1 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -12,6 +12,7 @@ #include "core/hle/service/kernel_helpers.h" #include "core/hle/service/nvdrv/nvdata.h" #include "core/hle/service/nvdrv/syncpoint_manager.h" +#include "core/hle/service/nvflinger/ui/fence.h" #include "core/hle/service/service.h" namespace Core { @@ -37,7 +38,7 @@ class nvdevice; /// Represents an Nvidia event struct NvEvent { Kernel::KEvent* event{}; - Fence fence{}; + NvFence fence{}; }; struct EventInterface { -- cgit v1.2.3 From 05d80fba38eada5ec671980a5cd7276bcf14482a Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 18:31:05 -0800 Subject: hle: nvflinger: Move BufferTransformFlags to its own header. --- src/core/CMakeLists.txt | 1 + src/core/hle/service/nvdrv/devices/nvdisp_disp0.h | 2 +- .../hle/service/nvflinger/buffer_transform_flags.h | 25 ++++++++++++++++++++++ src/video_core/framebuffer_config.h | 19 ++-------------- 4 files changed, 29 insertions(+), 18 deletions(-) create mode 100644 src/core/hle/service/nvflinger/buffer_transform_flags.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index a7afc675d..c8c3e7f7f 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -537,6 +537,7 @@ add_library(core STATIC hle/service/nvdrv/syncpoint_manager.h hle/service/nvflinger/buffer_queue.cpp hle/service/nvflinger/buffer_queue.h + hle/service/nvflinger/buffer_transform_flags.h hle/service/nvflinger/nvflinger.cpp hle/service/nvflinger/nvflinger.h hle/service/nvflinger/pixel_format.h diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index 53c539ce4..30b5da429 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h @@ -9,7 +9,7 @@ #include "common/common_types.h" #include "common/math_util.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" -#include "core/hle/service/nvflinger/buffer_queue.h" +#include "core/hle/service/nvflinger/buffer_transform_flags.h" #include "core/hle/service/nvflinger/pixel_format.h" namespace Service::Nvidia::Devices { diff --git a/src/core/hle/service/nvflinger/buffer_transform_flags.h b/src/core/hle/service/nvflinger/buffer_transform_flags.h new file mode 100644 index 000000000..398c6370b --- /dev/null +++ b/src/core/hle/service/nvflinger/buffer_transform_flags.h @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project + +#pragma once + +#include "common/common_types.h" + +namespace android { + +enum class BufferTransformFlags : u32 { + /// No transform flags are set + Unset = 0x00, + /// Flip source image horizontally (around the vertical axis) + FlipH = 0x01, + /// Flip source image vertically (around the horizontal axis) + FlipV = 0x02, + /// Rotate source image 90 degrees clockwise + Rotate90 = 0x04, + /// Rotate source image 180 degrees + Rotate180 = 0x03, + /// Rotate source image 270 degrees clockwise + Rotate270 = 0x07, +}; + +} // namespace android diff --git a/src/video_core/framebuffer_config.h b/src/video_core/framebuffer_config.h index 5921d830e..1e75d51ab 100644 --- a/src/video_core/framebuffer_config.h +++ b/src/video_core/framebuffer_config.h @@ -6,6 +6,7 @@ #include "common/common_types.h" #include "common/math_util.h" +#include "core/hle/service/nvflinger/buffer_transform_flags.h" #include "core/hle/service/nvflinger/pixel_format.h" namespace Tegra { @@ -14,29 +15,13 @@ namespace Tegra { * Struct describing framebuffer configuration */ struct FramebufferConfig { - enum class TransformFlags : u32 { - /// No transform flags are set - Unset = 0x00, - /// Flip source image horizontally (around the vertical axis) - FlipH = 0x01, - /// Flip source image vertically (around the horizontal axis) - FlipV = 0x02, - /// Rotate source image 90 degrees clockwise - Rotate90 = 0x04, - /// Rotate source image 180 degrees - Rotate180 = 0x03, - /// Rotate source image 270 degrees clockwise - Rotate270 = 0x07, - }; - VAddr address{}; u32 offset{}; u32 width{}; u32 height{}; u32 stride{}; - - TransformFlags transform_flags{}; android::PixelFormat pixel_format{}; + android::BufferTransformFlags transform_flags{}; Common::Rectangle crop_rect; }; -- cgit v1.2.3 From 05ff9e8d4e31e643131bf827c491052cdba003a0 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 18:32:06 -0800 Subject: hle: nvflinger: Add android Status flags to its own header. --- src/core/hle/service/nvflinger/status.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/core/hle/service/nvflinger/status.h (limited to 'src') diff --git a/src/core/hle/service/nvflinger/status.h b/src/core/hle/service/nvflinger/status.h new file mode 100644 index 000000000..9bc1205df --- /dev/null +++ b/src/core/hle/service/nvflinger/status.h @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project + +#pragma once + +#include "common/common_funcs.h" +#include "common/common_types.h" + +namespace android { + +enum class Status : s32 { + None = 0, + NoError = 0, + StaleBufferSlot = 1, + NoBufferAvailable = 2, + PresentLater = 3, + WouldBlock = -11, + NoMemory = -12, + Busy = -16, + NoInit = -19, + BadValue = -22, + InvalidOperation = -37, + BufferNeedsReallocation = 1, + ReleaseAllBuffers = 2, +}; +DECLARE_ENUM_FLAG_OPERATORS(Status); + +} // namespace android -- cgit v1.2.3 From fd24d5a0a229fbcf1d96650a170ad64d9bb00651 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 18:32:50 -0800 Subject: hle: nvflinger: Add android window enumerations to its own header. --- src/core/CMakeLists.txt | 1 + src/core/hle/service/nvflinger/window.h | 53 +++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/core/hle/service/nvflinger/window.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c8c3e7f7f..bf1a9490c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -545,6 +545,7 @@ add_library(core STATIC hle/service/nvflinger/ui/fence.h hle/service/nvflinger/ui/graphic_buffer.h hle/service/nvflinger/ui/rect.h + hle/service/nvflinger/window.h hle/service/olsc/olsc.cpp hle/service/olsc/olsc.h hle/service/pcie/pcie.cpp diff --git a/src/core/hle/service/nvflinger/window.h b/src/core/hle/service/nvflinger/window.h new file mode 100644 index 000000000..17f36da20 --- /dev/null +++ b/src/core/hle/service/nvflinger/window.h @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project + +#pragma once + +#include "common/common_funcs.h" +#include "common/common_types.h" + +namespace android { + +/// Attributes queryable with Query +enum class NativeWindow : s32 { + Width = 0, + Height = 1, + Format = 2, + MinUndequeedBuffers = 3, + QueuesToWindowComposer = 4, + ConcreteType = 5, + DefaultWidth = 6, + DefaultHeight = 7, + TransformHint = 8, + ConsumerRunningBehind = 9, + ConsumerUsageBits = 10, + StickyTransform = 11, + DefaultDataSpace = 12, + BufferAge = 13, +}; + +/// Parameter for Connect/Disconnect +enum class NativeWindowApi : s32 { + NoConnectedApi = 0, + Egl = 1, + Cpu = 2, + Media = 3, + Camera = 4, +}; + +/// Scaling mode parameter for QueueBuffer +enum class NativeWindowScalingMode : s32 { + Freeze = 0, + ScaleToWindow = 1, + ScaleCrop = 2, + NoScaleCrop = 3, +}; + +/// Transform parameter for QueueBuffer +enum class NativeWindowTransform : u32 { + None = 0x0, + InverseDisplay = 0x08, +}; +DECLARE_ENUM_FLAG_OPERATORS(NativeWindowTransform); + +} // namespace android -- cgit v1.2.3 From 81e143a3d25c537f294c9e76009320252fced66b Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 18:33:38 -0800 Subject: hle: nvflinger: Add ProducerListener interface. --- src/core/CMakeLists.txt | 1 + src/core/hle/service/nvflinger/producer_listener.h | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 src/core/hle/service/nvflinger/producer_listener.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index bf1a9490c..3ddda2528 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -541,6 +541,7 @@ add_library(core STATIC hle/service/nvflinger/nvflinger.cpp hle/service/nvflinger/nvflinger.h hle/service/nvflinger/pixel_format.h + hle/service/nvflinger/producer_listener.h hle/service/nvflinger/status.h hle/service/nvflinger/ui/fence.h hle/service/nvflinger/ui/graphic_buffer.h diff --git a/src/core/hle/service/nvflinger/producer_listener.h b/src/core/hle/service/nvflinger/producer_listener.h new file mode 100644 index 000000000..8fe29d73e --- /dev/null +++ b/src/core/hle/service/nvflinger/producer_listener.h @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project +// Copyright 2014 The Android Open Source Project +// Parts of this implementation were base on: +// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/IProducerListener.h + +#pragma once + +namespace android { + +class IProducerListener { +public: + virtual void OnBufferReleased() = 0; +}; + +} // namespace android -- cgit v1.2.3 From b9cbc708e84d9b96dca6a93bbd70de85e6320f40 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 18:34:44 -0800 Subject: hle: nvflinger: Add IConsumerListener interface. --- src/core/CMakeLists.txt | 1 + src/core/hle/service/nvflinger/consumer_listener.h | 26 ++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 src/core/hle/service/nvflinger/consumer_listener.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 3ddda2528..eebd610c3 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -538,6 +538,7 @@ add_library(core STATIC hle/service/nvflinger/buffer_queue.cpp hle/service/nvflinger/buffer_queue.h hle/service/nvflinger/buffer_transform_flags.h + hle/service/nvflinger/consumer_listener.h hle/service/nvflinger/nvflinger.cpp hle/service/nvflinger/nvflinger.h hle/service/nvflinger/pixel_format.h diff --git a/src/core/hle/service/nvflinger/consumer_listener.h b/src/core/hle/service/nvflinger/consumer_listener.h new file mode 100644 index 000000000..0aa4ad17b --- /dev/null +++ b/src/core/hle/service/nvflinger/consumer_listener.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project +// Copyright 2014 The Android Open Source Project +// Parts of this implementation were base on: +// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/IConsumerListener.h + +#pragma once + +namespace android { + +class BufferItem; + +/// ConsumerListener is the interface through which the BufferQueue notifies the consumer of events +/// that the consumer may wish to react to. +class IConsumerListener { +public: + IConsumerListener() = default; + virtual ~IConsumerListener() = default; + + virtual void OnFrameAvailable(const BufferItem& item) = 0; + virtual void OnFrameReplaced(const BufferItem& item) = 0; + virtual void OnBuffersReleased() = 0; + virtual void OnSidebandStreamChanged() = 0; +}; + +}; // namespace android -- cgit v1.2.3 From fe9945ad6cc44ea234743bf085617d535342fab1 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 18:35:28 -0800 Subject: hle: nvflinger: Add IBinder interface. --- src/core/CMakeLists.txt | 1 + src/core/hle/service/nvflinger/binder.h | 42 +++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 src/core/hle/service/nvflinger/binder.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index eebd610c3..b8fdcbd1f 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -537,6 +537,7 @@ add_library(core STATIC hle/service/nvdrv/syncpoint_manager.h hle/service/nvflinger/buffer_queue.cpp hle/service/nvflinger/buffer_queue.h + hle/service/nvflinger/binder.h hle/service/nvflinger/buffer_transform_flags.h hle/service/nvflinger/consumer_listener.h hle/service/nvflinger/nvflinger.cpp diff --git a/src/core/hle/service/nvflinger/binder.h b/src/core/hle/service/nvflinger/binder.h new file mode 100644 index 000000000..2d9a23573 --- /dev/null +++ b/src/core/hle/service/nvflinger/binder.h @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project +// Copyright 2014 The Android Open Source Project +// Parts of this implementation were base on: +// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/binder/IBinder.h + +#pragma once + +#include "common/common_types.h" + +namespace Kernel { +class HLERequestContext; +class KReadableEvent; +} // namespace Kernel + +namespace android { + +enum class TransactionId { + RequestBuffer = 1, + SetBufferCount = 2, + DequeueBuffer = 3, + DetachBuffer = 4, + DetachNextBuffer = 5, + AttachBuffer = 6, + QueueBuffer = 7, + CancelBuffer = 8, + Query = 9, + Connect = 10, + Disconnect = 11, + AllocateBuffers = 13, + SetPreallocatedBuffer = 14, + GetBufferHistory = 17, +}; + +class IBinder { +public: + virtual void Transact(Kernel::HLERequestContext& ctx, android::TransactionId code, + u32 flags) = 0; + virtual Kernel::KReadableEvent& GetNativeHandle() = 0; +}; + +} // namespace android -- cgit v1.2.3 From a454670de5c02522af68b66cb4953b4ae4ac13f2 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 18:36:03 -0800 Subject: hle: nvflinger: Add android buffer queue definitions to its own header. --- src/core/CMakeLists.txt | 1 + src/core/hle/service/nvflinger/buffer_queue_defs.h | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/core/hle/service/nvflinger/buffer_queue_defs.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index b8fdcbd1f..d9b94b480 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -538,6 +538,7 @@ add_library(core STATIC hle/service/nvflinger/buffer_queue.cpp hle/service/nvflinger/buffer_queue.h hle/service/nvflinger/binder.h + hle/service/nvflinger/buffer_queue_defs.h hle/service/nvflinger/buffer_transform_flags.h hle/service/nvflinger/consumer_listener.h hle/service/nvflinger/nvflinger.cpp diff --git a/src/core/hle/service/nvflinger/buffer_queue_defs.h b/src/core/hle/service/nvflinger/buffer_queue_defs.h new file mode 100644 index 000000000..cea09e044 --- /dev/null +++ b/src/core/hle/service/nvflinger/buffer_queue_defs.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project +// Copyright 2014 The Android Open Source Project +// Parts of this implementation were base on: +// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferQueueDefs.h + +#pragma once + +#include + +#include "common/common_types.h" +#include "core/hle/service/nvflinger/buffer_slot.h" + +namespace android::BufferQueueDefs { + +// BufferQueue will keep track of at most this value of buffers. +constexpr s32 NUM_BUFFER_SLOTS = 64; + +using SlotsType = std::array; + +} // namespace android::BufferQueueDefs -- cgit v1.2.3 From d13e18a8edfb6f26026acb72db426f651ab80ef2 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 18:36:52 -0800 Subject: hle: nvflinger: Move implementation for Parcel to its own header. --- src/core/CMakeLists.txt | 1 + src/core/hle/service/nvflinger/parcel.h | 171 ++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 src/core/hle/service/nvflinger/parcel.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index d9b94b480..367d44cf3 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -543,6 +543,7 @@ add_library(core STATIC hle/service/nvflinger/consumer_listener.h hle/service/nvflinger/nvflinger.cpp hle/service/nvflinger/nvflinger.h + hle/service/nvflinger/parcel.h hle/service/nvflinger/pixel_format.h hle/service/nvflinger/producer_listener.h hle/service/nvflinger/status.h diff --git a/src/core/hle/service/nvflinger/parcel.h b/src/core/hle/service/nvflinger/parcel.h new file mode 100644 index 000000000..710964f5d --- /dev/null +++ b/src/core/hle/service/nvflinger/parcel.h @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project + +#pragma once + +#include +#include + +#include "common/alignment.h" +#include "common/assert.h" +#include "common/common_types.h" + +namespace android { + +class Parcel final { +public: + static constexpr std::size_t DefaultBufferSize = 0x40; + + Parcel() : buffer(DefaultBufferSize) {} + + template + explicit Parcel(const T& out_data) : buffer(DefaultBufferSize) { + Write(out_data); + } + + explicit Parcel(std::vector in_data) : buffer(std::move(in_data)) { + DeserializeHeader(); + [[maybe_unused]] const std::u16string token = ReadInterfaceToken(); + } + + template + void Read(T& val) { + static_assert(std::is_trivially_copyable_v, "T must be trivially copyable."); + ASSERT(read_index + sizeof(T) <= buffer.size()); + + std::memcpy(&val, buffer.data() + read_index, sizeof(T)); + read_index += sizeof(T); + read_index = Common::AlignUp(read_index, 4); + } + + template + T Read() { + T val; + Read(val); + return val; + } + + template + void ReadFlattened(T& val) { + const auto flattened_size = Read(); + ASSERT(sizeof(T) == flattened_size); + Read(val); + } + + template + T ReadFlattened() { + T val; + ReadFlattened(val); + return val; + } + + template + T ReadUnaligned() { + static_assert(std::is_trivially_copyable_v, "T must be trivially copyable."); + ASSERT(read_index + sizeof(T) <= buffer.size()); + + T val; + std::memcpy(&val, buffer.data() + read_index, sizeof(T)); + read_index += sizeof(T); + return val; + } + + template + const std::shared_ptr ReadObject() { + static_assert(std::is_trivially_copyable_v, "T must be trivially copyable."); + + const auto is_valid{Read()}; + + if (is_valid) { + auto result = std::make_shared(); + ReadFlattened(*result); + return result; + } + + return {}; + } + + std::u16string ReadInterfaceToken() { + [[maybe_unused]] const u32 unknown = Read(); + const u32 length = Read(); + + std::u16string token{}; + + for (u32 ch = 0; ch < length + 1; ++ch) { + token.push_back(ReadUnaligned()); + } + + read_index = Common::AlignUp(read_index, 4); + + return token; + } + + template + void Write(const T& val) { + static_assert(std::is_trivially_copyable_v, "T must be trivially copyable."); + + if (buffer.size() < write_index + sizeof(T)) { + buffer.resize(buffer.size() + sizeof(T) + DefaultBufferSize); + } + + std::memcpy(buffer.data() + write_index, &val, sizeof(T)); + write_index += sizeof(T); + write_index = Common::AlignUp(write_index, 4); + } + + template + void WriteObject(const T* ptr) { + static_assert(std::is_trivially_copyable_v, "T must be trivially copyable."); + + if (!ptr) { + Write(0); + return; + } + + Write(1); + Write(sizeof(T)); + Write(*ptr); + } + + template + void WriteObject(const std::shared_ptr ptr) { + WriteObject(ptr.get()); + } + + void DeserializeHeader() { + ASSERT(buffer.size() > sizeof(Header)); + + Header header{}; + std::memcpy(&header, buffer.data(), sizeof(Header)); + + read_index = header.data_offset; + } + + std::vector Serialize() const { + ASSERT(read_index == 0); + + Header header{}; + header.data_size = static_cast(write_index - sizeof(Header)); + header.data_offset = sizeof(Header); + header.objects_size = 4; + header.objects_offset = static_cast(sizeof(Header) + header.data_size); + std::memcpy(buffer.data(), &header, sizeof(Header)); + + return buffer; + } + +private: + struct Header { + u32 data_size; + u32 data_offset; + u32 objects_size; + u32 objects_offset; + }; + static_assert(sizeof(Header) == 16, "ParcelHeader has wrong size"); + + mutable std::vector buffer; + std::size_t read_index = 0; + std::size_t write_index = sizeof(Header); +}; + +} // namespace android -- cgit v1.2.3 From c723db39c7a508ca6445c328ab85f506bce4927a Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 18:38:36 -0800 Subject: hle: nvflinger: Add implementation for BufferItem class. --- src/core/CMakeLists.txt | 1 + src/core/hle/service/nvflinger/buffer_item.h | 46 ++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 src/core/hle/service/nvflinger/buffer_item.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 367d44cf3..a1139068d 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -538,6 +538,7 @@ add_library(core STATIC hle/service/nvflinger/buffer_queue.cpp hle/service/nvflinger/buffer_queue.h hle/service/nvflinger/binder.h + hle/service/nvflinger/buffer_item.h hle/service/nvflinger/buffer_queue_defs.h hle/service/nvflinger/buffer_transform_flags.h hle/service/nvflinger/consumer_listener.h diff --git a/src/core/hle/service/nvflinger/buffer_item.h b/src/core/hle/service/nvflinger/buffer_item.h new file mode 100644 index 000000000..9dc6f3fee --- /dev/null +++ b/src/core/hle/service/nvflinger/buffer_item.h @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project +// Copyright 2014 The Android Open Source Project +// Parts of this implementation were base on: +// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferItem.h + +#pragma once + +#include + +#include "common/common_types.h" +#include "core/hle/service/nvflinger/ui/fence.h" +#include "core/hle/service/nvflinger/ui/rect.h" +#include "core/hle/service/nvflinger/window.h" + +namespace android { + +class GraphicBuffer; + +class BufferItem final { +public: + constexpr BufferItem() = default; + + std::shared_ptr graphic_buffer; + Fence fence; + Rect crop; + NativeWindowTransform transform{}; + u32 scaling_mode{}; + s64 timestamp{}; + bool is_auto_timestamp{}; + u64 frame_number{}; + + // The default value for buf, used to indicate this doesn't correspond to a slot. + static constexpr s32 INVALID_BUFFER_SLOT = -1; + union { + s32 slot{INVALID_BUFFER_SLOT}; + s32 buf; + }; + + bool is_droppable{}; + bool acquire_called{}; + bool transform_to_display_inverse{}; + s32 swap_interval{}; +}; + +} // namespace android -- cgit v1.2.3 From d25cb12bffe93bcd2c37cb02d96c0d4c7d006002 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 18:39:29 -0800 Subject: hle: nvflinger: Add implementation for BufferSlot class. --- src/core/CMakeLists.txt | 1 + src/core/hle/service/nvflinger/buffer_slot.h | 39 ++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/core/hle/service/nvflinger/buffer_slot.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index a1139068d..fd2777b11 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -540,6 +540,7 @@ add_library(core STATIC hle/service/nvflinger/binder.h hle/service/nvflinger/buffer_item.h hle/service/nvflinger/buffer_queue_defs.h + hle/service/nvflinger/buffer_slot.h hle/service/nvflinger/buffer_transform_flags.h hle/service/nvflinger/consumer_listener.h hle/service/nvflinger/nvflinger.cpp diff --git a/src/core/hle/service/nvflinger/buffer_slot.h b/src/core/hle/service/nvflinger/buffer_slot.h new file mode 100644 index 000000000..24b806d33 --- /dev/null +++ b/src/core/hle/service/nvflinger/buffer_slot.h @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project +// Copyright 2014 The Android Open Source Project +// Parts of this implementation were base on: +// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferSlot.h + +#pragma once + +#include + +#include "common/common_types.h" +#include "core/hle/service/nvflinger/ui/fence.h" + +namespace android { + +class GraphicBuffer; + +enum class BufferState : u32 { + Free = 0, + Dequeued = 1, + Queued = 2, + Acquired = 3, +}; + +struct BufferSlot final { + constexpr BufferSlot() = default; + + std::shared_ptr graphic_buffer; + BufferState buffer_state{BufferState::Free}; + bool request_buffer_called{}; + u64 frame_number{}; + Fence fence; + bool acquire_called{}; + bool needs_cleanup_on_release{}; + bool attached_by_consumer{}; + bool is_preallocated{}; +}; + +} // namespace android -- cgit v1.2.3 From 79e8cdf595e1fe86f985b88c655aea277ba32692 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 18:43:30 -0800 Subject: hle: nvflinger: Add implementation for ConsumerBase class. --- src/core/CMakeLists.txt | 2 + src/core/hle/service/nvflinger/consumer_base.cpp | 129 +++++++++++++++++++++++ src/core/hle/service/nvflinger/consumer_base.h | 59 +++++++++++ 3 files changed, 190 insertions(+) create mode 100644 src/core/hle/service/nvflinger/consumer_base.cpp create mode 100644 src/core/hle/service/nvflinger/consumer_base.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index fd2777b11..44d6b3cf7 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -542,6 +542,8 @@ add_library(core STATIC hle/service/nvflinger/buffer_queue_defs.h hle/service/nvflinger/buffer_slot.h hle/service/nvflinger/buffer_transform_flags.h + hle/service/nvflinger/consumer_base.cpp + hle/service/nvflinger/consumer_base.h hle/service/nvflinger/consumer_listener.h hle/service/nvflinger/nvflinger.cpp hle/service/nvflinger/nvflinger.h diff --git a/src/core/hle/service/nvflinger/consumer_base.cpp b/src/core/hle/service/nvflinger/consumer_base.cpp new file mode 100644 index 000000000..127e5930b --- /dev/null +++ b/src/core/hle/service/nvflinger/consumer_base.cpp @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project +// Copyright 2010 The Android Open Source Project +// Parts of this implementation were base on: +// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/ConsumerBase.cpp + +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/hle/service/nvflinger/buffer_item.h" +#include "core/hle/service/nvflinger/buffer_queue_consumer.h" +#include "core/hle/service/nvflinger/buffer_queue_core.h" +#include "core/hle/service/nvflinger/consumer_base.h" +#include "core/hle/service/nvflinger/ui/graphic_buffer.h" + +namespace android { + +ConsumerBase::ConsumerBase(std::unique_ptr consumer_) + : consumer{std::move(consumer_)} {} + +ConsumerBase::~ConsumerBase() { + std::unique_lock lock(mutex); + + ASSERT_MSG(is_abandoned, "consumer is not abandoned!"); +} + +void ConsumerBase::Connect(bool controlled_by_app) { + consumer->Connect(shared_from_this(), controlled_by_app); +} + +void ConsumerBase::FreeBufferLocked(s32 slot_index) { + LOG_DEBUG(Service_NVFlinger, "slot_index={}", slot_index); + + slots[slot_index].graphic_buffer = nullptr; + slots[slot_index].fence = Fence::NoFence(); + slots[slot_index].frame_number = 0; +} + +void ConsumerBase::OnFrameAvailable(const BufferItem& item) { + std::unique_lock lock(mutex); + LOG_DEBUG(Service_NVFlinger, "called"); +} + +void ConsumerBase::OnFrameReplaced(const BufferItem& item) { + std::unique_lock lock(mutex); + LOG_DEBUG(Service_NVFlinger, "called"); +} + +void ConsumerBase::OnBuffersReleased() { + std::unique_lock lock(mutex); + LOG_DEBUG(Service_NVFlinger, "called"); +} + +void ConsumerBase::OnSidebandStreamChanged() {} + +Status ConsumerBase::AcquireBufferLocked(BufferItem* item, u64 present_when_ns, + u64 max_frame_number) { + if (is_abandoned) { + LOG_ERROR(Service_NVFlinger, "consumer is abandoned!"); + return Status::NoInit; + } + + Status err = consumer->AcquireBuffer(item, present_when_ns, max_frame_number); + if (err != Status::NoError) { + return err; + } + + if (item->graphic_buffer != nullptr) { + if (slots[item->slot].graphic_buffer != nullptr) { + FreeBufferLocked(item->slot); + } + slots[item->slot].graphic_buffer = item->graphic_buffer; + } + + slots[item->slot].frame_number = item->frame_number; + slots[item->slot].fence = item->fence; + + LOG_DEBUG(Service_NVFlinger, "slot={}", item->slot); + + return Status::NoError; +} + +Status ConsumerBase::AddReleaseFenceLocked(s32 slot, + const std::shared_ptr graphic_buffer, + const Fence& fence) { + LOG_DEBUG(Service_NVFlinger, "slot={}", slot); + + // If consumer no longer tracks this graphic_buffer, we can safely + // drop this fence, as it will never be received by the producer. + + if (!StillTracking(slot, graphic_buffer)) { + return Status::NoError; + } + + slots[slot].fence = fence; + + return Status::NoError; +} + +Status ConsumerBase::ReleaseBufferLocked(s32 slot, + const std::shared_ptr graphic_buffer) { + // If consumer no longer tracks this graphic_buffer (we received a new + // buffer on the same slot), the buffer producer is definitely no longer + // tracking it. + + if (!StillTracking(slot, graphic_buffer)) { + return Status::NoError; + } + + LOG_DEBUG(Service_NVFlinger, "slot={}", slot); + Status err = consumer->ReleaseBuffer(slot, slots[slot].frame_number, slots[slot].fence); + if (err == Status::StaleBufferSlot) { + FreeBufferLocked(slot); + } + + slots[slot].fence = Fence::NoFence(); + + return err; +} + +bool ConsumerBase::StillTracking(s32 slot, const std::shared_ptr graphic_buffer) { + if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { + return false; + } + + return (slots[slot].graphic_buffer != nullptr && + slots[slot].graphic_buffer->Handle() == graphic_buffer->Handle()); +} + +} // namespace android diff --git a/src/core/hle/service/nvflinger/consumer_base.h b/src/core/hle/service/nvflinger/consumer_base.h new file mode 100644 index 000000000..574ea9781 --- /dev/null +++ b/src/core/hle/service/nvflinger/consumer_base.h @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project +// Copyright 2010 The Android Open Source Project +// Parts of this implementation were base on: +// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/ConsumerBase.h + +#pragma once + +#include +#include +#include + +#include "common/common_types.h" +#include "core/hle/service/nvflinger/buffer_queue_defs.h" +#include "core/hle/service/nvflinger/consumer_listener.h" +#include "core/hle/service/nvflinger/status.h" + +namespace android { + +class BufferItem; +class BufferQueueConsumer; + +class ConsumerBase : public IConsumerListener, public std::enable_shared_from_this { +public: + void Connect(bool controlled_by_app); + +protected: + ConsumerBase(std::unique_ptr consumer_); + virtual ~ConsumerBase(); + + virtual void OnFrameAvailable(const BufferItem& item) override; + virtual void OnFrameReplaced(const BufferItem& item) override; + virtual void OnBuffersReleased() override; + virtual void OnSidebandStreamChanged() override; + + void FreeBufferLocked(s32 slot_index); + Status AcquireBufferLocked(BufferItem* item, u64 present_when_ns, u64 max_frame_number = 0); + Status ReleaseBufferLocked(s32 slot, const std::shared_ptr graphic_buffer); + bool StillTracking(s32 slot, const std::shared_ptr graphic_buffer); + Status AddReleaseFenceLocked(s32 slot, const std::shared_ptr graphic_buffer, + const Fence& fence); + + struct Slot final { + std::shared_ptr graphic_buffer; + Fence fence; + u64 frame_number{}; + }; + +protected: + std::array slots; + + bool is_abandoned{}; + + std::unique_ptr consumer; + + mutable std::mutex mutex; +}; + +} // namespace android -- cgit v1.2.3 From 00571590663f73b7bfb659f78d6cc59473113a5a Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 18:46:56 -0800 Subject: hle: nvflinger: Add implementation for BufferItemConsumer class. --- src/core/CMakeLists.txt | 2 + .../hle/service/nvflinger/buffer_item_consumer.cpp | 59 ++++++++++++++++++++++ .../hle/service/nvflinger/buffer_item_consumer.h | 26 ++++++++++ 3 files changed, 87 insertions(+) create mode 100644 src/core/hle/service/nvflinger/buffer_item_consumer.cpp create mode 100644 src/core/hle/service/nvflinger/buffer_item_consumer.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 44d6b3cf7..78b1e68ea 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -539,6 +539,8 @@ add_library(core STATIC hle/service/nvflinger/buffer_queue.h hle/service/nvflinger/binder.h hle/service/nvflinger/buffer_item.h + hle/service/nvflinger/buffer_item_consumer.cpp + hle/service/nvflinger/buffer_item_consumer.h hle/service/nvflinger/buffer_queue_defs.h hle/service/nvflinger/buffer_slot.h hle/service/nvflinger/buffer_transform_flags.h diff --git a/src/core/hle/service/nvflinger/buffer_item_consumer.cpp b/src/core/hle/service/nvflinger/buffer_item_consumer.cpp new file mode 100644 index 000000000..424b19d32 --- /dev/null +++ b/src/core/hle/service/nvflinger/buffer_item_consumer.cpp @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project +// Copyright 2012 The Android Open Source Project +// Parts of this implementation were base on: +// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferItemConsumer.cpp + +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/hle/service/nvflinger/buffer_item.h" +#include "core/hle/service/nvflinger/buffer_item_consumer.h" +#include "core/hle/service/nvflinger/buffer_queue_consumer.h" + +namespace android { + +BufferItemConsumer::BufferItemConsumer(std::unique_ptr consumer_) + : ConsumerBase{std::move(consumer_)} {} + +Status BufferItemConsumer::AcquireBuffer(BufferItem* item, u64 present_when_ns, + bool wait_for_fence) { + if (!item) { + return Status::BadValue; + } + + std::unique_lock lock(mutex); + + if (const auto status = AcquireBufferLocked(item, present_when_ns); status != Status::NoError) { + if (status != Status::NoBufferAvailable) { + LOG_ERROR(Service_NVFlinger, "Failed to acquire buffer: {}", status); + } + return status; + } + + if (wait_for_fence) { + UNIMPLEMENTED(); + } + + item->graphic_buffer = slots[item->slot].graphic_buffer; + + return Status::NoError; +} + +Status BufferItemConsumer::ReleaseBuffer(const BufferItem& item, Fence& release_fence) { + std::unique_lock lock(mutex); + + if (const auto status = AddReleaseFenceLocked(item.buf, item.graphic_buffer, release_fence); + status != Status::NoError) { + LOG_ERROR(Service_NVFlinger, "Failed to add fence: {}", status); + } + + if (const auto status = ReleaseBufferLocked(item.buf, item.graphic_buffer); + status != Status::NoError) { + LOG_WARNING(Service_NVFlinger, "Failed to release buffer: {}", status); + return status; + } + + return Status::NoError; +} + +} // namespace android diff --git a/src/core/hle/service/nvflinger/buffer_item_consumer.h b/src/core/hle/service/nvflinger/buffer_item_consumer.h new file mode 100644 index 000000000..f61c180b3 --- /dev/null +++ b/src/core/hle/service/nvflinger/buffer_item_consumer.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project +// Copyright 2012 The Android Open Source Project +// Parts of this implementation were base on: +// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferItemConsumer.h + +#pragma once + +#include + +#include "common/common_types.h" +#include "core/hle/service/nvflinger/consumer_base.h" +#include "core/hle/service/nvflinger/status.h" + +namespace android { + +class BufferItem; + +class BufferItemConsumer final : public ConsumerBase { +public: + explicit BufferItemConsumer(std::unique_ptr consumer); + Status AcquireBuffer(BufferItem* item, u64 present_when_ns, bool wait_for_fence = true); + Status ReleaseBuffer(const BufferItem& item, Fence& release_fence); +}; + +} // namespace android -- cgit v1.2.3 From 41983bc0ca40c4cb52198b30448464e41f914a87 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 18:49:43 -0800 Subject: hle: nvflinger: Add implementation for QueueBufferInput and QueueBufferOutput structs. --- src/core/CMakeLists.txt | 2 + .../service/nvflinger/graphic_buffer_producer.cpp | 20 ++++++ .../service/nvflinger/graphic_buffer_producer.h | 78 ++++++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 src/core/hle/service/nvflinger/graphic_buffer_producer.cpp create mode 100644 src/core/hle/service/nvflinger/graphic_buffer_producer.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 78b1e68ea..045a08648 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -547,6 +547,8 @@ add_library(core STATIC hle/service/nvflinger/consumer_base.cpp hle/service/nvflinger/consumer_base.h hle/service/nvflinger/consumer_listener.h + hle/service/nvflinger/graphic_buffer_producer.cpp + hle/service/nvflinger/graphic_buffer_producer.h hle/service/nvflinger/nvflinger.cpp hle/service/nvflinger/nvflinger.h hle/service/nvflinger/parcel.h diff --git a/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp b/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp new file mode 100644 index 000000000..3e3669c99 --- /dev/null +++ b/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project +// Copyright 2010 The Android Open Source Project +// Parts of this implementation were base on: +// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/IGraphicBufferProducer.cpp + +#pragma once + +#include "core/hle/service/nvflinger/graphic_buffer_producer.h" +#include "core/hle/service/nvflinger/parcel.h" + +namespace android { + +QueueBufferInput::QueueBufferInput(Parcel& parcel) { + parcel.ReadFlattened(*this); +} + +QueueBufferOutput::QueueBufferOutput() = default; + +} // namespace android diff --git a/src/core/hle/service/nvflinger/graphic_buffer_producer.h b/src/core/hle/service/nvflinger/graphic_buffer_producer.h new file mode 100644 index 000000000..cad683cd3 --- /dev/null +++ b/src/core/hle/service/nvflinger/graphic_buffer_producer.h @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project +// Copyright 2010 The Android Open Source Project +// Parts of this implementation were base on: +// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/IGraphicBufferProducer.h + +#pragma once + +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "core/hle/service/nvflinger/ui/fence.h" +#include "core/hle/service/nvflinger/ui/rect.h" +#include "core/hle/service/nvflinger/window.h" + +namespace android { + +class Parcel; + +#pragma pack(push, 1) +struct QueueBufferInput final { + explicit QueueBufferInput(Parcel& parcel); + + void Deflate(s64* timestamp_, bool* is_auto_timestamp_, Rect* crop_, + NativeWindowScalingMode* scaling_mode_, NativeWindowTransform* transform_, + u32* sticky_transform_, bool* async_, s32* swap_interval_, Fence* fence_) const { + *timestamp_ = timestamp; + *is_auto_timestamp_ = static_cast(is_auto_timestamp); + *crop_ = crop; + *scaling_mode_ = scaling_mode; + *transform_ = transform; + *sticky_transform_ = sticky_transform; + *async_ = static_cast(async); + *swap_interval_ = swap_interval; + *fence_ = fence; + } + +private: + s64 timestamp{}; + s32 is_auto_timestamp{}; + Rect crop{}; + NativeWindowScalingMode scaling_mode{}; + NativeWindowTransform transform{}; + u32 sticky_transform{}; + s32 async{}; + s32 swap_interval{}; + Fence fence{}; +}; +#pragma pack(pop) +static_assert(sizeof(QueueBufferInput) == 84, "QueueBufferInput has wrong size"); + +#pragma pack(push, 1) +struct QueueBufferOutput final { + QueueBufferOutput(); + + void Deflate(u32* width_, u32* height_, u32* transform_hint_, u32* num_pending_buffers_) const { + *width_ = width; + *height_ = height; + *transform_hint_ = transform_hint; + *num_pending_buffers_ = num_pending_buffers; + } + + void Inflate(u32 width_, u32 height_, u32 transform_hint_, u32 num_pending_buffers_) { + width = width_; + height = height_; + transform_hint = transform_hint_; + num_pending_buffers = num_pending_buffers_; + } + +private: + u32 width{}; + u32 height{}; + u32 transform_hint{}; + u32 num_pending_buffers{}; +}; +#pragma pack(pop) +static_assert(sizeof(QueueBufferOutput) == 16, "QueueBufferOutput has wrong size"); + +} // namespace android -- cgit v1.2.3 From 6e7f687df421e3d30b5b08e8e1747e6084e89342 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 18:53:00 -0800 Subject: hle: nvflinger: Add implementation for BufferQueueConsumer class. --- src/core/CMakeLists.txt | 2 + .../service/nvflinger/buffer_queue_consumer.cpp | 225 +++++++++++++++++++++ .../hle/service/nvflinger/buffer_queue_consumer.h | 36 ++++ 3 files changed, 263 insertions(+) create mode 100644 src/core/hle/service/nvflinger/buffer_queue_consumer.cpp create mode 100644 src/core/hle/service/nvflinger/buffer_queue_consumer.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 045a08648..c7ce6c1a6 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -541,6 +541,8 @@ add_library(core STATIC hle/service/nvflinger/buffer_item.h hle/service/nvflinger/buffer_item_consumer.cpp hle/service/nvflinger/buffer_item_consumer.h + hle/service/nvflinger/buffer_queue_consumer.cpp + hle/service/nvflinger/buffer_queue_consumer.h hle/service/nvflinger/buffer_queue_defs.h hle/service/nvflinger/buffer_slot.h hle/service/nvflinger/buffer_transform_flags.h diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp new file mode 100644 index 000000000..f0875eca3 --- /dev/null +++ b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project +// Copyright 2014 The Android Open Source Project +// Parts of this implementation were base on: +// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueConsumer.cpp + +#include "common/logging/log.h" +#include "core/hle/service/nvflinger/buffer_item.h" +#include "core/hle/service/nvflinger/buffer_queue_consumer.h" +#include "core/hle/service/nvflinger/buffer_queue_core.h" +#include "core/hle/service/nvflinger/producer_listener.h" + +namespace android { + +BufferQueueConsumer::BufferQueueConsumer(std::shared_ptr core_) + : core{std::move(core_)}, slots{core->slots} {} + +BufferQueueConsumer::~BufferQueueConsumer() = default; + +Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer, s64 expected_presenst_ns, + u64 max_frame_number) { + s32 num_dropped_buffers{}; + + std::shared_ptr listener; + { + std::unique_lock lock(core->mutex); + + // Check that the consumer doesn't currently have the maximum number of buffers acquired. + s32 num_acquired_buffers{}; + for (const auto& slot : slots) { + if (slot.buffer_state == BufferState::Acquired) { + ++num_acquired_buffers; + } + } + + if (num_acquired_buffers >= core->max_acquired_buffer_count + 1) { + LOG_ERROR(Service_NVFlinger, "max acquired buffer count reached: {} (max {})", + num_acquired_buffers, core->max_acquired_buffer_count); + return Status::InvalidOperation; + } + + // Check if the queue is empty. + if (core->queue.empty()) { + return Status::NoBufferAvailable; + } + + auto front(core->queue.begin()); + + // If expected_presenst_ns is specified, we may not want to return a buffer yet. + if (expected_presenst_ns != 0) { + constexpr auto MAX_REASONABLE_NSEC = 1000000000LL; // 1 second + + // The expected_presenst_ns argument indicates when the buffer is expected to be + // presented on-screen. + while (core->queue.size() > 1 && !core->queue[0].is_auto_timestamp) { + const auto& buffer_item{core->queue[1]}; + + // If dropping entry[0] would leave us with a buffer that the consumer is not yet + // ready for, don't drop it. + if (max_frame_number && buffer_item.frame_number > max_frame_number) { + break; + } + + // If entry[1] is timely, drop entry[0] (and repeat). + const auto desired_present = buffer_item.timestamp; + if (desired_present < expected_presenst_ns - MAX_REASONABLE_NSEC || + desired_present > expected_presenst_ns) { + // This buffer is set to display in the near future, or desired_present is + // garbage. + LOG_DEBUG(Service_NVFlinger, "nodrop desire={} expect={}", desired_present, + expected_presenst_ns); + break; + } + + LOG_DEBUG(Service_NVFlinger, "drop desire={} expect={} size={}", desired_present, + expected_presenst_ns, core->queue.size()); + + if (core->StillTracking(&*front)) { + // Front buffer is still in mSlots, so mark the slot as free + slots[front->slot].buffer_state = BufferState::Free; + core->free_buffers.push_back(front->slot); + listener = core->connected_producer_listener; + ++num_dropped_buffers; + } + + core->queue.erase(front); + front = core->queue.begin(); + } + + // See if the front buffer is ready to be acquired. + const auto desired_present = front->timestamp; + const auto buffer_is_due = desired_present <= expected_presenst_ns || + desired_present > expected_presenst_ns + MAX_REASONABLE_NSEC; + const auto consumer_is_ready = + max_frame_number > 0 ? front->frame_number <= max_frame_number : true; + + if (!buffer_is_due || !consumer_is_ready) { + LOG_DEBUG(Service_NVFlinger, "defer desire={} expect={}", desired_present, + expected_presenst_ns); + return Status::PresentLater; + } + + LOG_DEBUG(Service_NVFlinger, "accept desire={} expect={}", desired_present, + expected_presenst_ns); + } + + const auto slot = front->slot; + *out_buffer = *front; + + LOG_DEBUG(Service_NVFlinger, "acquiring slot={}", slot); + + // If the front buffer is still being tracked, update its slot state + if (core->StillTracking(&*front)) { + slots[slot].acquire_called = true; + slots[slot].needs_cleanup_on_release = false; + slots[slot].buffer_state = BufferState::Acquired; + slots[slot].fence = Fence::NoFence(); + } + + // If the buffer has previously been acquired by the consumer, set graphic_buffer to nullptr + // to avoid unnecessarily remapping this buffer on the consumer side. + if (out_buffer->acquire_called) { + out_buffer->graphic_buffer = nullptr; + } + + core->queue.erase(front); + + // We might have freed a slot while dropping old buffers, or the producer may be blocked + // waiting for the number of buffers in the queue to decrease. + core->SignalDequeueCondition(); + } + + if (listener != nullptr) { + for (s32 i = 0; i < num_dropped_buffers; ++i) { + listener->OnBufferReleased(); + } + } + + return Status::NoError; +} + +Status BufferQueueConsumer::ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence) { + if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { + LOG_ERROR(Service_NVFlinger, "slot {} out of range", slot); + return Status::BadValue; + } + + std::shared_ptr listener; + { + std::unique_lock lock(core->mutex); + + // If the frame number has changed because the buffer has been reallocated, we can ignore + // this ReleaseBuffer for the old buffer. + if (frame_number != slots[slot].frame_number) { + return Status::StaleBufferSlot; + } + + // Make sure this buffer hasn't been queued while acquired by the consumer. + auto current(core->queue.begin()); + while (current != core->queue.end()) { + if (current->slot == slot) { + LOG_ERROR(Service_NVFlinger, "buffer slot {} pending release is currently queued", + slot); + return Status::BadValue; + } + ++current; + } + + if (slots[slot].buffer_state == BufferState::Acquired) { + slots[slot].fence = release_fence; + slots[slot].buffer_state = BufferState::Free; + + core->free_buffers.push_back(slot); + + listener = core->connected_producer_listener; + + LOG_DEBUG(Service_NVFlinger, "releasing slot {}", slot); + } else if (slots[slot].needs_cleanup_on_release) { + LOG_DEBUG(Service_NVFlinger, "releasing a stale buffer slot {} (state = {})", slot, + slots[slot].buffer_state); + + slots[slot].needs_cleanup_on_release = false; + + return Status::StaleBufferSlot; + } else { + LOG_ERROR(Service_NVFlinger, "attempted to release buffer slot {} but its state was {}", + slot, slots[slot].buffer_state); + + return Status::BadValue; + } + + core->dequeue_condition.notify_all(); + } + + // Call back without lock held + if (listener != nullptr) { + listener->OnBufferReleased(); + } + + return Status::NoError; +} + +Status BufferQueueConsumer::Connect(std::shared_ptr consumer_listener, + bool controlled_by_app) { + if (consumer_listener == nullptr) { + LOG_ERROR(Service_NVFlinger, "consumer_listener may not be nullptr"); + return Status::BadValue; + } + + LOG_DEBUG(Service_NVFlinger, "controlled_by_app={}", controlled_by_app); + + BufferQueueCore::AutoLock lock(core); + + if (core->is_abandoned) { + LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); + return Status::NoInit; + } + + core->consumer_listener = consumer_listener; + core->consumer_controlled_by_app = controlled_by_app; + + return Status::NoError; +} + +} // namespace android diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.h b/src/core/hle/service/nvflinger/buffer_queue_consumer.h new file mode 100644 index 000000000..fbeb8b8d7 --- /dev/null +++ b/src/core/hle/service/nvflinger/buffer_queue_consumer.h @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project +// Copyright 2014 The Android Open Source Project +// Parts of this implementation were base on: +// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferQueueConsumer.h + +#pragma once + +#include + +#include "common/common_types.h" +#include "core/hle/service/nvflinger/buffer_queue_defs.h" +#include "core/hle/service/nvflinger/status.h" + +namespace android { + +class BufferItem; +class BufferQueueCore; +class IConsumerListener; + +class BufferQueueConsumer final { +public: + explicit BufferQueueConsumer(std::shared_ptr core_); + ~BufferQueueConsumer(); + + Status AcquireBuffer(BufferItem* out_buffer, s64 expected_presenst_ns, + u64 max_frame_number = 0); + Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence); + Status Connect(std::shared_ptr consumer_listener, bool controlled_by_app); + +private: + std::shared_ptr core; + BufferQueueDefs::SlotsType& slots; +}; + +} // namespace android -- cgit v1.2.3 From bfff7b58fd06d738ef3d8d40de46290b1cc158a5 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 18:56:11 -0800 Subject: hle: nvflinger: Add implementation for BufferQueueCore class. --- src/core/CMakeLists.txt | 2 + .../hle/service/nvflinger/buffer_queue_core.cpp | 135 +++++++++++++++++++++ src/core/hle/service/nvflinger/buffer_queue_core.h | 98 +++++++++++++++ 3 files changed, 235 insertions(+) create mode 100644 src/core/hle/service/nvflinger/buffer_queue_core.cpp create mode 100644 src/core/hle/service/nvflinger/buffer_queue_core.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c7ce6c1a6..5ba9b6c09 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -543,6 +543,8 @@ add_library(core STATIC hle/service/nvflinger/buffer_item_consumer.h hle/service/nvflinger/buffer_queue_consumer.cpp hle/service/nvflinger/buffer_queue_consumer.h + hle/service/nvflinger/buffer_queue_core.cpp + hle/service/nvflinger/buffer_queue_core.h hle/service/nvflinger/buffer_queue_defs.h hle/service/nvflinger/buffer_slot.h hle/service/nvflinger/buffer_transform_flags.h diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.cpp b/src/core/hle/service/nvflinger/buffer_queue_core.cpp new file mode 100644 index 000000000..a6ff46aa9 --- /dev/null +++ b/src/core/hle/service/nvflinger/buffer_queue_core.cpp @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project +// Copyright 2014 The Android Open Source Project +// Parts of this implementation were base on: +// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueCore.cpp + +#include "common/assert.h" + +#include "core/hle/service/nvflinger/buffer_queue_core.h" + +namespace android { + +BufferQueueCore::BufferQueueCore() : lock{mutex} { + // This is locked on creation, so unlock. + lock.unlock(); + + for (s32 slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) { + free_slots.insert(slot); + } +} + +void BufferQueueCore::NotifyShutdown() { + std::unique_lock lk(mutex); + + is_shutting_down = true; + + SignalDequeueCondition(); +} + +void BufferQueueCore::SignalDequeueCondition() { + dequeue_condition.notify_all(); +} + +bool BufferQueueCore::WaitForDequeueCondition() { + if (is_shutting_down) { + return false; + } + + dequeue_condition.wait(lock); + + return true; +} + +s32 BufferQueueCore::GetMinUndequeuedBufferCountLocked(bool async) const { + // If DequeueBuffer is allowed to error out, we don't have to add an extra buffer. + if (!use_async_buffer) { + return max_acquired_buffer_count; + } + + if (dequeue_buffer_cannot_block || async) { + return max_acquired_buffer_count + 1; + } + + return max_acquired_buffer_count; +} + +s32 BufferQueueCore::GetMinMaxBufferCountLocked(bool async) const { + return GetMinUndequeuedBufferCountLocked(async) + 1; +} + +s32 BufferQueueCore::GetMaxBufferCountLocked(bool async) const { + const auto min_buffer_count = GetMinMaxBufferCountLocked(async); + auto max_buffer_count = std::max(default_max_buffer_count, min_buffer_count); + + if (override_max_buffer_count != 0) { + ASSERT(override_max_buffer_count >= min_buffer_count); + max_buffer_count = override_max_buffer_count; + } + + // Any buffers that are dequeued by the producer or sitting in the queue waiting to be consumed + // need to have their slots preserved. + for (s32 slot = max_buffer_count; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) { + const auto state = slots[slot].buffer_state; + if (state == BufferState::Queued || state == BufferState::Dequeued) { + max_buffer_count = slot + 1; + } + } + + return max_buffer_count; +} + +s32 BufferQueueCore::GetPreallocatedBufferCountLocked() const { + return static_cast(std::count_if(slots.begin(), slots.end(), + [](const auto& slot) { return slot.is_preallocated; })); +} + +void BufferQueueCore::FreeBufferLocked(s32 slot) { + LOG_DEBUG(Service_NVFlinger, "slot {}", slot); + + const auto had_buffer = slots[slot].graphic_buffer != nullptr; + + slots[slot].graphic_buffer.reset(); + + if (slots[slot].buffer_state == BufferState::Acquired) { + slots[slot].needs_cleanup_on_release = true; + } + + if (slots[slot].buffer_state != BufferState::Free) { + free_slots.insert(slot); + } else if (had_buffer) { + // If the slot was FREE, but we had a buffer, we need to move this slot from the free + // buffers list to the the free slots list. + free_buffers.remove(slot); + free_slots.insert(slot); + } + + slots[slot].buffer_state = BufferState::Free; + slots[slot].acquire_called = false; + slots[slot].frame_number = 0; + slots[slot].fence = Fence::NoFence(); +} + +void BufferQueueCore::FreeAllBuffersLocked() { + queue.clear(); + buffer_has_been_queued = false; + + for (s32 slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) { + FreeBufferLocked(slot); + } +} + +bool BufferQueueCore::StillTracking(const BufferItem* item) const { + const BufferSlot& slot = slots[item->slot]; + + return (slot.graphic_buffer != nullptr) && (item->graphic_buffer == slot.graphic_buffer); +} + +void BufferQueueCore::WaitWhileAllocatingLocked() const { + while (is_allocating) { + std::unique_lock lk(mutex); + is_allocating_condition.wait(lk); + } +} + +} // namespace android diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.h b/src/core/hle/service/nvflinger/buffer_queue_core.h new file mode 100644 index 000000000..8019b7024 --- /dev/null +++ b/src/core/hle/service/nvflinger/buffer_queue_core.h @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project +// Copyright 2014 The Android Open Source Project +// Parts of this implementation were base on: +// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferQueueCore.h + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "core/hle/service/nvflinger/buffer_item.h" +#include "core/hle/service/nvflinger/buffer_queue_defs.h" +#include "core/hle/service/nvflinger/pixel_format.h" +#include "core/hle/service/nvflinger/status.h" +#include "core/hle/service/nvflinger/window.h" + +namespace android { + +class IConsumerListener; +class IProducerListener; + +class BufferQueueCore final { + friend class BufferQueueProducer; + friend class BufferQueueConsumer; + +public: + static constexpr s32 INVALID_BUFFER_SLOT = BufferItem::INVALID_BUFFER_SLOT; + + BufferQueueCore(); + + void NotifyShutdown(); + +private: + void SignalDequeueCondition(); + bool WaitForDequeueCondition(); + + s32 GetMinUndequeuedBufferCountLocked(bool async) const; + s32 GetMinMaxBufferCountLocked(bool async) const; + s32 GetMaxBufferCountLocked(bool async) const; + s32 GetPreallocatedBufferCountLocked() const; + void FreeBufferLocked(s32 slot); + void FreeAllBuffersLocked(); + bool StillTracking(const BufferItem* item) const; + void WaitWhileAllocatingLocked() const; + +private: + class AutoLock final { + public: + AutoLock(std::shared_ptr& core_) : core{core_} { + core->lock.lock(); + } + + ~AutoLock() { + core->lock.unlock(); + } + + private: + std::shared_ptr& core; + }; + +private: + mutable std::mutex mutex; + mutable std::unique_lock lock; + bool is_abandoned{}; + bool consumer_controlled_by_app{}; + std::shared_ptr consumer_listener; + u32 consumer_usage_bit{}; + NativeWindowApi connected_api{NativeWindowApi::NoConnectedApi}; + std::shared_ptr connected_producer_listener; + BufferQueueDefs::SlotsType slots{}; + std::vector queue; + std::set free_slots; + std::list free_buffers; + s32 override_max_buffer_count{}; + mutable std::condition_variable dequeue_condition; + const bool use_async_buffer{}; // This is always disabled on HOS + bool dequeue_buffer_cannot_block{}; + PixelFormat default_buffer_format{PixelFormat::Rgba8888}; + u32 default_width{1}; + u32 default_height{1}; + s32 default_max_buffer_count{2}; + const s32 max_acquired_buffer_count{}; // This is always zero on HOS + bool buffer_has_been_queued{}; + u64 frame_counter{}; + u32 transform_hint{}; + bool is_allocating{}; + mutable std::condition_variable is_allocating_condition; + bool allow_allocation{true}; + u64 buffer_age{}; + bool is_shutting_down{}; +}; + +} // namespace android -- cgit v1.2.3 From 56284bff6c312da130eb0f2d0cda80cd29c82046 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 19:12:36 -0800 Subject: hle: nvflinger: Add implementation for BufferQueueProducer class. --- src/core/CMakeLists.txt | 4 +- .../service/nvflinger/buffer_queue_producer.cpp | 936 +++++++++++++++++++++ .../hle/service/nvflinger/buffer_queue_producer.h | 83 ++ 3 files changed, 1021 insertions(+), 2 deletions(-) create mode 100644 src/core/hle/service/nvflinger/buffer_queue_producer.cpp create mode 100644 src/core/hle/service/nvflinger/buffer_queue_producer.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 5ba9b6c09..669de3091 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -535,8 +535,6 @@ add_library(core STATIC hle/service/nvdrv/nvmemp.h hle/service/nvdrv/syncpoint_manager.cpp hle/service/nvdrv/syncpoint_manager.h - hle/service/nvflinger/buffer_queue.cpp - hle/service/nvflinger/buffer_queue.h hle/service/nvflinger/binder.h hle/service/nvflinger/buffer_item.h hle/service/nvflinger/buffer_item_consumer.cpp @@ -546,6 +544,8 @@ add_library(core STATIC hle/service/nvflinger/buffer_queue_core.cpp hle/service/nvflinger/buffer_queue_core.h hle/service/nvflinger/buffer_queue_defs.h + hle/service/nvflinger/buffer_queue_producer.cpp + hle/service/nvflinger/buffer_queue_producer.h hle/service/nvflinger/buffer_slot.h hle/service/nvflinger/buffer_transform_flags.h hle/service/nvflinger/consumer_base.cpp diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp new file mode 100644 index 000000000..d48e96b14 --- /dev/null +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp @@ -0,0 +1,936 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project +// Copyright 2014 The Android Open Source Project +// Parts of this implementation were base on: +// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueProducer.cpp + +#include "common/assert.h" +#include "common/logging/log.h" +#include "common/settings.h" +#include "core/core.h" +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_readable_event.h" +#include "core/hle/kernel/k_writable_event.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/nvdrv/nvdrv.h" +#include "core/hle/service/nvflinger/buffer_queue_core.h" +#include "core/hle/service/nvflinger/buffer_queue_producer.h" +#include "core/hle/service/nvflinger/consumer_listener.h" +#include "core/hle/service/nvflinger/parcel.h" +#include "core/hle/service/nvflinger/ui/graphic_buffer.h" +#include "core/hle/service/nvflinger/window.h" +#include "core/hle/service/vi/vi.h" + +namespace android { + +BufferQueueProducer::BufferQueueProducer(Service::KernelHelpers::ServiceContext& service_context_, + std::shared_ptr buffer_queue_core_) + : service_context{service_context_}, core{std::move(buffer_queue_core_)}, slots(core->slots) { + buffer_wait_event = service_context.CreateEvent("BufferQueue:WaitEvent"); +} + +BufferQueueProducer::~BufferQueueProducer() { + service_context.CloseEvent(buffer_wait_event); +} + +Status BufferQueueProducer::RequestBuffer(s32 slot, std::shared_ptr* buf) { + LOG_DEBUG(Service_NVFlinger, "slot {}", slot); + + BufferQueueCore::AutoLock lock(core); + + if (core->is_abandoned) { + LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); + return Status::NoInit; + } + if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { + LOG_ERROR(Service_NVFlinger, "slot index {} out of range [0, {})", slot, + BufferQueueDefs::NUM_BUFFER_SLOTS); + return Status::BadValue; + } else if (slots[slot].buffer_state != BufferState::Dequeued) { + LOG_ERROR(Service_NVFlinger, "slot {} is not owned by the producer (state = {})", slot, + slots[slot].buffer_state); + return Status::BadValue; + } + + slots[slot].request_buffer_called = true; + *buf = slots[slot].graphic_buffer; + + return Status::NoError; +} + +Status BufferQueueProducer::SetBufferCount(s32 buffer_count) { + LOG_DEBUG(Service_NVFlinger, "count = {}", buffer_count); + std::shared_ptr listener; + + { + BufferQueueCore::AutoLock lock(core); + core->WaitWhileAllocatingLocked(); + if (core->is_abandoned) { + LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); + return Status::NoInit; + } + + if (buffer_count > BufferQueueDefs::NUM_BUFFER_SLOTS) { + LOG_ERROR(Service_NVFlinger, "buffer_count {} too large (max {})", buffer_count, + BufferQueueDefs::NUM_BUFFER_SLOTS); + return Status::BadValue; + } + + // There must be no dequeued buffers when changing the buffer count. + for (s32 s{}; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { + if (slots[s].buffer_state == BufferState::Dequeued) { + LOG_ERROR(Service_NVFlinger, "buffer owned by producer"); + return Status::BadValue; + } + } + + if (buffer_count == 0) { + core->override_max_buffer_count = 0; + core->SignalDequeueCondition(); + return Status::NoError; + } + + const s32 min_buffer_slots = core->GetMinMaxBufferCountLocked(false); + if (buffer_count < min_buffer_slots) { + LOG_ERROR(Service_NVFlinger, "requested buffer count {} is less than minimum {}", + buffer_count, min_buffer_slots); + return Status::BadValue; + } + + // Here we are guaranteed that the producer doesn't have any dequeued buffers and will + // release all of its buffer references. + if (core->GetPreallocatedBufferCountLocked() <= 0) { + core->FreeAllBuffersLocked(); + } + + core->override_max_buffer_count = buffer_count; + core->SignalDequeueCondition(); + buffer_wait_event->GetWritableEvent().Signal(); + listener = core->consumer_listener; + } + + // Call back without lock held + if (listener != nullptr) { + listener->OnBuffersReleased(); + } + + return Status::NoError; +} + +Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, + Status* returnFlags) const { + bool try_again = true; + + while (try_again) { + if (core->is_abandoned) { + LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); + return Status::NoInit; + } + + const s32 max_buffer_count = core->GetMaxBufferCountLocked(async); + if (async && core->override_max_buffer_count) { + if (core->override_max_buffer_count < max_buffer_count) { + LOG_ERROR(Service_NVFlinger, "async mode is invalid with buffer count override"); + return Status::BadValue; + } + } + + // Free up any buffers that are in slots beyond the max buffer count + for (s32 s = max_buffer_count; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { + ASSERT(slots[s].buffer_state == BufferState::Free); + if (slots[s].graphic_buffer != nullptr) { + core->FreeBufferLocked(s); + *returnFlags |= Status::ReleaseAllBuffers; + } + } + + s32 dequeued_count{}; + s32 acquired_count{}; + for (s32 s{}; s < max_buffer_count; ++s) { + switch (slots[s].buffer_state) { + case BufferState::Dequeued: + ++dequeued_count; + break; + case BufferState::Acquired: + ++acquired_count; + break; + default: + break; + } + } + + // Producers are not allowed to dequeue more than one buffer if they did not set a buffer + // count + if (!core->override_max_buffer_count && dequeued_count) { + LOG_ERROR(Service_NVFlinger, + "can't dequeue multiple buffers without setting the buffer count"); + return Status::InvalidOperation; + } + + // See whether a buffer has been queued since the last SetBufferCount so we know whether to + // perform the min undequeued buffers check below + if (core->buffer_has_been_queued) { + // Make sure the producer is not trying to dequeue more buffers than allowed + const s32 new_undequeued_count = max_buffer_count - (dequeued_count + 1); + const s32 min_undequeued_count = core->GetMinUndequeuedBufferCountLocked(async); + if (new_undequeued_count < min_undequeued_count) { + LOG_ERROR(Service_NVFlinger, + "min undequeued buffer count({}) exceeded (dequeued={} undequeued={})", + min_undequeued_count, dequeued_count, new_undequeued_count); + return Status::InvalidOperation; + } + } + + *found = BufferQueueCore::INVALID_BUFFER_SLOT; + + // If we disconnect and reconnect quickly, we can be in a state where our slots are empty + // but we have many buffers in the queue. This can cause us to run out of memory if we + // outrun the consumer. Wait here if it looks like we have too many buffers queued up. + const bool too_many_buffers = core->queue.size() > static_cast(max_buffer_count); + if (too_many_buffers) { + LOG_ERROR(Service_NVFlinger, "queue size is {}, waiting", core->queue.size()); + } else { + if (!core->free_buffers.empty()) { + auto slot = core->free_buffers.begin(); + *found = *slot; + core->free_buffers.erase(slot); + } else if (core->allow_allocation && !core->free_slots.empty()) { + auto slot = core->free_slots.begin(); + // Only return free slots up to the max buffer count + if (*slot < max_buffer_count) { + *found = *slot; + core->free_slots.erase(slot); + } + } + } + + // If no buffer is found, or if the queue has too many buffers outstanding, wait for a + // buffer to be acquired or released, or for the max buffer count to change. + try_again = (*found == BufferQueueCore::INVALID_BUFFER_SLOT) || too_many_buffers; + if (try_again) { + // Return an error if we're in non-blocking mode (producer and consumer are controlled + // by the application). + if (core->dequeue_buffer_cannot_block && + (acquired_count <= core->max_acquired_buffer_count)) { + return Status::WouldBlock; + } + + if (!core->WaitForDequeueCondition()) { + // We are no longer running + return Status::NoError; + } + } + } + + return Status::NoError; +} + +Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool async, u32 width, + u32 height, PixelFormat format, u32 usage) { + { BufferQueueCore::AutoLock lock(core); } + + LOG_DEBUG(Service_NVFlinger, "async={} w={} h={} format={}, usage={}", async ? "true" : "false", + width, height, format, usage); + + if ((width && !height) || (!width && height)) { + LOG_ERROR(Service_NVFlinger, "invalid size: w={} h={}", width, height); + return Status::BadValue; + } + + Status return_flags = Status::NoError; + bool attached_by_consumer = false; + { + BufferQueueCore::AutoLock lock(core); + core->WaitWhileAllocatingLocked(); + if (format == PixelFormat::NoFormat) { + format = core->default_buffer_format; + } + + // Enable the usage bits the consumer requested + usage |= core->consumer_usage_bit; + const bool use_default_size = !width && !height; + if (use_default_size) { + width = core->default_width; + height = core->default_height; + } + + s32 found = BufferItem::INVALID_BUFFER_SLOT; + while (found == BufferItem::INVALID_BUFFER_SLOT) { + Status status = WaitForFreeSlotThenRelock(async, &found, &return_flags); + if (status != Status::NoError) { + return status; + } + + // This should not happen + if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { + LOG_DEBUG(Service_NVFlinger, "no available buffer slots"); + return Status::Busy; + } + + const std::shared_ptr& buffer(slots[found].graphic_buffer); + + // If we are not allowed to allocate new buffers, WaitForFreeSlotThenRelock must have + // returned a slot containing a buffer. If this buffer would require reallocation to + // meet the requested attributes, we free it and attempt to get another one. + if (!core->allow_allocation) { + if (buffer->NeedsReallocation(width, height, format, usage)) { + core->FreeBufferLocked(found); + found = BufferItem::INVALID_BUFFER_SLOT; + continue; + } + } + } + + *out_slot = found; + attached_by_consumer = slots[found].attached_by_consumer; + slots[found].buffer_state = BufferState::Dequeued; + + const std::shared_ptr& buffer(slots[found].graphic_buffer); + + if ((buffer == nullptr) || buffer->NeedsReallocation(width, height, format, usage)) { + slots[found].acquire_called = false; + slots[found].graphic_buffer = nullptr; + slots[found].request_buffer_called = false; + slots[found].fence = Fence::NoFence(); + core->buffer_age = 0; + return_flags |= Status::BufferNeedsReallocation; + } else { + // We add 1 because that will be the frame number when this buffer + // is queued + core->buffer_age = core->frame_counter + 1 - slots[found].frame_number; + } + + LOG_DEBUG(Service_NVFlinger, "setting buffer age to {}", core->buffer_age); + + *out_fence = slots[found].fence; + + slots[found].fence = Fence::NoFence(); + } + + if ((return_flags & Status::BufferNeedsReallocation) != Status::None) { + LOG_DEBUG(Service_NVFlinger, "allocating a new buffer for slot {}", *out_slot); + + auto graphic_buffer = std::make_shared(width, height, format, usage); + if (graphic_buffer == nullptr) { + LOG_ERROR(Service_NVFlinger, "creating GraphicBuffer failed"); + return Status::NoMemory; + } + + { + BufferQueueCore::AutoLock lock(core); + if (core->is_abandoned) { + LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); + return Status::NoInit; + } + + slots[*out_slot].graphic_buffer = graphic_buffer; + } + } + + if (attached_by_consumer) { + return_flags |= Status::BufferNeedsReallocation; + } + + LOG_DEBUG(Service_NVFlinger, "returning slot={} frame={}, flags={}", *out_slot, + slots[*out_slot].frame_number, return_flags); + return return_flags; +} + +Status BufferQueueProducer::DetachBuffer(s32 slot) { + LOG_DEBUG(Service_NVFlinger, "slot {}", slot); + + BufferQueueCore::AutoLock lock(core); + if (core->is_abandoned) { + LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); + return Status::NoInit; + } + + if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { + LOG_ERROR(Service_NVFlinger, "slot {} out of range [0, {})", slot, + BufferQueueDefs::NUM_BUFFER_SLOTS); + return Status::BadValue; + } else if (slots[slot].buffer_state != BufferState::Dequeued) { + LOG_ERROR(Service_NVFlinger, "slot {} is not owned by the producer (state = {})", slot, + slots[slot].buffer_state); + return Status::BadValue; + } else if (!slots[slot].request_buffer_called) { + LOG_ERROR(Service_NVFlinger, "buffer in slot {} has not been requested", slot); + return Status::BadValue; + } + + core->FreeBufferLocked(slot); + core->SignalDequeueCondition(); + + return Status::NoError; +} + +Status BufferQueueProducer::DetachNextBuffer(std::shared_ptr* out_buffer, + Fence* out_fence) { + if (out_buffer == nullptr) { + LOG_ERROR(Service_NVFlinger, "out_buffer must not be nullptr"); + return Status::BadValue; + } else if (out_fence == nullptr) { + LOG_ERROR(Service_NVFlinger, "out_fence must not be nullptr"); + return Status::BadValue; + } + + BufferQueueCore::AutoLock lock(core); + + core->WaitWhileAllocatingLocked(); + + if (core->is_abandoned) { + LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); + return Status::NoInit; + } + if (core->free_buffers.empty()) { + return Status::NoMemory; + } + + const s32 found = core->free_buffers.front(); + core->free_buffers.remove(found); + + LOG_DEBUG(Service_NVFlinger, "Detached slot {}", found); + + *out_buffer = slots[found].graphic_buffer; + *out_fence = slots[found].fence; + + core->FreeBufferLocked(found); + + return Status::NoError; +} + +Status BufferQueueProducer::AttachBuffer(s32* out_slot, + const std::shared_ptr& buffer) { + if (out_slot == nullptr) { + LOG_ERROR(Service_NVFlinger, "out_slot must not be nullptr"); + return Status::BadValue; + } else if (buffer == nullptr) { + LOG_ERROR(Service_NVFlinger, "Cannot attach nullptr buffer"); + return Status::BadValue; + } + + BufferQueueCore::AutoLock lock(core); + core->WaitWhileAllocatingLocked(); + + Status return_flags = Status::NoError; + s32 found{}; + + const auto status = WaitForFreeSlotThenRelock(false, &found, &return_flags); + if (status != Status::NoError) { + return status; + } + + if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { + LOG_ERROR(Service_NVFlinger, "No available buffer slots"); + return Status::Busy; + } + + *out_slot = found; + + LOG_DEBUG(Service_NVFlinger, "Returning slot {} flags={}", *out_slot, return_flags); + + slots[*out_slot].graphic_buffer = buffer; + slots[*out_slot].buffer_state = BufferState::Dequeued; + slots[*out_slot].fence = Fence::NoFence(); + slots[*out_slot].request_buffer_called = true; + + return return_flags; +} + +Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input, + QueueBufferOutput* output) { + s64 timestamp{}; + bool is_auto_timestamp{}; + Rect crop; + NativeWindowScalingMode scaling_mode{}; + NativeWindowTransform transform; + u32 sticky_transform_{}; + bool async{}; + s32 swap_interval{}; + Fence fence{}; + + input.Deflate(×tamp, &is_auto_timestamp, &crop, &scaling_mode, &transform, + &sticky_transform_, &async, &swap_interval, &fence); + + switch (scaling_mode) { + case NativeWindowScalingMode::Freeze: + case NativeWindowScalingMode::ScaleToWindow: + case NativeWindowScalingMode::ScaleCrop: + case NativeWindowScalingMode::NoScaleCrop: + break; + default: + LOG_ERROR(Service_NVFlinger, "unknown scaling mode {}", scaling_mode); + return Status::BadValue; + } + + std::shared_ptr frameAvailableListener; + std::shared_ptr frameReplacedListener; + s32 callback_ticket{}; + BufferItem item; + + { + BufferQueueCore::AutoLock lock(core); + + if (core->is_abandoned) { + LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); + return Status::NoInit; + } + + const s32 max_buffer_count = core->GetMaxBufferCountLocked(async); + if (async && core->override_max_buffer_count) { + if (core->override_max_buffer_count < max_buffer_count) { + LOG_ERROR(Service_NVFlinger, "async mode is invalid with " + "buffer count override"); + return Status::BadValue; + } + } + + if (slot < 0 || slot >= max_buffer_count) { + LOG_ERROR(Service_NVFlinger, "slot index {} out of range [0, {})", slot, + max_buffer_count); + return Status::BadValue; + } else if (slots[slot].buffer_state != BufferState::Dequeued) { + LOG_ERROR(Service_NVFlinger, + "slot {} is not owned by the producer " + "(state = {})", + slot, slots[slot].buffer_state); + return Status::BadValue; + } else if (!slots[slot].request_buffer_called) { + LOG_ERROR(Service_NVFlinger, + "slot {} was queued without requesting " + "a buffer", + slot); + return Status::BadValue; + } + + LOG_DEBUG(Service_NVFlinger, + "slot={} frame={} time={} crop=[{},{},{},{}] transform={} scale={}", slot, + core->frame_counter + 1, timestamp, crop.Left(), crop.Top(), crop.Right(), + crop.Bottom(), transform, scaling_mode); + + const std::shared_ptr& graphic_buffer(slots[slot].graphic_buffer); + Rect buffer_rect(graphic_buffer->Width(), graphic_buffer->Height()); + Rect cropped_rect; + crop.Intersect(buffer_rect, &cropped_rect); + + if (cropped_rect != crop) { + LOG_ERROR(Service_NVFlinger, "crop rect is not contained within the buffer in slot {}", + slot); + return Status::BadValue; + } + + slots[slot].fence = fence; + slots[slot].buffer_state = BufferState::Queued; + ++core->frame_counter; + slots[slot].frame_number = core->frame_counter; + + item.acquire_called = slots[slot].acquire_called; + item.graphic_buffer = slots[slot].graphic_buffer; + item.crop = crop; + item.transform = transform & ~NativeWindowTransform::InverseDisplay; + item.transform_to_display_inverse = + (transform & NativeWindowTransform::InverseDisplay) != NativeWindowTransform::None; + item.scaling_mode = static_cast(scaling_mode); + item.timestamp = timestamp; + item.is_auto_timestamp = is_auto_timestamp; + item.frame_number = core->frame_counter; + item.slot = slot; + item.fence = fence; + item.is_droppable = core->dequeue_buffer_cannot_block || async; + item.swap_interval = swap_interval; + sticky_transform = sticky_transform_; + + if (core->queue.empty()) { + // When the queue is empty, we can simply queue this buffer + core->queue.push_back(item); + frameAvailableListener = core->consumer_listener; + } else { + // When the queue is not empty, we need to look at the front buffer + // state to see if we need to replace it + auto front(core->queue.begin()); + + if (front->is_droppable) { + // If the front queued buffer is still being tracked, we first + // mark it as freed + if (core->StillTracking(&*front)) { + slots[front->slot].buffer_state = BufferState::Free; + core->free_buffers.push_front(front->slot); + } + // Overwrite the droppable buffer with the incoming one + *front = item; + frameReplacedListener = core->consumer_listener; + } else { + core->queue.push_back(item); + frameAvailableListener = core->consumer_listener; + } + } + + core->buffer_has_been_queued = true; + core->SignalDequeueCondition(); + output->Inflate(core->default_width, core->default_height, core->transform_hint, + static_cast(core->queue.size())); + + // Take a ticket for the callback functions + callback_ticket = next_callback_ticket++; + } + + // Don't send the GraphicBuffer through the callback, and don't send the slot number, since the + // consumer shouldn't need it + item.graphic_buffer.reset(); + item.slot = BufferItem::INVALID_BUFFER_SLOT; + + // Call back without the main BufferQueue lock held, but with the callback lock held so we can + // ensure that callbacks occur in order + { + std::unique_lock lock(callback_mutex); + while (callback_ticket != current_callback_ticket) { + std::unique_lock lk(callback_mutex); + callback_condition.wait(lk); + } + + if (frameAvailableListener != nullptr) { + frameAvailableListener->OnFrameAvailable(item); + } else if (frameReplacedListener != nullptr) { + frameReplacedListener->OnFrameReplaced(item); + } + + ++current_callback_ticket; + callback_condition.notify_all(); + } + + return Status::NoError; +} + +void BufferQueueProducer::CancelBuffer(s32 slot, const Fence& fence) { + LOG_DEBUG(Service_NVFlinger, "slot {}", slot); + + BufferQueueCore::AutoLock lock(core); + + if (core->is_abandoned) { + LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); + return; + } + + if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { + LOG_ERROR(Service_NVFlinger, "slot index {} out of range [0, {})", slot, + BufferQueueDefs::NUM_BUFFER_SLOTS); + return; + } else if (slots[slot].buffer_state != BufferState::Dequeued) { + LOG_ERROR(Service_NVFlinger, "slot {} is not owned by the producer (state = {})", slot, + slots[slot].buffer_state); + return; + } + + core->free_buffers.push_front(slot); + slots[slot].buffer_state = BufferState::Free; + slots[slot].fence = fence; + + core->SignalDequeueCondition(); + buffer_wait_event->GetWritableEvent().Signal(); +} + +Status BufferQueueProducer::Query(NativeWindow what, s32* out_value) { + BufferQueueCore::AutoLock lock(core); + + if (out_value == nullptr) { + LOG_ERROR(Service_NVFlinger, "outValue was nullptr"); + return Status::BadValue; + } + + if (core->is_abandoned) { + LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); + return Status::NoInit; + } + + s32 value{}; + switch (what) { + case NativeWindow::Width: + value = static_cast(core->default_width); + break; + case NativeWindow::Height: + value = static_cast(core->default_height); + break; + case NativeWindow::Format: + value = static_cast(core->default_buffer_format); + break; + case NativeWindow::MinUndequeedBuffers: + value = core->GetMinUndequeuedBufferCountLocked(false); + break; + case NativeWindow::StickyTransform: + value = static_cast(sticky_transform); + break; + case NativeWindow::ConsumerRunningBehind: + value = (core->queue.size() > 1); + break; + case NativeWindow::ConsumerUsageBits: + value = static_cast(core->consumer_usage_bit); + break; + case NativeWindow::BufferAge: + if (core->buffer_age > INT32_MAX) { + value = 0; + } else { + value = static_cast(core->buffer_age); + } + break; + default: + UNREACHABLE(); + return Status::BadValue; + } + + LOG_DEBUG(Service_NVFlinger, "what = {}, value = {}", what, value); + + *out_value = value; + + return Status::NoError; +} + +Status BufferQueueProducer::Connect(const std::shared_ptr& listener, + NativeWindowApi api, bool producer_controlled_by_app, + QueueBufferOutput* output) { + BufferQueueCore::AutoLock lock(core); + + LOG_DEBUG(Service_NVFlinger, "api = {} producer_controlled_by_app = {}", api, + producer_controlled_by_app); + + if (core->is_abandoned) { + LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned"); + return Status::NoInit; + } + + if (core->consumer_listener == nullptr) { + LOG_ERROR(Service_NVFlinger, "BufferQueue has no consumer"); + return Status::NoInit; + } + + if (output == nullptr) { + LOG_ERROR(Service_NVFlinger, "output was nullptr"); + return Status::BadValue; + } + + if (core->connected_api != NativeWindowApi::NoConnectedApi) { + LOG_ERROR(Service_NVFlinger, "already connected (cur = {} req = {})", core->connected_api, + api); + return Status::BadValue; + } + + Status status = Status::NoError; + switch (api) { + case NativeWindowApi::Egl: + case NativeWindowApi::Cpu: + case NativeWindowApi::Media: + case NativeWindowApi::Camera: + core->connected_api = api; + output->Inflate(core->default_width, core->default_height, core->transform_hint, + static_cast(core->queue.size())); + core->connected_producer_listener = listener; + break; + default: + LOG_ERROR(Service_NVFlinger, "unknown api = {}", api); + status = Status::BadValue; + break; + } + + core->buffer_has_been_queued = false; + core->dequeue_buffer_cannot_block = + core->consumer_controlled_by_app && producer_controlled_by_app; + core->allow_allocation = true; + + return status; +} + +Status BufferQueueProducer::Disconnect(NativeWindowApi api) { + LOG_DEBUG(Service_NVFlinger, "api = {}", api); + + Status status = Status::NoError; + std::shared_ptr listener; + + { + BufferQueueCore::AutoLock lock(core); + + core->WaitWhileAllocatingLocked(); + + if (core->is_abandoned) { + // Disconnecting after the surface has been abandoned is a no-op. + return Status::NoError; + } + + switch (api) { + case NativeWindowApi::Egl: + case NativeWindowApi::Cpu: + case NativeWindowApi::Media: + case NativeWindowApi::Camera: + if (core->connected_api == api) { + core->FreeAllBuffersLocked(); + core->connected_producer_listener = nullptr; + core->connected_api = NativeWindowApi::NoConnectedApi; + core->SignalDequeueCondition(); + buffer_wait_event->GetWritableEvent().Signal(); + listener = core->consumer_listener; + } else if (core->connected_api != NativeWindowApi::NoConnectedApi) { + LOG_ERROR(Service_NVFlinger, "still connected to another api (cur = {} req = {})", + core->connected_api, api); + status = Status::BadValue; + } + break; + default: + LOG_ERROR(Service_NVFlinger, "unknown api = {}", api); + status = Status::BadValue; + break; + } + } + + // Call back without lock held + if (listener != nullptr) { + listener->OnBuffersReleased(); + } + + return status; +} + +Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot, + const std::shared_ptr& buffer) { + LOG_DEBUG(Service_NVFlinger, "slot {}", slot); + + UNIMPLEMENTED_IF_MSG(!buffer, "buffer must be valid!"); + + if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { + return Status::BadValue; + } + + BufferQueueCore::AutoLock lock(core); + + slots[slot] = {}; + slots[slot].is_preallocated = true; + slots[slot].graphic_buffer = buffer; + + core->override_max_buffer_count = core->GetPreallocatedBufferCountLocked(); + core->default_width = buffer->Width(); + core->default_height = buffer->Height(); + core->default_buffer_format = buffer->Format(); + + core->SignalDequeueCondition(); + buffer_wait_event->GetWritableEvent().Signal(); + + return Status::NoError; +} + +void BufferQueueProducer::Transact(Kernel::HLERequestContext& ctx, TransactionId code, u32 flags) { + Status status{Status::NoError}; + Parcel parcel_in{ctx.ReadBuffer()}; + Parcel parcel_out{}; + + switch (code) { + case TransactionId::Connect: { + const auto enable_listener = parcel_in.Read(); + const auto api = parcel_in.Read(); + const auto producer_controlled_by_app = parcel_in.Read(); + + UNIMPLEMENTED_IF_MSG(enable_listener, "Listener is unimplemented!"); + + std::shared_ptr listener; + QueueBufferOutput output{}; + + status = Connect(listener, api, producer_controlled_by_app, &output); + + parcel_out.Write(output); + break; + } + case TransactionId::SetPreallocatedBuffer: { + const auto slot = parcel_in.Read(); + const auto buffer = parcel_in.ReadObject(); + + status = SetPreallocatedBuffer(slot, buffer); + break; + } + case TransactionId::DequeueBuffer: { + const auto is_async = parcel_in.Read(); + const auto width = parcel_in.Read(); + const auto height = parcel_in.Read(); + const auto pixel_format = parcel_in.Read(); + const auto usage = parcel_in.Read(); + + s32 slot{}; + Fence fence{}; + + status = DequeueBuffer(&slot, &fence, is_async, width, height, pixel_format, usage); + + parcel_out.Write(slot); + parcel_out.WriteObject(&fence); + break; + } + case TransactionId::RequestBuffer: { + const auto slot = parcel_in.Read(); + + std::shared_ptr buf; + + status = RequestBuffer(slot, &buf); + + parcel_out.WriteObject(buf); + break; + } + case TransactionId::QueueBuffer: { + const auto slot = parcel_in.Read(); + + QueueBufferInput input{parcel_in}; + QueueBufferOutput output; + + status = QueueBuffer(slot, input, &output); + + parcel_out.Write(output); + break; + } + case TransactionId::Query: { + const auto what = parcel_in.Read(); + + s32 value{}; + + status = Query(what, &value); + + parcel_out.Write(value); + break; + } + case TransactionId::CancelBuffer: { + const auto slot = parcel_in.Read(); + const auto fence = parcel_in.ReadFlattened(); + + CancelBuffer(slot, fence); + break; + } + case TransactionId::Disconnect: { + const auto api = parcel_in.Read(); + + status = Disconnect(api); + break; + } + case TransactionId::DetachBuffer: { + const auto slot = parcel_in.Read(); + + status = DetachBuffer(slot); + break; + } + case TransactionId::SetBufferCount: { + const auto buffer_count = parcel_in.Read(); + + status = SetBufferCount(buffer_count); + break; + } + case TransactionId::GetBufferHistory: { + LOG_WARNING(Service_NVFlinger, "(STUBBED) called, transaction=GetBufferHistory"); + break; + } + default: + ASSERT_MSG(false, "Unimplemented"); + } + + parcel_out.Write(status); + + ctx.WriteBuffer(parcel_out.Serialize()); +} + +Kernel::KReadableEvent& BufferQueueProducer::GetNativeHandle() { + return buffer_wait_event->GetReadableEvent(); +} + +} // namespace android diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.h b/src/core/hle/service/nvflinger/buffer_queue_producer.h new file mode 100644 index 000000000..fcb71a794 --- /dev/null +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.h @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project +// Copyright 2014 The Android Open Source Project +// Parts of this implementation were base on: +// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferQueueProducer.h + +#pragma once + +#include +#include +#include + +#include "common/common_funcs.h" +#include "core/hle/service/nvdrv/nvdata.h" +#include "core/hle/service/nvflinger/binder.h" +#include "core/hle/service/nvflinger/buffer_queue_defs.h" +#include "core/hle/service/nvflinger/buffer_slot.h" +#include "core/hle/service/nvflinger/graphic_buffer_producer.h" +#include "core/hle/service/nvflinger/pixel_format.h" +#include "core/hle/service/nvflinger/status.h" +#include "core/hle/service/nvflinger/window.h" + +namespace Kernel { +class KernelCore; +class KEvent; +class KReadableEvent; +class KWritableEvent; +} // namespace Kernel + +namespace Service::KernelHelpers { +class ServiceContext; +} // namespace Service::KernelHelpers + +namespace android { + +class BufferQueueCore; +class IProducerListener; + +class BufferQueueProducer final : public IBinder { +public: + explicit BufferQueueProducer(Service::KernelHelpers::ServiceContext& service_context_, + std::shared_ptr buffer_queue_core_); + ~BufferQueueProducer(); + + void Transact(Kernel::HLERequestContext& ctx, android::TransactionId code, u32 flags) override; + + Kernel::KReadableEvent& GetNativeHandle() override; + +public: + Status RequestBuffer(s32 slot, std::shared_ptr* buf); + Status SetBufferCount(s32 buffer_count); + Status DequeueBuffer(s32* out_slot, android::Fence* out_fence, bool async, u32 width, + u32 height, PixelFormat format, u32 usage); + Status DetachBuffer(s32 slot); + Status DetachNextBuffer(std::shared_ptr* out_buffer, Fence* out_fence); + Status AttachBuffer(s32* outSlot, const std::shared_ptr& buffer); + Status QueueBuffer(s32 slot, const QueueBufferInput& input, QueueBufferOutput* output); + void CancelBuffer(s32 slot, const Fence& fence); + Status Query(NativeWindow what, s32* out_value); + Status Connect(const std::shared_ptr& listener, NativeWindowApi api, + bool producer_controlled_by_app, QueueBufferOutput* output); + + Status Disconnect(NativeWindowApi api); + Status SetPreallocatedBuffer(s32 slot, const std::shared_ptr& buffer); + +private: + BufferQueueProducer(const BufferQueueProducer&) = delete; + + Status WaitForFreeSlotThenRelock(bool async, s32* found, Status* returnFlags) const; + + Kernel::KEvent* buffer_wait_event{}; + Service::KernelHelpers::ServiceContext& service_context; + + std::shared_ptr core; + BufferQueueDefs::SlotsType& slots; + u32 sticky_transform{}; + std::mutex callback_mutex; + s32 next_callback_ticket{}; + s32 current_callback_ticket{}; + std::condition_variable callback_condition; +}; + +} // namespace android -- cgit v1.2.3 From a87812c6a12fbb4b48c0a890ae5a181402743f69 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 19:13:21 -0800 Subject: hle: nvflinger: Add implementation for HosBinderDriverServer service. --- src/core/CMakeLists.txt | 2 ++ .../service/nvflinger/hos_binder_driver_server.cpp | 36 +++++++++++++++++++++ .../service/nvflinger/hos_binder_driver_server.h | 37 ++++++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 src/core/hle/service/nvflinger/hos_binder_driver_server.cpp create mode 100644 src/core/hle/service/nvflinger/hos_binder_driver_server.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 669de3091..ff8adfc55 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -553,6 +553,8 @@ add_library(core STATIC hle/service/nvflinger/consumer_listener.h hle/service/nvflinger/graphic_buffer_producer.cpp hle/service/nvflinger/graphic_buffer_producer.h + hle/service/nvflinger/hos_binder_driver_server.cpp + hle/service/nvflinger/hos_binder_driver_server.h hle/service/nvflinger/nvflinger.cpp hle/service/nvflinger/nvflinger.h hle/service/nvflinger/parcel.h diff --git a/src/core/hle/service/nvflinger/hos_binder_driver_server.cpp b/src/core/hle/service/nvflinger/hos_binder_driver_server.cpp new file mode 100644 index 000000000..0c937d682 --- /dev/null +++ b/src/core/hle/service/nvflinger/hos_binder_driver_server.cpp @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project + +#include + +#include "common/common_types.h" +#include "core/hle/service/nvflinger/hos_binder_driver_server.h" + +namespace Service::NVFlinger { + +HosBinderDriverServer::HosBinderDriverServer(Core::System& system_) + : service_context(system_, "HosBinderDriverServer") {} + +HosBinderDriverServer::~HosBinderDriverServer() {} + +u64 HosBinderDriverServer::RegisterProducer(std::unique_ptr&& binder) { + std::lock_guard lk{lock}; + + last_id++; + + producers[last_id] = std::move(binder); + + return last_id; +} + +android::IBinder* HosBinderDriverServer::TryGetProducer(u64 id) { + std::lock_guard lk{lock}; + + if (auto search = producers.find(id); search != producers.end()) { + return search->second.get(); + } + + return {}; +} + +} // namespace Service::NVFlinger diff --git a/src/core/hle/service/nvflinger/hos_binder_driver_server.h b/src/core/hle/service/nvflinger/hos_binder_driver_server.h new file mode 100644 index 000000000..cbca87fa0 --- /dev/null +++ b/src/core/hle/service/nvflinger/hos_binder_driver_server.h @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project + +#pragma once + +#include +#include +#include + +#include "common/common_types.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/nvflinger/binder.h" + +namespace Core { +class System; +} + +namespace Service::NVFlinger { + +class HosBinderDriverServer final { +public: + explicit HosBinderDriverServer(Core::System& system_); + ~HosBinderDriverServer(); + + u64 RegisterProducer(std::unique_ptr&& binder); + + android::IBinder* TryGetProducer(u64 id); + +private: + KernelHelpers::ServiceContext service_context; + + std::unordered_map> producers; + std::mutex lock; + u64 last_id{}; +}; + +} // namespace Service::NVFlinger -- cgit v1.2.3 From 7f4165fc056261820fe760629e6ac7b1f27de003 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Nov 2021 19:15:51 -0800 Subject: hle: vi: Integrate new NVFlinger and HosBinderDriverServer service. --- src/core/hle/service/nvflinger/nvflinger.cpp | 81 ++- src/core/hle/service/nvflinger/nvflinger.h | 27 +- src/core/hle/service/service.cpp | 6 +- src/core/hle/service/service.h | 4 +- src/core/hle/service/vi/display/vi_display.cpp | 50 +- src/core/hle/service/vi/display/vi_display.h | 29 +- src/core/hle/service/vi/layer/vi_layer.cpp | 6 +- src/core/hle/service/vi/layer/vi_layer.h | 57 +- src/core/hle/service/vi/vi.cpp | 690 +++---------------------- src/core/hle/service/vi/vi.h | 10 +- src/core/hle/service/vi/vi_m.cpp | 9 +- src/core/hle/service/vi/vi_m.h | 7 +- src/core/hle/service/vi/vi_s.cpp | 9 +- src/core/hle/service/vi/vi_s.h | 7 +- src/core/hle/service/vi/vi_u.cpp | 9 +- src/core/hle/service/vi/vi_u.h | 7 +- src/video_core/gpu.h | 1 + 17 files changed, 286 insertions(+), 723 deletions(-) (limited to 'src') diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 01e69de30..e21dc902a 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -1,6 +1,5 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project #include #include @@ -16,8 +15,11 @@ #include "core/hle/kernel/k_readable_event.h" #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" #include "core/hle/service/nvdrv/nvdrv.h" -#include "core/hle/service/nvflinger/buffer_queue.h" +#include "core/hle/service/nvflinger/buffer_item_consumer.h" +#include "core/hle/service/nvflinger/buffer_queue_core.h" +#include "core/hle/service/nvflinger/hos_binder_driver_server.h" #include "core/hle/service/nvflinger/nvflinger.h" +#include "core/hle/service/nvflinger/ui/graphic_buffer.h" #include "core/hle/service/vi/display/vi_display.h" #include "core/hle/service/vi/layer/vi_layer.h" #include "video_core/gpu.h" @@ -53,13 +55,14 @@ void NVFlinger::SplitVSync(std::stop_token stop_token) { } } -NVFlinger::NVFlinger(Core::System& system_) - : system(system_), service_context(system_, "nvflinger") { - displays.emplace_back(0, "Default", service_context, system); - displays.emplace_back(1, "External", service_context, system); - displays.emplace_back(2, "Edid", service_context, system); - displays.emplace_back(3, "Internal", service_context, system); - displays.emplace_back(4, "Null", service_context, system); +NVFlinger::NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_) + : system(system_), service_context(system_, "nvflinger"), + hos_binder_driver_server(hos_binder_driver_server_) { + displays.emplace_back(0, "Default", hos_binder_driver_server, service_context, system); + displays.emplace_back(1, "External", hos_binder_driver_server, service_context, system); + displays.emplace_back(2, "Edid", hos_binder_driver_server, service_context, system); + displays.emplace_back(3, "Internal", hos_binder_driver_server, service_context, system); + displays.emplace_back(4, "Null", hos_binder_driver_server, service_context, system); guard = std::make_shared(); // Schedule the screen composition events @@ -83,12 +86,15 @@ NVFlinger::NVFlinger(Core::System& system_) } NVFlinger::~NVFlinger() { - for (auto& buffer_queue : buffer_queues) { - buffer_queue->Disconnect(); - } if (!system.IsMulticore()) { system.CoreTiming().UnscheduleEvent(composition_event, 0); } + + for (auto& display : displays) { + for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) { + display.GetLayer(layer).Core().NotifyShutdown(); + } + } } void NVFlinger::SetNVDrvInstance(std::shared_ptr instance) { @@ -125,10 +131,8 @@ std::optional NVFlinger::CreateLayer(u64 display_id) { } void NVFlinger::CreateLayerAtId(VI::Display& display, u64 layer_id) { - const u32 buffer_queue_id = next_buffer_queue_id++; - buffer_queues.emplace_back( - std::make_unique(system.Kernel(), buffer_queue_id, layer_id, service_context)); - display.CreateLayer(layer_id, *buffer_queues.back()); + const auto buffer_id = next_buffer_queue_id++; + display.CreateLayer(layer_id, buffer_id); } void NVFlinger::CloseLayer(u64 layer_id) { @@ -147,7 +151,7 @@ std::optional NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) { return std::nullopt; } - return layer->GetBufferQueue().GetId(); + return layer->GetBinderId(); } Kernel::KReadableEvent* NVFlinger::FindVsyncEvent(u64 display_id) { @@ -161,18 +165,6 @@ Kernel::KReadableEvent* NVFlinger::FindVsyncEvent(u64 display_id) { return &display->GetVSyncEvent(); } -BufferQueue* NVFlinger::FindBufferQueue(u32 id) { - const auto lock_guard = Lock(); - const auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(), - [id](const auto& queue) { return queue->GetId() == id; }); - - if (itr == buffer_queues.end()) { - return nullptr; - } - - return itr->get(); -} - VI::Display* NVFlinger::FindDisplay(u64 display_id) { const auto itr = std::find_if(displays.begin(), displays.end(), @@ -246,23 +238,22 @@ void NVFlinger::Compose() { // TODO(Subv): Support more than 1 layer. VI::Layer& layer = display.GetLayer(0); - auto& buffer_queue = layer.GetBufferQueue(); - // Search for a queued buffer and acquire it - auto buffer = buffer_queue.AcquireBuffer(); + android::BufferItem buffer{}; + const auto status = layer.GetConsumer().AcquireBuffer(&buffer, 0, false); - if (!buffer) { + if (status != android::Status::NoError) { continue; } - const auto& igbp_buffer = buffer->get().igbp_buffer; + const auto& igbp_buffer = *buffer.graphic_buffer; if (!system.IsPoweredOn()) { return; // We are likely shutting down } auto& gpu = system.GPU(); - const auto& multi_fence = buffer->get().multi_fence; + const auto& multi_fence = buffer.fence; guard->unlock(); for (u32 fence_id = 0; fence_id < multi_fence.num_fences; fence_id++) { const auto& fence = multi_fence.fences[fence_id]; @@ -278,12 +269,18 @@ void NVFlinger::Compose() { auto nvdisp = nvdrv->GetDevice("/dev/nvdisp_disp0"); ASSERT(nvdisp); - nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.external_format, - igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride, - buffer->get().transform, buffer->get().crop_rect); + Common::Rectangle crop_rect{ + static_cast(buffer.crop.Left()), static_cast(buffer.crop.Top()), + static_cast(buffer.crop.Right()), static_cast(buffer.crop.Bottom())}; + + nvdisp->flip(igbp_buffer.BufferId(), igbp_buffer.Offset(), igbp_buffer.ExternalFormat(), + igbp_buffer.Width(), igbp_buffer.Height(), igbp_buffer.Stride(), + static_cast(buffer.transform), crop_rect); + + swap_interval = buffer.swap_interval; - swap_interval = buffer->get().swap_interval; - buffer_queue.ReleaseBuffer(buffer->get().slot); + auto fence = android::Fence::NoFence(); + layer.GetConsumer().ReleaseBuffer(buffer, fence); } } diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 7935cf773..5112ae136 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -1,6 +1,5 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright 2021 yuzu Emulator Project #pragma once @@ -9,6 +8,7 @@ #include #include #include +#include #include #include "common/common_types.h" @@ -37,13 +37,16 @@ class Display; class Layer; } // namespace Service::VI -namespace Service::NVFlinger { +namespace android { +class BufferQueueCore; +class BufferQueueProducer; +} // namespace android -class BufferQueue; +namespace Service::NVFlinger { class NVFlinger final { public: - explicit NVFlinger(Core::System& system_); + explicit NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_); ~NVFlinger(); /// Sets the NVDrv module instance to use to send buffers to the GPU. @@ -72,15 +75,18 @@ public: /// If an invalid display ID is provided, then nullptr is returned. [[nodiscard]] Kernel::KReadableEvent* FindVsyncEvent(u64 display_id); - /// Obtains a buffer queue identified by the ID. - [[nodiscard]] BufferQueue* FindBufferQueue(u32 id); - /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when /// finished. void Compose(); [[nodiscard]] s64 GetNextTicks() const; +private: + struct Layer { + std::unique_ptr core; + std::unique_ptr producer; + }; + private: [[nodiscard]] std::unique_lock Lock() const { return std::unique_lock{*guard}; @@ -111,7 +117,6 @@ private: std::shared_ptr nvdrv; std::list displays; - std::vector> buffer_queues; /// Id to use for the next layer that is created, this counter is shared among all displays. u64 next_layer_id = 1; @@ -131,6 +136,8 @@ private: std::jthread vsync_thread; KernelHelpers::ServiceContext service_context; + + HosBinderDriverServer& hos_binder_driver_server; }; } // namespace Service::NVFlinger diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index eb1138313..ab3286db9 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -49,6 +49,7 @@ #include "core/hle/service/npns/npns.h" #include "core/hle/service/ns/ns.h" #include "core/hle/service/nvdrv/nvdrv.h" +#include "core/hle/service/nvflinger/hos_binder_driver_server.h" #include "core/hle/service/nvflinger/nvflinger.h" #include "core/hle/service/olsc/olsc.h" #include "core/hle/service/pcie/pcie.h" @@ -230,7 +231,8 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& sessi /// Initialize Services Services::Services(std::shared_ptr& sm, Core::System& system) - : nv_flinger{std::make_unique(system)} { + : hos_binder_driver_server{std::make_unique(system)}, + nv_flinger{std::make_unique(system, *hos_binder_driver_server)} { // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it // here and pass it into the respective InstallInterfaces functions. @@ -290,7 +292,7 @@ Services::Services(std::shared_ptr& sm, Core::System& system SSL::InstallInterfaces(*sm, system); Time::InstallInterfaces(system); USB::InstallInterfaces(*sm, system); - VI::InstallInterfaces(*sm, system, *nv_flinger); + VI::InstallInterfaces(*sm, system, *nv_flinger, *hos_binder_driver_server); WLAN::InstallInterfaces(*sm, system); } diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index c9d6b879d..b9ab2c465 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -33,8 +33,9 @@ class FileSystemController; } namespace NVFlinger { +class HosBinderDriverServer; class NVFlinger; -} +} // namespace NVFlinger namespace SM { class ServiceManager; @@ -236,6 +237,7 @@ public: ~Services(); private: + std::unique_ptr hos_binder_driver_server; std::unique_ptr nv_flinger; }; diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp index b7705c02a..558022511 100644 --- a/src/core/hle/service/vi/display/vi_display.cpp +++ b/src/core/hle/service/vi/display/vi_display.cpp @@ -13,14 +13,34 @@ #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_writable_event.h" #include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/nvflinger/buffer_item_consumer.h" +#include "core/hle/service/nvflinger/buffer_queue_consumer.h" +#include "core/hle/service/nvflinger/buffer_queue_core.h" +#include "core/hle/service/nvflinger/buffer_queue_producer.h" +#include "core/hle/service/nvflinger/hos_binder_driver_server.h" #include "core/hle/service/vi/display/vi_display.h" #include "core/hle/service/vi/layer/vi_layer.h" namespace Service::VI { -Display::Display(u64 id, std::string name_, KernelHelpers::ServiceContext& service_context_, - Core::System& system_) - : display_id{id}, name{std::move(name_)}, service_context{service_context_} { +struct BufferQueue { + std::shared_ptr core; + std::unique_ptr producer; + std::unique_ptr consumer; +}; + +static BufferQueue CreateBufferQueue(KernelHelpers::ServiceContext& service_context) { + auto buffer_queue_core = std::make_shared(); + return {buffer_queue_core, + std::make_unique(service_context, buffer_queue_core), + std::make_unique(buffer_queue_core)}; +} + +Display::Display(u64 id, std::string name_, + NVFlinger::HosBinderDriverServer& hos_binder_driver_server_, + KernelHelpers::ServiceContext& service_context_, Core::System& system_) + : display_id{id}, name{std::move(name_)}, hos_binder_driver_server{hos_binder_driver_server_}, + service_context{service_context_} { vsync_event = service_context.CreateEvent(fmt::format("Display VSync Event {}", id)); } @@ -44,21 +64,29 @@ void Display::SignalVSyncEvent() { vsync_event->GetWritableEvent().Signal(); } -void Display::CreateLayer(u64 layer_id, NVFlinger::BufferQueue& buffer_queue) { - // TODO(Subv): Support more than 1 layer. +void Display::CreateLayer(u64 layer_id, u32 binder_id) { ASSERT_MSG(layers.empty(), "Only one layer is supported per display at the moment"); - layers.emplace_back(std::make_shared(layer_id, buffer_queue)); + auto [core, producer, consumer] = CreateBufferQueue(service_context); + + auto buffer_item_consumer = std::make_shared(std::move(consumer)); + buffer_item_consumer->Connect(false); + + layers.emplace_back(std::make_unique(layer_id, binder_id, *core, *producer, + std::move(buffer_item_consumer))); + + hos_binder_driver_server.RegisterProducer(std::move(producer)); } void Display::CloseLayer(u64 layer_id) { - std::erase_if(layers, [layer_id](const auto& layer) { return layer->GetID() == layer_id; }); + std::erase_if(layers, + [layer_id](const auto& layer) { return layer->GetLayerId() == layer_id; }); } Layer* Display::FindLayer(u64 layer_id) { const auto itr = - std::find_if(layers.begin(), layers.end(), [layer_id](const std::shared_ptr& layer) { - return layer->GetID() == layer_id; + std::find_if(layers.begin(), layers.end(), [layer_id](const std::unique_ptr& layer) { + return layer->GetLayerId() == layer_id; }); if (itr == layers.end()) { @@ -70,8 +98,8 @@ Layer* Display::FindLayer(u64 layer_id) { const Layer* Display::FindLayer(u64 layer_id) const { const auto itr = - std::find_if(layers.begin(), layers.end(), [layer_id](const std::shared_ptr& layer) { - return layer->GetID() == layer_id; + std::find_if(layers.begin(), layers.end(), [layer_id](const std::unique_ptr& layer) { + return layer->GetLayerId() == layer_id; }); if (itr == layers.end()) { diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h index 329f4ba86..9cf324395 100644 --- a/src/core/hle/service/vi/display/vi_display.h +++ b/src/core/hle/service/vi/display/vi_display.h @@ -15,12 +15,17 @@ namespace Kernel { class KEvent; } -namespace Service::NVFlinger { -class BufferQueue; +namespace android { +class BufferQueueProducer; } + namespace Service::KernelHelpers { class ServiceContext; -} // namespace Service::KernelHelpers +} + +namespace Service::NVFlinger { +class HosBinderDriverServer; +} namespace Service::VI { @@ -35,12 +40,13 @@ public: /// Constructs a display with a given unique ID and name. /// /// @param id The unique ID for this display. + /// @param hos_binder_driver_server_ NVFlinger HOSBinderDriver server instance. /// @param service_context_ The ServiceContext for the owning service. /// @param name_ The name for this display. /// @param system_ The global system instance. /// - Display(u64 id, std::string name_, KernelHelpers::ServiceContext& service_context_, - Core::System& system_); + Display(u64 id, std::string name_, NVFlinger::HosBinderDriverServer& hos_binder_driver_server_, + KernelHelpers::ServiceContext& service_context_, Core::System& system_); ~Display(); /// Gets the unique ID assigned to this display. @@ -64,6 +70,10 @@ public: /// Gets a layer for this display based off an index. const Layer& GetLayer(std::size_t index) const; + std::size_t GetNumLayers() const { + return layers.size(); + } + /// Gets the readable vsync event. Kernel::KReadableEvent& GetVSyncEvent(); @@ -72,10 +82,10 @@ public: /// Creates and adds a layer to this display with the given ID. /// - /// @param layer_id The ID to assign to the created layer. - /// @param buffer_queue The buffer queue for the layer instance to use. + /// @param layer_id The ID to assign to the created layer. + /// @param binder_id The ID assigned to the buffer queue. /// - void CreateLayer(u64 layer_id, NVFlinger::BufferQueue& buffer_queue); + void CreateLayer(u64 layer_id, u32 binder_id); /// Closes and removes a layer from this display with the given ID. /// @@ -104,9 +114,10 @@ public: private: u64 display_id; std::string name; + NVFlinger::HosBinderDriverServer& hos_binder_driver_server; KernelHelpers::ServiceContext& service_context; - std::vector> layers; + std::vector> layers; Kernel::KEvent* vsync_event{}; }; diff --git a/src/core/hle/service/vi/layer/vi_layer.cpp b/src/core/hle/service/vi/layer/vi_layer.cpp index 9bc382587..93858e91f 100644 --- a/src/core/hle/service/vi/layer/vi_layer.cpp +++ b/src/core/hle/service/vi/layer/vi_layer.cpp @@ -6,7 +6,11 @@ namespace Service::VI { -Layer::Layer(u64 id, NVFlinger::BufferQueue& queue) : layer_id{id}, buffer_queue{queue} {} +Layer::Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_, + android::BufferQueueProducer& binder_, + std::shared_ptr&& consumer_) + : layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_}, consumer{std::move( + consumer_)} {} Layer::~Layer() = default; diff --git a/src/core/hle/service/vi/layer/vi_layer.h b/src/core/hle/service/vi/layer/vi_layer.h index ebdd85505..079ec4dda 100644 --- a/src/core/hle/service/vi/layer/vi_layer.h +++ b/src/core/hle/service/vi/layer/vi_layer.h @@ -4,11 +4,15 @@ #pragma once +#include + #include "common/common_types.h" -namespace Service::NVFlinger { -class BufferQueue; -} +namespace android { +class BufferItemConsumer; +class BufferQueueCore; +class BufferQueueProducer; +} // namespace android namespace Service::VI { @@ -17,10 +21,13 @@ class Layer { public: /// Constructs a layer with a given ID and buffer queue. /// - /// @param id The ID to assign to this layer. - /// @param queue The buffer queue for this layer to use. + /// @param layer_id_ The ID to assign to this layer. + /// @param binder_id_ The binder ID to assign to this layer. + /// @param binder_ The buffer producer queue for this layer to use. /// - Layer(u64 id, NVFlinger::BufferQueue& queue); + Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_, + android::BufferQueueProducer& binder_, + std::shared_ptr&& consumer_); ~Layer(); Layer(const Layer&) = delete; @@ -30,23 +37,47 @@ public: Layer& operator=(Layer&&) = delete; /// Gets the ID for this layer. - u64 GetID() const { + u64 GetLayerId() const { return layer_id; } + /// Gets the binder ID for this layer. + u32 GetBinderId() const { + return binder_id; + } + /// Gets a reference to the buffer queue this layer is using. - NVFlinger::BufferQueue& GetBufferQueue() { - return buffer_queue; + android::BufferQueueProducer& GetBufferQueue() { + return binder; } /// Gets a const reference to the buffer queue this layer is using. - const NVFlinger::BufferQueue& GetBufferQueue() const { - return buffer_queue; + const android::BufferQueueProducer& GetBufferQueue() const { + return binder; + } + + android::BufferItemConsumer& GetConsumer() { + return *consumer; + } + + const android::BufferItemConsumer& GetConsumer() const { + return *consumer; + } + + android::BufferQueueCore& Core() { + return core; + } + + const android::BufferQueueCore& Core() const { + return core; } private: - u64 layer_id; - NVFlinger::BufferQueue& buffer_queue; + const u64 layer_id; + const u32 binder_id; + android::BufferQueueCore& core; + android::BufferQueueProducer& binder; + std::shared_ptr consumer; }; } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 75ee3e5e4..e49e1ae28 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -22,8 +22,11 @@ #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/service/nvdrv/nvdata.h" -#include "core/hle/service/nvflinger/buffer_queue.h" +#include "core/hle/service/nvflinger/binder.h" +#include "core/hle/service/nvflinger/buffer_queue_producer.h" +#include "core/hle/service/nvflinger/hos_binder_driver_server.h" #include "core/hle/service/nvflinger/nvflinger.h" +#include "core/hle/service/nvflinger/parcel.h" #include "core/hle/service/service.h" #include "core/hle/service/vi/vi.h" #include "core/hle/service/vi/vi_m.h" @@ -57,447 +60,24 @@ struct DisplayInfo { }; static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size"); -class Parcel { +class NativeWindow final { public: - // This default size was chosen arbitrarily. - static constexpr std::size_t DefaultBufferSize = 0x40; - Parcel() : buffer(DefaultBufferSize) {} - explicit Parcel(std::vector data) : buffer(std::move(data)) {} - virtual ~Parcel() = default; - - template - T Read() { - static_assert(std::is_trivially_copyable_v, "T must be trivially copyable."); - ASSERT(read_index + sizeof(T) <= buffer.size()); - - T val; - std::memcpy(&val, buffer.data() + read_index, sizeof(T)); - read_index += sizeof(T); - read_index = Common::AlignUp(read_index, 4); - return val; - } - - template - T ReadUnaligned() { - static_assert(std::is_trivially_copyable_v, "T must be trivially copyable."); - ASSERT(read_index + sizeof(T) <= buffer.size()); - - T val; - std::memcpy(&val, buffer.data() + read_index, sizeof(T)); - read_index += sizeof(T); - return val; - } - - std::vector ReadBlock(std::size_t length) { - ASSERT(read_index + length <= buffer.size()); - const u8* const begin = buffer.data() + read_index; - const u8* const end = begin + length; - std::vector data(begin, end); - read_index += length; - read_index = Common::AlignUp(read_index, 4); - return data; - } - - std::u16string ReadInterfaceToken() { - [[maybe_unused]] const u32 unknown = Read(); - const u32 length = Read(); - - std::u16string token{}; - - for (u32 ch = 0; ch < length + 1; ++ch) { - token.push_back(ReadUnaligned()); - } - - read_index = Common::AlignUp(read_index, 4); - - return token; - } - - template - void Write(const T& val) { - static_assert(std::is_trivially_copyable_v, "T must be trivially copyable."); - - if (buffer.size() < write_index + sizeof(T)) { - buffer.resize(buffer.size() + sizeof(T) + DefaultBufferSize); - } - - std::memcpy(buffer.data() + write_index, &val, sizeof(T)); - write_index += sizeof(T); - write_index = Common::AlignUp(write_index, 4); - } - - template - void WriteObject(const T& val) { - static_assert(std::is_trivially_copyable_v, "T must be trivially copyable."); - - const u32_le size = static_cast(sizeof(val)); - Write(size); - // TODO(Subv): Support file descriptors. - Write(0); // Fd count. - Write(val); - } - - void Deserialize() { - ASSERT(buffer.size() > sizeof(Header)); - - Header header{}; - std::memcpy(&header, buffer.data(), sizeof(Header)); - - read_index = header.data_offset; - DeserializeData(); - } - - std::vector Serialize() { - ASSERT(read_index == 0); - write_index = sizeof(Header); - - SerializeData(); - - Header header{}; - header.data_size = static_cast(write_index - sizeof(Header)); - header.data_offset = sizeof(Header); - header.objects_size = 4; - header.objects_offset = static_cast(sizeof(Header) + header.data_size); - std::memcpy(buffer.data(), &header, sizeof(Header)); - - return buffer; - } - -protected: - virtual void SerializeData() {} - - virtual void DeserializeData() {} - -private: - struct Header { - u32_le data_size; - u32_le data_offset; - u32_le objects_size; - u32_le objects_offset; - }; - static_assert(sizeof(Header) == 16, "ParcelHeader has wrong size"); - - std::vector buffer; - std::size_t read_index = 0; - std::size_t write_index = 0; -}; - -class NativeWindow : public Parcel { -public: - explicit NativeWindow(u32 id) { - data.id = id; - } - ~NativeWindow() override = default; - -protected: - void SerializeData() override { - Write(data); - } - -private: - struct Data { - u32_le magic = 2; - u32_le process_id = 1; - u32_le id; - INSERT_PADDING_WORDS(3); - std::array dispdrv = {'d', 'i', 's', 'p', 'd', 'r', 'v', '\0'}; - INSERT_PADDING_WORDS(2); - }; - static_assert(sizeof(Data) == 0x28, "ParcelData has wrong size"); - - Data data{}; -}; - -class IGBPConnectRequestParcel : public Parcel { -public: - explicit IGBPConnectRequestParcel(std::vector buffer_) : Parcel(std::move(buffer_)) { - Deserialize(); - } - - void DeserializeData() override { - [[maybe_unused]] const std::u16string token = ReadInterfaceToken(); - data = Read(); - } - - struct Data { - u32_le unk; - u32_le api; - u32_le producer_controlled_by_app; - }; - - Data data; -}; - -class IGBPConnectResponseParcel : public Parcel { -public: - explicit IGBPConnectResponseParcel(u32 width, u32 height) { - data.width = width; - data.height = height; - } - ~IGBPConnectResponseParcel() override = default; - -protected: - void SerializeData() override { - Write(data); - } - -private: - struct Data { - u32_le width; - u32_le height; - u32_le transform_hint; - u32_le num_pending_buffers; - u32_le status; - }; - static_assert(sizeof(Data) == 20, "ParcelData has wrong size"); - - Data data{}; -}; - -/// Represents a parcel containing one int '0' as its data -/// Used by DetachBuffer and Disconnect -class IGBPEmptyResponseParcel : public Parcel { -protected: - void SerializeData() override { - Write(data); - } - -private: - struct Data { - u32_le unk_0{}; - }; - - Data data{}; -}; - -class IGBPSetPreallocatedBufferRequestParcel : public Parcel { -public: - explicit IGBPSetPreallocatedBufferRequestParcel(std::vector buffer_) - : Parcel(std::move(buffer_)) { - Deserialize(); - } - - void DeserializeData() override { - [[maybe_unused]] const std::u16string token = ReadInterfaceToken(); - data = Read(); - if (data.contains_object != 0) { - buffer_container = Read(); - } - } - - struct Data { - u32_le slot; - u32_le contains_object; - }; - - struct BufferContainer { - u32_le graphic_buffer_length; - INSERT_PADDING_WORDS(1); - NVFlinger::IGBPBuffer buffer{}; - }; - - Data data{}; - BufferContainer buffer_container{}; -}; - -class IGBPSetPreallocatedBufferResponseParcel : public Parcel { -protected: - void SerializeData() override { - // TODO(Subv): Find out what this means - Write(0); - } -}; - -class IGBPCancelBufferRequestParcel : public Parcel { -public: - explicit IGBPCancelBufferRequestParcel(std::vector buffer_) : Parcel(std::move(buffer_)) { - Deserialize(); - } - - void DeserializeData() override { - [[maybe_unused]] const std::u16string token = ReadInterfaceToken(); - data = Read(); - } - - struct Data { - u32_le slot; - Service::Nvidia::MultiFence multi_fence; - }; - - Data data; -}; - -class IGBPCancelBufferResponseParcel : public Parcel { -protected: - void SerializeData() override { - Write(0); // Success - } -}; - -class IGBPDequeueBufferRequestParcel : public Parcel { -public: - explicit IGBPDequeueBufferRequestParcel(std::vector buffer_) : Parcel(std::move(buffer_)) { - Deserialize(); - } - - void DeserializeData() override { - [[maybe_unused]] const std::u16string token = ReadInterfaceToken(); - data = Read(); - } - - struct Data { - u32_le pixel_format; - u32_le width; - u32_le height; - u32_le get_frame_timestamps; - u32_le usage; - }; - - Data data; -}; - -class IGBPDequeueBufferResponseParcel : public Parcel { -public: - explicit IGBPDequeueBufferResponseParcel(u32 slot_, Nvidia::MultiFence& multi_fence_) - : slot(slot_), multi_fence(multi_fence_) {} - -protected: - void SerializeData() override { - Write(slot); - Write(1); - WriteObject(multi_fence); - Write(0); - } - - u32_le slot; - Service::Nvidia::MultiFence multi_fence; -}; - -class IGBPRequestBufferRequestParcel : public Parcel { -public: - explicit IGBPRequestBufferRequestParcel(std::vector buffer_) : Parcel(std::move(buffer_)) { - Deserialize(); - } - - void DeserializeData() override { - [[maybe_unused]] const std::u16string token = ReadInterfaceToken(); - slot = Read(); - } - - u32_le slot; -}; - -class IGBPRequestBufferResponseParcel : public Parcel { -public: - explicit IGBPRequestBufferResponseParcel(NVFlinger::IGBPBuffer buffer_) : buffer(buffer_) {} - ~IGBPRequestBufferResponseParcel() override = default; - -protected: - void SerializeData() override { - // TODO(Subv): Figure out what this value means, writing non-zero here will make libnx - // try to read an IGBPBuffer object from the parcel. - Write(1); - WriteObject(buffer); - Write(0); - } - - NVFlinger::IGBPBuffer buffer; -}; - -class IGBPQueueBufferRequestParcel : public Parcel { -public: - explicit IGBPQueueBufferRequestParcel(std::vector buffer_) : Parcel(std::move(buffer_)) { - Deserialize(); - } - - void DeserializeData() override { - [[maybe_unused]] const std::u16string token = ReadInterfaceToken(); - data = Read(); - } - - struct Data { - u32_le slot; - INSERT_PADDING_WORDS(3); - u32_le timestamp; - s32_le is_auto_timestamp; - s32_le crop_top; - s32_le crop_left; - s32_le crop_right; - s32_le crop_bottom; - s32_le scaling_mode; - NVFlinger::BufferQueue::BufferTransformFlags transform; - u32_le sticky_transform; - INSERT_PADDING_WORDS(1); - u32_le swap_interval; - Service::Nvidia::MultiFence multi_fence; - - Common::Rectangle GetCropRect() const { - return {crop_left, crop_top, crop_right, crop_bottom}; - } - }; - static_assert(sizeof(Data) == 96, "ParcelData has wrong size"); - - Data data; -}; - -class IGBPQueueBufferResponseParcel : public Parcel { -public: - explicit IGBPQueueBufferResponseParcel(u32 width, u32 height) { - data.width = width; - data.height = height; - } - ~IGBPQueueBufferResponseParcel() override = default; - -protected: - void SerializeData() override { - Write(data); - } - -private: - struct Data { - u32_le width; - u32_le height; - u32_le transform_hint; - u32_le num_pending_buffers; - u32_le status; - }; - static_assert(sizeof(Data) == 20, "ParcelData has wrong size"); - - Data data{}; -}; - -class IGBPQueryRequestParcel : public Parcel { -public: - explicit IGBPQueryRequestParcel(std::vector buffer_) : Parcel(std::move(buffer_)) { - Deserialize(); - } - - void DeserializeData() override { - [[maybe_unused]] const std::u16string token = ReadInterfaceToken(); - type = Read(); - } - - u32 type; -}; - -class IGBPQueryResponseParcel : public Parcel { -public: - explicit IGBPQueryResponseParcel(u32 value_) : value{value_} {} - ~IGBPQueryResponseParcel() override = default; - -protected: - void SerializeData() override { - Write(value); - } + constexpr explicit NativeWindow(u32 id_) : id{id_} {} private: - u32_le value; + const u32 magic = 2; + const u32 process_id = 1; + const u32 id; + const INSERT_PADDING_WORDS(3); + const std::array dispdrv = {'d', 'i', 's', 'p', 'd', 'r', 'v', '\0'}; + const INSERT_PADDING_WORDS(2); }; +static_assert(sizeof(NativeWindow) == 0x28, "ParcelData has wrong size"); class IHOSBinderDriver final : public ServiceFramework { public: - explicit IHOSBinderDriver(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_) - : ServiceFramework{system_, "IHOSBinderDriver"}, nv_flinger(nv_flinger_) { + explicit IHOSBinderDriver(Core::System& system_, NVFlinger::HosBinderDriverServer& server_) + : ServiceFramework{system_, "IHOSBinderDriver"}, server(server_) { static const FunctionInfo functions[] = { {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"}, {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"}, @@ -508,147 +88,16 @@ public: } private: - enum class TransactionId { - RequestBuffer = 1, - SetBufferCount = 2, - DequeueBuffer = 3, - DetachBuffer = 4, - DetachNextBuffer = 5, - AttachBuffer = 6, - QueueBuffer = 7, - CancelBuffer = 8, - Query = 9, - Connect = 10, - Disconnect = 11, - - AllocateBuffers = 13, - SetPreallocatedBuffer = 14, - - GetBufferHistory = 17 - }; - void TransactParcel(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const u32 id = rp.Pop(); - const auto transaction = static_cast(rp.Pop()); + const auto transaction = static_cast(rp.Pop()); const u32 flags = rp.Pop(); LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id, transaction, flags); - auto& buffer_queue = *nv_flinger.FindBufferQueue(id); - - switch (transaction) { - case TransactionId::Connect: { - IGBPConnectRequestParcel request{ctx.ReadBuffer()}; - IGBPConnectResponseParcel response{static_cast(DisplayResolution::UndockedWidth), - static_cast(DisplayResolution::UndockedHeight)}; - - buffer_queue.Connect(); - - ctx.WriteBuffer(response.Serialize()); - break; - } - case TransactionId::SetPreallocatedBuffer: { - IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()}; - - buffer_queue.SetPreallocatedBuffer(request.data.slot, request.buffer_container.buffer); - - IGBPSetPreallocatedBufferResponseParcel response{}; - ctx.WriteBuffer(response.Serialize()); - break; - } - case TransactionId::DequeueBuffer: { - IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()}; - const u32 width{request.data.width}; - const u32 height{request.data.height}; - - do { - if (auto result = buffer_queue.DequeueBuffer(width, height); result) { - // Buffer is available - IGBPDequeueBufferResponseParcel response{result->first, *result->second}; - ctx.WriteBuffer(response.Serialize()); - break; - } - } while (buffer_queue.IsConnected()); - - break; - } - case TransactionId::RequestBuffer: { - IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()}; - - auto& buffer = buffer_queue.RequestBuffer(request.slot); - IGBPRequestBufferResponseParcel response{buffer}; - ctx.WriteBuffer(response.Serialize()); - - break; - } - case TransactionId::QueueBuffer: { - IGBPQueueBufferRequestParcel request{ctx.ReadBuffer()}; - - buffer_queue.QueueBuffer(request.data.slot, request.data.transform, - request.data.GetCropRect(), request.data.swap_interval, - request.data.multi_fence); - - IGBPQueueBufferResponseParcel response{1280, 720}; - ctx.WriteBuffer(response.Serialize()); - break; - } - case TransactionId::Query: { - IGBPQueryRequestParcel request{ctx.ReadBuffer()}; - - const u32 value = - buffer_queue.Query(static_cast(request.type)); - - IGBPQueryResponseParcel response{value}; - ctx.WriteBuffer(response.Serialize()); - break; - } - case TransactionId::CancelBuffer: { - IGBPCancelBufferRequestParcel request{ctx.ReadBuffer()}; - - buffer_queue.CancelBuffer(request.data.slot, request.data.multi_fence); - - IGBPCancelBufferResponseParcel response{}; - ctx.WriteBuffer(response.Serialize()); - break; - } - case TransactionId::Disconnect: { - LOG_WARNING(Service_VI, "(STUBBED) called, transaction=Disconnect"); - const auto buffer = ctx.ReadBuffer(); - - buffer_queue.Disconnect(); - - IGBPEmptyResponseParcel response{}; - ctx.WriteBuffer(response.Serialize()); - break; - } - case TransactionId::DetachBuffer: { - const auto buffer = ctx.ReadBuffer(); - - IGBPEmptyResponseParcel response{}; - ctx.WriteBuffer(response.Serialize()); - break; - } - case TransactionId::SetBufferCount: { - LOG_WARNING(Service_VI, "(STUBBED) called, transaction=SetBufferCount"); - [[maybe_unused]] const auto buffer = ctx.ReadBuffer(); - - IGBPEmptyResponseParcel response{}; - ctx.WriteBuffer(response.Serialize()); - break; - } - case TransactionId::GetBufferHistory: { - LOG_WARNING(Service_VI, "(STUBBED) called, transaction=GetBufferHistory"); - [[maybe_unused]] const auto buffer = ctx.ReadBuffer(); - - IGBPEmptyResponseParcel response{}; - ctx.WriteBuffer(response.Serialize()); - break; - } - default: - ASSERT_MSG(false, "Unimplemented"); - } + server.TryGetProducer(id)->Transact(ctx, transaction, flags); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -674,13 +123,13 @@ private: LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown); - // TODO(Subv): Find out what this actually is. IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); - rb.PushCopyObjects(nv_flinger.FindBufferQueue(id)->GetBufferWaitEvent()); + rb.PushCopyObjects(server.TryGetProducer(id)->GetNativeHandle()); } - NVFlinger::NVFlinger& nv_flinger; +private: + NVFlinger::HosBinderDriverServer& server; }; class ISystemDisplayService final : public ServiceFramework { @@ -937,7 +386,40 @@ private: class IApplicationDisplayService final : public ServiceFramework { public: - explicit IApplicationDisplayService(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_); + IApplicationDisplayService(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_, + NVFlinger::HosBinderDriverServer& hos_binder_driver_server_) + : ServiceFramework{system_, "IApplicationDisplayService"}, nv_flinger{nv_flinger_}, + hos_binder_driver_server{hos_binder_driver_server_} { + + static const FunctionInfo functions[] = { + {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"}, + {101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"}, + {102, &IApplicationDisplayService::GetManagerDisplayService, + "GetManagerDisplayService"}, + {103, &IApplicationDisplayService::GetIndirectDisplayTransactionService, + "GetIndirectDisplayTransactionService"}, + {1000, &IApplicationDisplayService::ListDisplays, "ListDisplays"}, + {1010, &IApplicationDisplayService::OpenDisplay, "OpenDisplay"}, + {1011, &IApplicationDisplayService::OpenDefaultDisplay, "OpenDefaultDisplay"}, + {1020, &IApplicationDisplayService::CloseDisplay, "CloseDisplay"}, + {1101, &IApplicationDisplayService::SetDisplayEnabled, "SetDisplayEnabled"}, + {1102, &IApplicationDisplayService::GetDisplayResolution, "GetDisplayResolution"}, + {2020, &IApplicationDisplayService::OpenLayer, "OpenLayer"}, + {2021, &IApplicationDisplayService::CloseLayer, "CloseLayer"}, + {2030, &IApplicationDisplayService::CreateStrayLayer, "CreateStrayLayer"}, + {2031, &IApplicationDisplayService::DestroyStrayLayer, "DestroyStrayLayer"}, + {2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"}, + {2102, &IApplicationDisplayService::ConvertScalingMode, "ConvertScalingMode"}, + {2450, &IApplicationDisplayService::GetIndirectLayerImageMap, + "GetIndirectLayerImageMap"}, + {2451, nullptr, "GetIndirectLayerImageCropMap"}, + {2460, &IApplicationDisplayService::GetIndirectLayerImageRequiredMemoryInfo, + "GetIndirectLayerImageRequiredMemoryInfo"}, + {5202, &IApplicationDisplayService::GetDisplayVsyncEvent, "GetDisplayVsyncEvent"}, + {5203, nullptr, "GetDisplayVsyncEventForDebug"}, + }; + RegisterHandlers(functions); + } private: enum class ConvertedScaleMode : u64 { @@ -961,7 +443,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system, nv_flinger); + rb.PushIpcInterface(system, hos_binder_driver_server); } void GetSystemDisplayService(Kernel::HLERequestContext& ctx) { @@ -985,7 +467,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system, nv_flinger); + rb.PushIpcInterface(system, hos_binder_driver_server); } void OpenDisplay(Kernel::HLERequestContext& ctx) { @@ -1089,7 +571,7 @@ private: void ListDisplays(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_VI, "(STUBBED) called"); - DisplayInfo display_info; + const DisplayInfo display_info; ctx.WriteBuffer(&display_info, sizeof(DisplayInfo)); IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); @@ -1124,8 +606,8 @@ private: return; } - NativeWindow native_window{*buffer_queue_id}; - const auto buffer_size = ctx.WriteBuffer(native_window.Serialize()); + const auto parcel = android::Parcel{NativeWindow{*buffer_queue_id}}; + const auto buffer_size = ctx.WriteBuffer(parcel.Serialize()); IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); @@ -1170,8 +652,8 @@ private: return; } - NativeWindow native_window{*buffer_queue_id}; - const auto buffer_size = ctx.WriteBuffer(native_window.Serialize()); + const auto parcel = android::Parcel{NativeWindow{*buffer_queue_id}}; + const auto buffer_size = ctx.WriteBuffer(parcel.Serialize()); IPC::ResponseBuilder rb{ctx, 6}; rb.Push(ResultSuccess); @@ -1287,39 +769,9 @@ private: } NVFlinger::NVFlinger& nv_flinger; + NVFlinger::HosBinderDriverServer& hos_binder_driver_server; }; -IApplicationDisplayService::IApplicationDisplayService(Core::System& system_, - NVFlinger::NVFlinger& nv_flinger_) - : ServiceFramework{system_, "IApplicationDisplayService"}, nv_flinger{nv_flinger_} { - static const FunctionInfo functions[] = { - {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"}, - {101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"}, - {102, &IApplicationDisplayService::GetManagerDisplayService, "GetManagerDisplayService"}, - {103, &IApplicationDisplayService::GetIndirectDisplayTransactionService, - "GetIndirectDisplayTransactionService"}, - {1000, &IApplicationDisplayService::ListDisplays, "ListDisplays"}, - {1010, &IApplicationDisplayService::OpenDisplay, "OpenDisplay"}, - {1011, &IApplicationDisplayService::OpenDefaultDisplay, "OpenDefaultDisplay"}, - {1020, &IApplicationDisplayService::CloseDisplay, "CloseDisplay"}, - {1101, &IApplicationDisplayService::SetDisplayEnabled, "SetDisplayEnabled"}, - {1102, &IApplicationDisplayService::GetDisplayResolution, "GetDisplayResolution"}, - {2020, &IApplicationDisplayService::OpenLayer, "OpenLayer"}, - {2021, &IApplicationDisplayService::CloseLayer, "CloseLayer"}, - {2030, &IApplicationDisplayService::CreateStrayLayer, "CreateStrayLayer"}, - {2031, &IApplicationDisplayService::DestroyStrayLayer, "DestroyStrayLayer"}, - {2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"}, - {2102, &IApplicationDisplayService::ConvertScalingMode, "ConvertScalingMode"}, - {2450, &IApplicationDisplayService::GetIndirectLayerImageMap, "GetIndirectLayerImageMap"}, - {2451, nullptr, "GetIndirectLayerImageCropMap"}, - {2460, &IApplicationDisplayService::GetIndirectLayerImageRequiredMemoryInfo, - "GetIndirectLayerImageRequiredMemoryInfo"}, - {5202, &IApplicationDisplayService::GetDisplayVsyncEvent, "GetDisplayVsyncEvent"}, - {5203, nullptr, "GetDisplayVsyncEventForDebug"}, - }; - RegisterHandlers(functions); -} - static bool IsValidServiceAccess(Permission permission, Policy policy) { if (permission == Permission::User) { return policy == Policy::User; @@ -1333,7 +785,9 @@ static bool IsValidServiceAccess(Permission permission, Policy policy) { } void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System& system, - NVFlinger::NVFlinger& nv_flinger, Permission permission) { + NVFlinger::NVFlinger& nv_flinger, + NVFlinger::HosBinderDriverServer& hos_binder_driver_server, + Permission permission) { IPC::RequestParser rp{ctx}; const auto policy = rp.PopEnum(); @@ -1346,14 +800,18 @@ void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System& IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system, nv_flinger); + rb.PushIpcInterface(system, nv_flinger, hos_binder_driver_server); } void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system, - NVFlinger::NVFlinger& nv_flinger) { - std::make_shared(system, nv_flinger)->InstallAsService(service_manager); - std::make_shared(system, nv_flinger)->InstallAsService(service_manager); - std::make_shared(system, nv_flinger)->InstallAsService(service_manager); + NVFlinger::NVFlinger& nv_flinger, + NVFlinger::HosBinderDriverServer& hos_binder_driver_server) { + std::make_shared(system, nv_flinger, hos_binder_driver_server) + ->InstallAsService(service_manager); + std::make_shared(system, nv_flinger, hos_binder_driver_server) + ->InstallAsService(service_manager); + std::make_shared(system, nv_flinger, hos_binder_driver_server) + ->InstallAsService(service_manager); } } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h index 2fd7f8e61..d68f2646b 100644 --- a/src/core/hle/service/vi/vi.h +++ b/src/core/hle/service/vi/vi.h @@ -15,8 +15,9 @@ class HLERequestContext; } namespace Service::NVFlinger { +class HosBinderDriverServer; class NVFlinger; -} +} // namespace Service::NVFlinger namespace Service::SM { class ServiceManager; @@ -47,11 +48,14 @@ enum class Policy { namespace detail { void GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System& system, - NVFlinger::NVFlinger& nv_flinger, Permission permission); + NVFlinger::NVFlinger& nv_flinger, + NVFlinger::HosBinderDriverServer& hos_binder_driver_server, + Permission permission); } // namespace detail /// Registers all VI services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system, - NVFlinger::NVFlinger& nv_flinger); + NVFlinger::NVFlinger& nv_flinger, + NVFlinger::HosBinderDriverServer& hos_binder_driver_server); } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_m.cpp b/src/core/hle/service/vi/vi_m.cpp index 87db1c416..be0255f3d 100644 --- a/src/core/hle/service/vi/vi_m.cpp +++ b/src/core/hle/service/vi/vi_m.cpp @@ -8,8 +8,10 @@ namespace Service::VI { -VI_M::VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_) - : ServiceFramework{system_, "vi:m"}, nv_flinger{nv_flinger_} { +VI_M::VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_, + NVFlinger::HosBinderDriverServer& hos_binder_driver_server_) + : ServiceFramework{system_, "vi:m"}, nv_flinger{nv_flinger_}, hos_binder_driver_server{ + hos_binder_driver_server_} { static const FunctionInfo functions[] = { {2, &VI_M::GetDisplayService, "GetDisplayService"}, {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, @@ -22,7 +24,8 @@ VI_M::~VI_M() = default; void VI_M::GetDisplayService(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_VI, "called"); - detail::GetDisplayServiceImpl(ctx, system, nv_flinger, Permission::Manager); + detail::GetDisplayServiceImpl(ctx, system, nv_flinger, hos_binder_driver_server, + Permission::Manager); } } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_m.h b/src/core/hle/service/vi/vi_m.h index d79c41beb..efbd34e09 100644 --- a/src/core/hle/service/vi/vi_m.h +++ b/src/core/hle/service/vi/vi_m.h @@ -15,20 +15,23 @@ class HLERequestContext; } namespace Service::NVFlinger { +class HosBinderDriverServer; class NVFlinger; -} +} // namespace Service::NVFlinger namespace Service::VI { class VI_M final : public ServiceFramework { public: - explicit VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_); + explicit VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_, + NVFlinger::HosBinderDriverServer& hos_binder_driver_server_); ~VI_M() override; private: void GetDisplayService(Kernel::HLERequestContext& ctx); NVFlinger::NVFlinger& nv_flinger; + NVFlinger::HosBinderDriverServer& hos_binder_driver_server; }; } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_s.cpp b/src/core/hle/service/vi/vi_s.cpp index 5cd22f7df..7996a6811 100644 --- a/src/core/hle/service/vi/vi_s.cpp +++ b/src/core/hle/service/vi/vi_s.cpp @@ -8,8 +8,10 @@ namespace Service::VI { -VI_S::VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_) - : ServiceFramework{system_, "vi:s"}, nv_flinger{nv_flinger_} { +VI_S::VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_, + NVFlinger::HosBinderDriverServer& hos_binder_driver_server_) + : ServiceFramework{system_, "vi:s"}, nv_flinger{nv_flinger_}, hos_binder_driver_server{ + hos_binder_driver_server_} { static const FunctionInfo functions[] = { {1, &VI_S::GetDisplayService, "GetDisplayService"}, {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, @@ -22,7 +24,8 @@ VI_S::~VI_S() = default; void VI_S::GetDisplayService(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_VI, "called"); - detail::GetDisplayServiceImpl(ctx, system, nv_flinger, Permission::System); + detail::GetDisplayServiceImpl(ctx, system, nv_flinger, hos_binder_driver_server, + Permission::System); } } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_s.h b/src/core/hle/service/vi/vi_s.h index 5f1f8f290..3812c5061 100644 --- a/src/core/hle/service/vi/vi_s.h +++ b/src/core/hle/service/vi/vi_s.h @@ -15,20 +15,23 @@ class HLERequestContext; } namespace Service::NVFlinger { +class HosBinderDriverServer; class NVFlinger; -} +} // namespace Service::NVFlinger namespace Service::VI { class VI_S final : public ServiceFramework { public: - explicit VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_); + explicit VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_, + NVFlinger::HosBinderDriverServer& hos_binder_driver_server_); ~VI_S() override; private: void GetDisplayService(Kernel::HLERequestContext& ctx); NVFlinger::NVFlinger& nv_flinger; + NVFlinger::HosBinderDriverServer& hos_binder_driver_server; }; } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_u.cpp b/src/core/hle/service/vi/vi_u.cpp index 0079d51f0..57c888313 100644 --- a/src/core/hle/service/vi/vi_u.cpp +++ b/src/core/hle/service/vi/vi_u.cpp @@ -8,8 +8,10 @@ namespace Service::VI { -VI_U::VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_) - : ServiceFramework{system_, "vi:u"}, nv_flinger{nv_flinger_} { +VI_U::VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_, + NVFlinger::HosBinderDriverServer& hos_binder_driver_server_) + : ServiceFramework{system_, "vi:u"}, nv_flinger{nv_flinger_}, hos_binder_driver_server{ + hos_binder_driver_server_} { static const FunctionInfo functions[] = { {0, &VI_U::GetDisplayService, "GetDisplayService"}, {1, nullptr, "GetDisplayServiceWithProxyNameExchange"}, @@ -22,7 +24,8 @@ VI_U::~VI_U() = default; void VI_U::GetDisplayService(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_VI, "called"); - detail::GetDisplayServiceImpl(ctx, system, nv_flinger, Permission::User); + detail::GetDisplayServiceImpl(ctx, system, nv_flinger, hos_binder_driver_server, + Permission::User); } } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi_u.h b/src/core/hle/service/vi/vi_u.h index 8e3885c73..b08e56576 100644 --- a/src/core/hle/service/vi/vi_u.h +++ b/src/core/hle/service/vi/vi_u.h @@ -15,20 +15,23 @@ class HLERequestContext; } namespace Service::NVFlinger { +class HosBinderDriverServer; class NVFlinger; -} +} // namespace Service::NVFlinger namespace Service::VI { class VI_U final : public ServiceFramework { public: - explicit VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_); + explicit VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_, + NVFlinger::HosBinderDriverServer& hos_binder_driver_server_); ~VI_U() override; private: void GetDisplayService(Kernel::HLERequestContext& ctx); NVFlinger::NVFlinger& nv_flinger; + NVFlinger::HosBinderDriverServer& hos_binder_driver_server; }; } // namespace Service::VI diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 26b8ea233..97c029140 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -8,6 +8,7 @@ #include "common/bit_field.h" #include "common/common_types.h" +#include "core/hle/service/nvdrv/nvdata.h" #include "video_core/cdma_pusher.h" #include "video_core/framebuffer_config.h" -- cgit v1.2.3 From 5849c9a4cdcb3cb18c2b63c390365d2a00ddb916 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 12 Nov 2021 23:54:18 -0800 Subject: hle: nvflinger: BufferQueueProducer: Handle SetPreallocatedBuffer with empty buffer. - Used by Naruto Ultimate Ninja Storm. --- .../hle/service/nvflinger/buffer_queue_producer.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp index d48e96b14..a347f8b3b 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp @@ -793,8 +793,6 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot, const std::shared_ptr& buffer) { LOG_DEBUG(Service_NVFlinger, "slot {}", slot); - UNIMPLEMENTED_IF_MSG(!buffer, "buffer must be valid!"); - if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { return Status::BadValue; } @@ -802,13 +800,18 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot, BufferQueueCore::AutoLock lock(core); slots[slot] = {}; - slots[slot].is_preallocated = true; slots[slot].graphic_buffer = buffer; - core->override_max_buffer_count = core->GetPreallocatedBufferCountLocked(); - core->default_width = buffer->Width(); - core->default_height = buffer->Height(); - core->default_buffer_format = buffer->Format(); + // Most games preallocate a buffer and pass a valid buffer here. However, it is possible for + // this to be called with an empty buffer, Naruto Ultimate Ninja Storm is a game that does this. + if (buffer) { + slots[slot].is_preallocated = true; + + core->override_max_buffer_count = core->GetPreallocatedBufferCountLocked(); + core->default_width = buffer->Width(); + core->default_height = buffer->Height(); + core->default_buffer_format = buffer->Format(); + } core->SignalDequeueCondition(); buffer_wait_event->GetWritableEvent().Signal(); -- cgit v1.2.3 From ca12a77670d1463c2257bcdd829bb9bc56f1461b Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 19 Mar 2022 21:51:16 -0700 Subject: hle: nvflinger: Migrate android namespace -> Service::android. --- src/core/hle/service/nvflinger/binder.h | 4 ++-- src/core/hle/service/nvflinger/buffer_item.h | 4 ++-- src/core/hle/service/nvflinger/buffer_item_consumer.cpp | 4 ++-- src/core/hle/service/nvflinger/buffer_item_consumer.h | 4 ++-- src/core/hle/service/nvflinger/buffer_queue_consumer.cpp | 4 ++-- src/core/hle/service/nvflinger/buffer_queue_consumer.h | 4 ++-- src/core/hle/service/nvflinger/buffer_queue_core.cpp | 9 +++------ src/core/hle/service/nvflinger/buffer_queue_core.h | 4 ++-- src/core/hle/service/nvflinger/buffer_queue_defs.h | 4 ++-- src/core/hle/service/nvflinger/buffer_queue_producer.cpp | 4 ++-- src/core/hle/service/nvflinger/buffer_queue_producer.h | 4 ++-- src/core/hle/service/nvflinger/buffer_slot.h | 4 ++-- src/core/hle/service/nvflinger/buffer_transform_flags.h | 4 ++-- src/core/hle/service/nvflinger/consumer_base.cpp | 4 ++-- src/core/hle/service/nvflinger/consumer_base.h | 4 ++-- src/core/hle/service/nvflinger/consumer_listener.h | 4 ++-- src/core/hle/service/nvflinger/graphic_buffer_producer.cpp | 4 ++-- src/core/hle/service/nvflinger/graphic_buffer_producer.h | 4 ++-- src/core/hle/service/nvflinger/nvflinger.h | 4 ++-- src/core/hle/service/nvflinger/parcel.h | 4 ++-- src/core/hle/service/nvflinger/pixel_format.h | 4 ++-- src/core/hle/service/nvflinger/producer_listener.h | 4 ++-- src/core/hle/service/nvflinger/status.h | 4 ++-- src/core/hle/service/nvflinger/ui/fence.h | 4 ++-- src/core/hle/service/nvflinger/ui/graphic_buffer.h | 4 ++-- src/core/hle/service/nvflinger/ui/rect.h | 4 ++-- src/core/hle/service/nvflinger/window.h | 4 ++-- src/core/hle/service/vi/display/vi_display.h | 2 +- src/core/hle/service/vi/layer/vi_layer.h | 4 ++-- src/video_core/framebuffer_config.h | 4 ++-- src/video_core/renderer_opengl/renderer_opengl.cpp | 8 ++++---- src/video_core/renderer_opengl/renderer_opengl.h | 4 ++-- src/video_core/renderer_vulkan/vk_blit_screen.cpp | 10 +++++----- src/video_core/surface.cpp | 8 ++++---- src/video_core/surface.h | 2 +- 35 files changed, 76 insertions(+), 79 deletions(-) (limited to 'src') diff --git a/src/core/hle/service/nvflinger/binder.h b/src/core/hle/service/nvflinger/binder.h index 2d9a23573..7d0d4d819 100644 --- a/src/core/hle/service/nvflinger/binder.h +++ b/src/core/hle/service/nvflinger/binder.h @@ -13,7 +13,7 @@ class HLERequestContext; class KReadableEvent; } // namespace Kernel -namespace android { +namespace Service::android { enum class TransactionId { RequestBuffer = 1, @@ -39,4 +39,4 @@ public: virtual Kernel::KReadableEvent& GetNativeHandle() = 0; }; -} // namespace android +} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_item.h b/src/core/hle/service/nvflinger/buffer_item.h index 9dc6f3fee..d60719065 100644 --- a/src/core/hle/service/nvflinger/buffer_item.h +++ b/src/core/hle/service/nvflinger/buffer_item.h @@ -13,7 +13,7 @@ #include "core/hle/service/nvflinger/ui/rect.h" #include "core/hle/service/nvflinger/window.h" -namespace android { +namespace Service::android { class GraphicBuffer; @@ -43,4 +43,4 @@ public: s32 swap_interval{}; }; -} // namespace android +} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_item_consumer.cpp b/src/core/hle/service/nvflinger/buffer_item_consumer.cpp index 424b19d32..508df3a12 100644 --- a/src/core/hle/service/nvflinger/buffer_item_consumer.cpp +++ b/src/core/hle/service/nvflinger/buffer_item_consumer.cpp @@ -10,7 +10,7 @@ #include "core/hle/service/nvflinger/buffer_item_consumer.h" #include "core/hle/service/nvflinger/buffer_queue_consumer.h" -namespace android { +namespace Service::android { BufferItemConsumer::BufferItemConsumer(std::unique_ptr consumer_) : ConsumerBase{std::move(consumer_)} {} @@ -56,4 +56,4 @@ Status BufferItemConsumer::ReleaseBuffer(const BufferItem& item, Fence& release_ return Status::NoError; } -} // namespace android +} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_item_consumer.h b/src/core/hle/service/nvflinger/buffer_item_consumer.h index f61c180b3..99d592960 100644 --- a/src/core/hle/service/nvflinger/buffer_item_consumer.h +++ b/src/core/hle/service/nvflinger/buffer_item_consumer.h @@ -12,7 +12,7 @@ #include "core/hle/service/nvflinger/consumer_base.h" #include "core/hle/service/nvflinger/status.h" -namespace android { +namespace Service::android { class BufferItem; @@ -23,4 +23,4 @@ public: Status ReleaseBuffer(const BufferItem& item, Fence& release_fence); }; -} // namespace android +} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp index f0875eca3..865f696d7 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp @@ -10,7 +10,7 @@ #include "core/hle/service/nvflinger/buffer_queue_core.h" #include "core/hle/service/nvflinger/producer_listener.h" -namespace android { +namespace Service::android { BufferQueueConsumer::BufferQueueConsumer(std::shared_ptr core_) : core{std::move(core_)}, slots{core->slots} {} @@ -222,4 +222,4 @@ Status BufferQueueConsumer::Connect(std::shared_ptr consumer_ return Status::NoError; } -} // namespace android +} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.h b/src/core/hle/service/nvflinger/buffer_queue_consumer.h index fbeb8b8d7..26981ed19 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_consumer.h +++ b/src/core/hle/service/nvflinger/buffer_queue_consumer.h @@ -12,7 +12,7 @@ #include "core/hle/service/nvflinger/buffer_queue_defs.h" #include "core/hle/service/nvflinger/status.h" -namespace android { +namespace Service::android { class BufferItem; class BufferQueueCore; @@ -33,4 +33,4 @@ private: BufferQueueDefs::SlotsType& slots; }; -} // namespace android +} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.cpp b/src/core/hle/service/nvflinger/buffer_queue_core.cpp index a6ff46aa9..63cf66ba3 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_core.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_core.cpp @@ -8,12 +8,9 @@ #include "core/hle/service/nvflinger/buffer_queue_core.h" -namespace android { - -BufferQueueCore::BufferQueueCore() : lock{mutex} { - // This is locked on creation, so unlock. - lock.unlock(); +namespace Service::android { +BufferQueueCore::BufferQueueCore() : lock{mutex, std::defer_lock} { for (s32 slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) { free_slots.insert(slot); } @@ -132,4 +129,4 @@ void BufferQueueCore::WaitWhileAllocatingLocked() const { } } -} // namespace android +} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.h b/src/core/hle/service/nvflinger/buffer_queue_core.h index 8019b7024..252a36350 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_core.h +++ b/src/core/hle/service/nvflinger/buffer_queue_core.h @@ -19,7 +19,7 @@ #include "core/hle/service/nvflinger/status.h" #include "core/hle/service/nvflinger/window.h" -namespace android { +namespace Service::android { class IConsumerListener; class IProducerListener; @@ -95,4 +95,4 @@ private: bool is_shutting_down{}; }; -} // namespace android +} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_queue_defs.h b/src/core/hle/service/nvflinger/buffer_queue_defs.h index cea09e044..387d3d36a 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_defs.h +++ b/src/core/hle/service/nvflinger/buffer_queue_defs.h @@ -11,11 +11,11 @@ #include "common/common_types.h" #include "core/hle/service/nvflinger/buffer_slot.h" -namespace android::BufferQueueDefs { +namespace Service::android::BufferQueueDefs { // BufferQueue will keep track of at most this value of buffers. constexpr s32 NUM_BUFFER_SLOTS = 64; using SlotsType = std::array; -} // namespace android::BufferQueueDefs +} // namespace Service::android::BufferQueueDefs diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp index a347f8b3b..2f7e9dcfc 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp @@ -23,7 +23,7 @@ #include "core/hle/service/nvflinger/window.h" #include "core/hle/service/vi/vi.h" -namespace android { +namespace Service::android { BufferQueueProducer::BufferQueueProducer(Service::KernelHelpers::ServiceContext& service_context_, std::shared_ptr buffer_queue_core_) @@ -936,4 +936,4 @@ Kernel::KReadableEvent& BufferQueueProducer::GetNativeHandle() { return buffer_wait_event->GetReadableEvent(); } -} // namespace android +} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.h b/src/core/hle/service/nvflinger/buffer_queue_producer.h index fcb71a794..5ddeebe0c 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.h +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.h @@ -31,7 +31,7 @@ namespace Service::KernelHelpers { class ServiceContext; } // namespace Service::KernelHelpers -namespace android { +namespace Service::android { class BufferQueueCore; class IProducerListener; @@ -80,4 +80,4 @@ private: std::condition_variable callback_condition; }; -} // namespace android +} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_slot.h b/src/core/hle/service/nvflinger/buffer_slot.h index 24b806d33..e3ea58910 100644 --- a/src/core/hle/service/nvflinger/buffer_slot.h +++ b/src/core/hle/service/nvflinger/buffer_slot.h @@ -11,7 +11,7 @@ #include "common/common_types.h" #include "core/hle/service/nvflinger/ui/fence.h" -namespace android { +namespace Service::android { class GraphicBuffer; @@ -36,4 +36,4 @@ struct BufferSlot final { bool is_preallocated{}; }; -} // namespace android +} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_transform_flags.h b/src/core/hle/service/nvflinger/buffer_transform_flags.h index 398c6370b..e8e6300e3 100644 --- a/src/core/hle/service/nvflinger/buffer_transform_flags.h +++ b/src/core/hle/service/nvflinger/buffer_transform_flags.h @@ -5,7 +5,7 @@ #include "common/common_types.h" -namespace android { +namespace Service::android { enum class BufferTransformFlags : u32 { /// No transform flags are set @@ -22,4 +22,4 @@ enum class BufferTransformFlags : u32 { Rotate270 = 0x07, }; -} // namespace android +} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/consumer_base.cpp b/src/core/hle/service/nvflinger/consumer_base.cpp index 127e5930b..c752ffc8e 100644 --- a/src/core/hle/service/nvflinger/consumer_base.cpp +++ b/src/core/hle/service/nvflinger/consumer_base.cpp @@ -12,7 +12,7 @@ #include "core/hle/service/nvflinger/consumer_base.h" #include "core/hle/service/nvflinger/ui/graphic_buffer.h" -namespace android { +namespace Service::android { ConsumerBase::ConsumerBase(std::unique_ptr consumer_) : consumer{std::move(consumer_)} {} @@ -126,4 +126,4 @@ bool ConsumerBase::StillTracking(s32 slot, const std::shared_ptr slots[slot].graphic_buffer->Handle() == graphic_buffer->Handle()); } -} // namespace android +} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/consumer_base.h b/src/core/hle/service/nvflinger/consumer_base.h index 574ea9781..ae34ea0a9 100644 --- a/src/core/hle/service/nvflinger/consumer_base.h +++ b/src/core/hle/service/nvflinger/consumer_base.h @@ -15,7 +15,7 @@ #include "core/hle/service/nvflinger/consumer_listener.h" #include "core/hle/service/nvflinger/status.h" -namespace android { +namespace Service::android { class BufferItem; class BufferQueueConsumer; @@ -56,4 +56,4 @@ protected: mutable std::mutex mutex; }; -} // namespace android +} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/consumer_listener.h b/src/core/hle/service/nvflinger/consumer_listener.h index 0aa4ad17b..b6d1c3e9a 100644 --- a/src/core/hle/service/nvflinger/consumer_listener.h +++ b/src/core/hle/service/nvflinger/consumer_listener.h @@ -6,7 +6,7 @@ #pragma once -namespace android { +namespace Service::android { class BufferItem; @@ -23,4 +23,4 @@ public: virtual void OnSidebandStreamChanged() = 0; }; -}; // namespace android +}; // namespace Service::android diff --git a/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp b/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp index 3e3669c99..d4da98ddb 100644 --- a/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp +++ b/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp @@ -9,7 +9,7 @@ #include "core/hle/service/nvflinger/graphic_buffer_producer.h" #include "core/hle/service/nvflinger/parcel.h" -namespace android { +namespace Service::android { QueueBufferInput::QueueBufferInput(Parcel& parcel) { parcel.ReadFlattened(*this); @@ -17,4 +17,4 @@ QueueBufferInput::QueueBufferInput(Parcel& parcel) { QueueBufferOutput::QueueBufferOutput() = default; -} // namespace android +} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/graphic_buffer_producer.h b/src/core/hle/service/nvflinger/graphic_buffer_producer.h index cad683cd3..dd4187027 100644 --- a/src/core/hle/service/nvflinger/graphic_buffer_producer.h +++ b/src/core/hle/service/nvflinger/graphic_buffer_producer.h @@ -12,7 +12,7 @@ #include "core/hle/service/nvflinger/ui/rect.h" #include "core/hle/service/nvflinger/window.h" -namespace android { +namespace Service::android { class Parcel; @@ -75,4 +75,4 @@ private: #pragma pack(pop) static_assert(sizeof(QueueBufferOutput) == 16, "QueueBufferOutput has wrong size"); -} // namespace android +} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 5112ae136..4f93ffe07 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -37,10 +37,10 @@ class Display; class Layer; } // namespace Service::VI -namespace android { +namespace Service::android { class BufferQueueCore; class BufferQueueProducer; -} // namespace android +} // namespace Service::android namespace Service::NVFlinger { diff --git a/src/core/hle/service/nvflinger/parcel.h b/src/core/hle/service/nvflinger/parcel.h index 710964f5d..b41c1732e 100644 --- a/src/core/hle/service/nvflinger/parcel.h +++ b/src/core/hle/service/nvflinger/parcel.h @@ -10,7 +10,7 @@ #include "common/assert.h" #include "common/common_types.h" -namespace android { +namespace Service::android { class Parcel final { public: @@ -168,4 +168,4 @@ private: std::size_t write_index = sizeof(Header); }; -} // namespace android +} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/pixel_format.h b/src/core/hle/service/nvflinger/pixel_format.h index 966c84775..8a77d8bea 100644 --- a/src/core/hle/service/nvflinger/pixel_format.h +++ b/src/core/hle/service/nvflinger/pixel_format.h @@ -5,7 +5,7 @@ #include "common/common_types.h" -namespace android { +namespace Service::android { enum class PixelFormat : u32 { NoFormat = 0, @@ -18,4 +18,4 @@ enum class PixelFormat : u32 { Rgba4444 = 7, }; -} // namespace android +} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/producer_listener.h b/src/core/hle/service/nvflinger/producer_listener.h index 8fe29d73e..468e06431 100644 --- a/src/core/hle/service/nvflinger/producer_listener.h +++ b/src/core/hle/service/nvflinger/producer_listener.h @@ -6,11 +6,11 @@ #pragma once -namespace android { +namespace Service::android { class IProducerListener { public: virtual void OnBufferReleased() = 0; }; -} // namespace android +} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/status.h b/src/core/hle/service/nvflinger/status.h index 9bc1205df..a003eda89 100644 --- a/src/core/hle/service/nvflinger/status.h +++ b/src/core/hle/service/nvflinger/status.h @@ -6,7 +6,7 @@ #include "common/common_funcs.h" #include "common/common_types.h" -namespace android { +namespace Service::android { enum class Status : s32 { None = 0, @@ -25,4 +25,4 @@ enum class Status : s32 { }; DECLARE_ENUM_FLAG_OPERATORS(Status); -} // namespace android +} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/ui/fence.h b/src/core/hle/service/nvflinger/ui/fence.h index 80ce98782..4a74e26a3 100644 --- a/src/core/hle/service/nvflinger/ui/fence.h +++ b/src/core/hle/service/nvflinger/ui/fence.h @@ -11,7 +11,7 @@ #include "common/common_types.h" #include "core/hle/service/nvdrv/nvdata.h" -namespace android { +namespace Service::android { class Fence { public: @@ -29,4 +29,4 @@ public: }; static_assert(sizeof(Fence) == 36, "Fence has wrong size"); -} // namespace android +} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/ui/graphic_buffer.h b/src/core/hle/service/nvflinger/ui/graphic_buffer.h index 2e7f251ef..7abbf78ba 100644 --- a/src/core/hle/service/nvflinger/ui/graphic_buffer.h +++ b/src/core/hle/service/nvflinger/ui/graphic_buffer.h @@ -10,7 +10,7 @@ #include "common/common_types.h" #include "core/hle/service/nvflinger/pixel_format.h" -namespace android { +namespace Service::android { class GraphicBuffer final { public: @@ -97,4 +97,4 @@ private: }; static_assert(sizeof(GraphicBuffer) == 0x16C, "GraphicBuffer has wrong size"); -} // namespace android +} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/ui/rect.h b/src/core/hle/service/nvflinger/ui/rect.h index 847f6f4ae..c7b5f1815 100644 --- a/src/core/hle/service/nvflinger/ui/rect.h +++ b/src/core/hle/service/nvflinger/ui/rect.h @@ -11,7 +11,7 @@ #include "common/common_types.h" -namespace android { +namespace Service::android { class Rect final { public: @@ -72,4 +72,4 @@ private: }; static_assert(sizeof(Rect) == 16, "Rect has wrong size"); -} // namespace android +} // namespace Service::android diff --git a/src/core/hle/service/nvflinger/window.h b/src/core/hle/service/nvflinger/window.h index 17f36da20..e26f8160e 100644 --- a/src/core/hle/service/nvflinger/window.h +++ b/src/core/hle/service/nvflinger/window.h @@ -6,7 +6,7 @@ #include "common/common_funcs.h" #include "common/common_types.h" -namespace android { +namespace Service::android { /// Attributes queryable with Query enum class NativeWindow : s32 { @@ -50,4 +50,4 @@ enum class NativeWindowTransform : u32 { }; DECLARE_ENUM_FLAG_OPERATORS(NativeWindowTransform); -} // namespace android +} // namespace Service::android diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h index 9cf324395..e93d084ee 100644 --- a/src/core/hle/service/vi/display/vi_display.h +++ b/src/core/hle/service/vi/display/vi_display.h @@ -15,7 +15,7 @@ namespace Kernel { class KEvent; } -namespace android { +namespace Service::android { class BufferQueueProducer; } diff --git a/src/core/hle/service/vi/layer/vi_layer.h b/src/core/hle/service/vi/layer/vi_layer.h index 079ec4dda..c28b14450 100644 --- a/src/core/hle/service/vi/layer/vi_layer.h +++ b/src/core/hle/service/vi/layer/vi_layer.h @@ -8,11 +8,11 @@ #include "common/common_types.h" -namespace android { +namespace Service::android { class BufferItemConsumer; class BufferQueueCore; class BufferQueueProducer; -} // namespace android +} // namespace Service::android namespace Service::VI { diff --git a/src/video_core/framebuffer_config.h b/src/video_core/framebuffer_config.h index 1e75d51ab..93349bb78 100644 --- a/src/video_core/framebuffer_config.h +++ b/src/video_core/framebuffer_config.h @@ -20,8 +20,8 @@ struct FramebufferConfig { u32 width{}; u32 height{}; u32 stride{}; - android::PixelFormat pixel_format{}; - android::BufferTransformFlags transform_flags{}; + Service::android::PixelFormat pixel_format{}; + Service::android::BufferTransformFlags transform_flags{}; Common::Rectangle crop_rect; }; diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 279421962..f8f29013a 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -323,12 +323,12 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, GLint internal_format; switch (framebuffer.pixel_format) { - case android::PixelFormat::Rgba8888: + case Service::android::PixelFormat::Rgba8888: internal_format = GL_RGBA8; texture.gl_format = GL_RGBA; texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; break; - case android::PixelFormat::Rgb565: + case Service::android::PixelFormat::Rgb565: internal_format = GL_RGB565; texture.gl_format = GL_RGB; texture.gl_type = GL_UNSIGNED_SHORT_5_6_5; @@ -464,8 +464,8 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { const auto& texcoords = screen_info.display_texcoords; auto left = texcoords.left; auto right = texcoords.right; - if (framebuffer_transform_flags != android::BufferTransformFlags::Unset) { - if (framebuffer_transform_flags == android::BufferTransformFlags::FlipV) { + if (framebuffer_transform_flags != Service::android::BufferTransformFlags::Unset) { + if (framebuffer_transform_flags == Service::android::BufferTransformFlags::FlipV) { // Flip the framebuffer vertically left = texcoords.right; right = texcoords.left; diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index e6395b900..aa206878b 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -46,7 +46,7 @@ struct TextureInfo { GLsizei height; GLenum gl_format; GLenum gl_type; - android::PixelFormat pixel_format; + Service::android::PixelFormat pixel_format; }; /// Structure used for storing information about the display target for the Switch screen @@ -135,7 +135,7 @@ private: std::vector gl_framebuffer_data; /// Used for transforming the framebuffer orientation - android::BufferTransformFlags framebuffer_transform_flags{}; + Service::android::BufferTransformFlags framebuffer_transform_flags{}; Common::Rectangle framebuffer_crop_rect; }; diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 3da16c422..d893c1952 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp @@ -94,11 +94,11 @@ std::size_t GetSizeInBytes(const Tegra::FramebufferConfig& framebuffer) { VkFormat GetFormat(const Tegra::FramebufferConfig& framebuffer) { switch (framebuffer.pixel_format) { - case android::PixelFormat::Rgba8888: + case Service::android::PixelFormat::Rgba8888: return VK_FORMAT_A8B8G8R8_UNORM_PACK32; - case android::PixelFormat::Rgb565: + case Service::android::PixelFormat::Rgb565: return VK_FORMAT_R5G6B5_UNORM_PACK16; - case android::PixelFormat::Bgra8888: + case Service::android::PixelFormat::Bgra8888: return VK_FORMAT_B8G8R8A8_UNORM; default: UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}", @@ -1390,9 +1390,9 @@ void VKBlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfi auto right = texcoords.right; switch (framebuffer_transform_flags) { - case android::BufferTransformFlags::Unset: + case Service::android::BufferTransformFlags::Unset: break; - case android::BufferTransformFlags::FlipV: + case Service::android::BufferTransformFlags::FlipV: // Flip the framebuffer vertically left = texcoords.right; right = texcoords.left; diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp index f7d29534e..5f428d35d 100644 --- a/src/video_core/surface.cpp +++ b/src/video_core/surface.cpp @@ -190,13 +190,13 @@ PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) } } -PixelFormat PixelFormatFromGPUPixelFormat(android::PixelFormat format) { +PixelFormat PixelFormatFromGPUPixelFormat(Service::android::PixelFormat format) { switch (format) { - case android::PixelFormat::Rgba8888: + case Service::android::PixelFormat::Rgba8888: return PixelFormat::A8B8G8R8_UNORM; - case android::PixelFormat::Rgb565: + case Service::android::PixelFormat::Rgb565: return PixelFormat::R5G6B5_UNORM; - case android::PixelFormat::Bgra8888: + case Service::android::PixelFormat::Bgra8888: return PixelFormat::B8G8R8A8_UNORM; default: UNIMPLEMENTED_MSG("Unimplemented format={}", format); diff --git a/src/video_core/surface.h b/src/video_core/surface.h index 1061b2fa7..5704cf16a 100644 --- a/src/video_core/surface.h +++ b/src/video_core/surface.h @@ -460,7 +460,7 @@ PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format); PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format); -PixelFormat PixelFormatFromGPUPixelFormat(android::PixelFormat format); +PixelFormat PixelFormatFromGPUPixelFormat(Service::android::PixelFormat format); SurfaceType GetFormatType(PixelFormat pixel_format); -- cgit v1.2.3 From 650c9d0d627b1c926a07d82d0248f283ccbd8a1b Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 19 Mar 2022 21:52:08 -0700 Subject: hle: nvflinger: Use std::chrono for present_ns. --- .../hle/service/nvflinger/buffer_item_consumer.cpp | 4 +-- .../hle/service/nvflinger/buffer_item_consumer.h | 4 ++- .../service/nvflinger/buffer_queue_consumer.cpp | 34 +++++++++++----------- .../hle/service/nvflinger/buffer_queue_consumer.h | 3 +- src/core/hle/service/nvflinger/consumer_base.cpp | 4 +-- src/core/hle/service/nvflinger/consumer_base.h | 4 ++- src/core/hle/service/nvflinger/nvflinger.cpp | 2 +- 7 files changed, 30 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/core/hle/service/nvflinger/buffer_item_consumer.cpp b/src/core/hle/service/nvflinger/buffer_item_consumer.cpp index 508df3a12..7f32c0775 100644 --- a/src/core/hle/service/nvflinger/buffer_item_consumer.cpp +++ b/src/core/hle/service/nvflinger/buffer_item_consumer.cpp @@ -15,7 +15,7 @@ namespace Service::android { BufferItemConsumer::BufferItemConsumer(std::unique_ptr consumer_) : ConsumerBase{std::move(consumer_)} {} -Status BufferItemConsumer::AcquireBuffer(BufferItem* item, u64 present_when_ns, +Status BufferItemConsumer::AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when, bool wait_for_fence) { if (!item) { return Status::BadValue; @@ -23,7 +23,7 @@ Status BufferItemConsumer::AcquireBuffer(BufferItem* item, u64 present_when_ns, std::unique_lock lock(mutex); - if (const auto status = AcquireBufferLocked(item, present_when_ns); status != Status::NoError) { + if (const auto status = AcquireBufferLocked(item, present_when); status != Status::NoError) { if (status != Status::NoBufferAvailable) { LOG_ERROR(Service_NVFlinger, "Failed to acquire buffer: {}", status); } diff --git a/src/core/hle/service/nvflinger/buffer_item_consumer.h b/src/core/hle/service/nvflinger/buffer_item_consumer.h index 99d592960..536db81e2 100644 --- a/src/core/hle/service/nvflinger/buffer_item_consumer.h +++ b/src/core/hle/service/nvflinger/buffer_item_consumer.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include "common/common_types.h" @@ -19,7 +20,8 @@ class BufferItem; class BufferItemConsumer final : public ConsumerBase { public: explicit BufferItemConsumer(std::unique_ptr consumer); - Status AcquireBuffer(BufferItem* item, u64 present_when_ns, bool wait_for_fence = true); + Status AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when, + bool wait_for_fence = true); Status ReleaseBuffer(const BufferItem& item, Fence& release_fence); }; diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp index 865f696d7..5184d876a 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp @@ -17,7 +17,8 @@ BufferQueueConsumer::BufferQueueConsumer(std::shared_ptr core_) BufferQueueConsumer::~BufferQueueConsumer() = default; -Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer, s64 expected_presenst_ns, +Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer, + std::chrono::nanoseconds expected_present, u64 max_frame_number) { s32 num_dropped_buffers{}; @@ -26,12 +27,10 @@ Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer, s64 expected_p std::unique_lock lock(core->mutex); // Check that the consumer doesn't currently have the maximum number of buffers acquired. - s32 num_acquired_buffers{}; - for (const auto& slot : slots) { - if (slot.buffer_state == BufferState::Acquired) { - ++num_acquired_buffers; - } - } + const s32 num_acquired_buffers{ + static_cast(std::count_if(slots.begin(), slots.end(), [](const auto& slot) { + return slot.buffer_state == BufferState::Acquired; + }))}; if (num_acquired_buffers >= core->max_acquired_buffer_count + 1) { LOG_ERROR(Service_NVFlinger, "max acquired buffer count reached: {} (max {})", @@ -46,8 +45,8 @@ Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer, s64 expected_p auto front(core->queue.begin()); - // If expected_presenst_ns is specified, we may not want to return a buffer yet. - if (expected_presenst_ns != 0) { + // If expected_present is specified, we may not want to return a buffer yet. + if (expected_present.count() != 0) { constexpr auto MAX_REASONABLE_NSEC = 1000000000LL; // 1 second // The expected_presenst_ns argument indicates when the buffer is expected to be @@ -63,17 +62,17 @@ Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer, s64 expected_p // If entry[1] is timely, drop entry[0] (and repeat). const auto desired_present = buffer_item.timestamp; - if (desired_present < expected_presenst_ns - MAX_REASONABLE_NSEC || - desired_present > expected_presenst_ns) { + if (desired_present < expected_present.count() - MAX_REASONABLE_NSEC || + desired_present > expected_present.count()) { // This buffer is set to display in the near future, or desired_present is // garbage. LOG_DEBUG(Service_NVFlinger, "nodrop desire={} expect={}", desired_present, - expected_presenst_ns); + expected_present.count()); break; } LOG_DEBUG(Service_NVFlinger, "drop desire={} expect={} size={}", desired_present, - expected_presenst_ns, core->queue.size()); + expected_present.count(), core->queue.size()); if (core->StillTracking(&*front)) { // Front buffer is still in mSlots, so mark the slot as free @@ -89,19 +88,20 @@ Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer, s64 expected_p // See if the front buffer is ready to be acquired. const auto desired_present = front->timestamp; - const auto buffer_is_due = desired_present <= expected_presenst_ns || - desired_present > expected_presenst_ns + MAX_REASONABLE_NSEC; + const auto buffer_is_due = + desired_present <= expected_present.count() || + desired_present > expected_present.count() + MAX_REASONABLE_NSEC; const auto consumer_is_ready = max_frame_number > 0 ? front->frame_number <= max_frame_number : true; if (!buffer_is_due || !consumer_is_ready) { LOG_DEBUG(Service_NVFlinger, "defer desire={} expect={}", desired_present, - expected_presenst_ns); + expected_present.count()); return Status::PresentLater; } LOG_DEBUG(Service_NVFlinger, "accept desire={} expect={}", desired_present, - expected_presenst_ns); + expected_present.count()); } const auto slot = front->slot; diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.h b/src/core/hle/service/nvflinger/buffer_queue_consumer.h index 26981ed19..f22854394 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_consumer.h +++ b/src/core/hle/service/nvflinger/buffer_queue_consumer.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include "common/common_types.h" @@ -23,7 +24,7 @@ public: explicit BufferQueueConsumer(std::shared_ptr core_); ~BufferQueueConsumer(); - Status AcquireBuffer(BufferItem* out_buffer, s64 expected_presenst_ns, + Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present, u64 max_frame_number = 0); Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence); Status Connect(std::shared_ptr consumer_listener, bool controlled_by_app); diff --git a/src/core/hle/service/nvflinger/consumer_base.cpp b/src/core/hle/service/nvflinger/consumer_base.cpp index c752ffc8e..0524463bd 100644 --- a/src/core/hle/service/nvflinger/consumer_base.cpp +++ b/src/core/hle/service/nvflinger/consumer_base.cpp @@ -52,14 +52,14 @@ void ConsumerBase::OnBuffersReleased() { void ConsumerBase::OnSidebandStreamChanged() {} -Status ConsumerBase::AcquireBufferLocked(BufferItem* item, u64 present_when_ns, +Status ConsumerBase::AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when, u64 max_frame_number) { if (is_abandoned) { LOG_ERROR(Service_NVFlinger, "consumer is abandoned!"); return Status::NoInit; } - Status err = consumer->AcquireBuffer(item, present_when_ns, max_frame_number); + Status err = consumer->AcquireBuffer(item, present_when, max_frame_number); if (err != Status::NoError) { return err; } diff --git a/src/core/hle/service/nvflinger/consumer_base.h b/src/core/hle/service/nvflinger/consumer_base.h index ae34ea0a9..453a47349 100644 --- a/src/core/hle/service/nvflinger/consumer_base.h +++ b/src/core/hle/service/nvflinger/consumer_base.h @@ -7,6 +7,7 @@ #pragma once #include +#include #include #include @@ -34,7 +35,8 @@ protected: virtual void OnSidebandStreamChanged() override; void FreeBufferLocked(s32 slot_index); - Status AcquireBufferLocked(BufferItem* item, u64 present_when_ns, u64 max_frame_number = 0); + Status AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when, + u64 max_frame_number = 0); Status ReleaseBufferLocked(s32 slot, const std::shared_ptr graphic_buffer); bool StillTracking(s32 slot, const std::shared_ptr graphic_buffer); Status AddReleaseFenceLocked(s32 slot, const std::shared_ptr graphic_buffer, diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index e21dc902a..76ce1fbfd 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -240,7 +240,7 @@ void NVFlinger::Compose() { VI::Layer& layer = display.GetLayer(0); android::BufferItem buffer{}; - const auto status = layer.GetConsumer().AcquireBuffer(&buffer, 0, false); + const auto status = layer.GetConsumer().AcquireBuffer(&buffer, {}, false); if (status != android::Status::NoError) { continue; -- cgit v1.2.3 From 53058ae73f26e19cd819ba1c9a365a091962757d Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 19 Mar 2022 21:53:47 -0700 Subject: hle: nvflinger: buffer_queue_core: Cleanup locking. --- src/core/hle/service/nvflinger/buffer_queue_core.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.cpp b/src/core/hle/service/nvflinger/buffer_queue_core.cpp index 63cf66ba3..4a26d2fdc 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_core.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_core.cpp @@ -17,7 +17,7 @@ BufferQueueCore::BufferQueueCore() : lock{mutex, std::defer_lock} { } void BufferQueueCore::NotifyShutdown() { - std::unique_lock lk(mutex); + std::unique_lock lk(mutex); is_shutting_down = true; @@ -124,7 +124,7 @@ bool BufferQueueCore::StillTracking(const BufferItem* item) const { void BufferQueueCore::WaitWhileAllocatingLocked() const { while (is_allocating) { - std::unique_lock lk(mutex); + std::unique_lock lk(mutex); is_allocating_condition.wait(lk); } } -- cgit v1.2.3 From ddd5a2b1c67a82f0b1dbaa75dc4b99ee71f93173 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 19 Mar 2022 22:06:46 -0700 Subject: hle: nvflinger: buffer_queue_core: StillTracking: Take const reference. --- src/core/hle/service/nvflinger/buffer_queue_consumer.cpp | 4 ++-- src/core/hle/service/nvflinger/buffer_queue_core.cpp | 6 +++--- src/core/hle/service/nvflinger/buffer_queue_core.h | 2 +- src/core/hle/service/nvflinger/buffer_queue_producer.cpp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp index 5184d876a..cf12cceff 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp @@ -74,7 +74,7 @@ Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer, LOG_DEBUG(Service_NVFlinger, "drop desire={} expect={} size={}", desired_present, expected_present.count(), core->queue.size()); - if (core->StillTracking(&*front)) { + if (core->StillTracking(*front)) { // Front buffer is still in mSlots, so mark the slot as free slots[front->slot].buffer_state = BufferState::Free; core->free_buffers.push_back(front->slot); @@ -110,7 +110,7 @@ Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer, LOG_DEBUG(Service_NVFlinger, "acquiring slot={}", slot); // If the front buffer is still being tracked, update its slot state - if (core->StillTracking(&*front)) { + if (core->StillTracking(*front)) { slots[slot].acquire_called = true; slots[slot].needs_cleanup_on_release = false; slots[slot].buffer_state = BufferState::Acquired; diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.cpp b/src/core/hle/service/nvflinger/buffer_queue_core.cpp index 4a26d2fdc..3f1ce78b0 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_core.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_core.cpp @@ -116,10 +116,10 @@ void BufferQueueCore::FreeAllBuffersLocked() { } } -bool BufferQueueCore::StillTracking(const BufferItem* item) const { - const BufferSlot& slot = slots[item->slot]; +bool BufferQueueCore::StillTracking(const BufferItem& item) const { + const BufferSlot& slot = slots[item.slot]; - return (slot.graphic_buffer != nullptr) && (item->graphic_buffer == slot.graphic_buffer); + return (slot.graphic_buffer != nullptr) && (item.graphic_buffer == slot.graphic_buffer); } void BufferQueueCore::WaitWhileAllocatingLocked() const { diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.h b/src/core/hle/service/nvflinger/buffer_queue_core.h index 252a36350..ad10b4c3c 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_core.h +++ b/src/core/hle/service/nvflinger/buffer_queue_core.h @@ -45,7 +45,7 @@ private: s32 GetPreallocatedBufferCountLocked() const; void FreeBufferLocked(s32 slot); void FreeAllBuffersLocked(); - bool StillTracking(const BufferItem* item) const; + bool StillTracking(const BufferItem& item) const; void WaitWhileAllocatingLocked() const; private: diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp index 2f7e9dcfc..eba486754 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp @@ -554,7 +554,7 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input, if (front->is_droppable) { // If the front queued buffer is still being tracked, we first // mark it as freed - if (core->StillTracking(&*front)) { + if (core->StillTracking(*front)) { slots[front->slot].buffer_state = BufferState::Free; core->free_buffers.push_front(front->slot); } -- cgit v1.2.3 From 7db60fe7da370c0d37182a27ec8af928cd066b40 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 19 Mar 2022 22:07:52 -0700 Subject: hle: nvflinger: parcel: Reserve token size. --- src/core/hle/service/nvflinger/parcel.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/hle/service/nvflinger/parcel.h b/src/core/hle/service/nvflinger/parcel.h index b41c1732e..aa36e6479 100644 --- a/src/core/hle/service/nvflinger/parcel.h +++ b/src/core/hle/service/nvflinger/parcel.h @@ -89,7 +89,8 @@ public: [[maybe_unused]] const u32 unknown = Read(); const u32 length = Read(); - std::u16string token{}; + std::u16string token; + token.reserve(length + 1); for (u32 ch = 0; ch < length + 1; ++ch) { token.push_back(ReadUnaligned()); -- cgit v1.2.3 From 480c79edba7162d29c82e3752653626d37aacd5f Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 19 Mar 2022 22:08:26 -0700 Subject: hle: nvflinger: graphic_buffer_producer: Remove unnecessary pragma pack. --- src/core/hle/service/nvflinger/graphic_buffer_producer.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/core/hle/service/nvflinger/graphic_buffer_producer.h b/src/core/hle/service/nvflinger/graphic_buffer_producer.h index dd4187027..58763cf08 100644 --- a/src/core/hle/service/nvflinger/graphic_buffer_producer.h +++ b/src/core/hle/service/nvflinger/graphic_buffer_producer.h @@ -48,7 +48,6 @@ private: #pragma pack(pop) static_assert(sizeof(QueueBufferInput) == 84, "QueueBufferInput has wrong size"); -#pragma pack(push, 1) struct QueueBufferOutput final { QueueBufferOutput(); @@ -72,7 +71,6 @@ private: u32 transform_hint{}; u32 num_pending_buffers{}; }; -#pragma pack(pop) static_assert(sizeof(QueueBufferOutput) == 16, "QueueBufferOutput has wrong size"); } // namespace Service::android -- cgit v1.2.3 From 0ce308047e08c9671631f9898be01360e77fcaad Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 19 Mar 2022 22:08:50 -0700 Subject: hle: nvflinger: consumer_base: StillTracking: Should be const. --- src/core/hle/service/nvflinger/consumer_base.cpp | 3 ++- src/core/hle/service/nvflinger/consumer_base.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/hle/service/nvflinger/consumer_base.cpp b/src/core/hle/service/nvflinger/consumer_base.cpp index 0524463bd..3ccbb7fb8 100644 --- a/src/core/hle/service/nvflinger/consumer_base.cpp +++ b/src/core/hle/service/nvflinger/consumer_base.cpp @@ -117,7 +117,8 @@ Status ConsumerBase::ReleaseBufferLocked(s32 slot, return err; } -bool ConsumerBase::StillTracking(s32 slot, const std::shared_ptr graphic_buffer) { +bool ConsumerBase::StillTracking(s32 slot, + const std::shared_ptr graphic_buffer) const { if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { return false; } diff --git a/src/core/hle/service/nvflinger/consumer_base.h b/src/core/hle/service/nvflinger/consumer_base.h index 453a47349..d72160c2c 100644 --- a/src/core/hle/service/nvflinger/consumer_base.h +++ b/src/core/hle/service/nvflinger/consumer_base.h @@ -38,7 +38,7 @@ protected: Status AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when, u64 max_frame_number = 0); Status ReleaseBufferLocked(s32 slot, const std::shared_ptr graphic_buffer); - bool StillTracking(s32 slot, const std::shared_ptr graphic_buffer); + bool StillTracking(s32 slot, const std::shared_ptr graphic_buffer) const; Status AddReleaseFenceLocked(s32 slot, const std::shared_ptr graphic_buffer, const Fence& fence); -- cgit v1.2.3 From 8e35eedf22c28e1602627243a68eeb52af788e7d Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 19 Mar 2022 22:09:22 -0700 Subject: hle: nvflinger: buffer_queue_producer: DequeueBuffer: Remove unnecessary lock. --- src/core/hle/service/nvflinger/buffer_queue_producer.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp index eba486754..99f7ec1ac 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp @@ -229,12 +229,10 @@ Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool async, u32 width, u32 height, PixelFormat format, u32 usage) { - { BufferQueueCore::AutoLock lock(core); } - LOG_DEBUG(Service_NVFlinger, "async={} w={} h={} format={}, usage={}", async ? "true" : "false", width, height, format, usage); - if ((width && !height) || (!width && height)) { + if ((width != 0 && height == 0) || (width == 0 && height != 0)) { LOG_ERROR(Service_NVFlinger, "invalid size: w={} h={}", width, height); return Status::BadValue; } -- cgit v1.2.3 From e524def8c068bcd4660410117a13241e175afc9b Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 19 Mar 2022 22:09:46 -0700 Subject: hle: nvflinger: buffer_queue_core: Declare default dtor. --- src/core/hle/service/nvflinger/buffer_queue_core.cpp | 2 ++ src/core/hle/service/nvflinger/buffer_queue_core.h | 1 + 2 files changed, 3 insertions(+) (limited to 'src') diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.cpp b/src/core/hle/service/nvflinger/buffer_queue_core.cpp index 3f1ce78b0..eb93b43ee 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_core.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_core.cpp @@ -16,6 +16,8 @@ BufferQueueCore::BufferQueueCore() : lock{mutex, std::defer_lock} { } } +BufferQueueCore::~BufferQueueCore() = default; + void BufferQueueCore::NotifyShutdown() { std::unique_lock lk(mutex); diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.h b/src/core/hle/service/nvflinger/buffer_queue_core.h index ad10b4c3c..a3cd89f1c 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_core.h +++ b/src/core/hle/service/nvflinger/buffer_queue_core.h @@ -32,6 +32,7 @@ public: static constexpr s32 INVALID_BUFFER_SLOT = BufferItem::INVALID_BUFFER_SLOT; BufferQueueCore(); + ~BufferQueueCore(); void NotifyShutdown(); -- cgit v1.2.3 From 4d9488033f849132446ffb7840f1309fa38be8fd Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 19 Mar 2022 22:47:46 -0700 Subject: hle: nvflinger: Merge Rect with Common::Rectangle. --- src/common/math_util.h | 50 +++++++++++++-- src/core/CMakeLists.txt | 1 - src/core/hle/service/nvflinger/buffer_item.h | 4 +- .../service/nvflinger/buffer_queue_producer.cpp | 8 +-- .../service/nvflinger/graphic_buffer_producer.h | 6 +- src/core/hle/service/nvflinger/ui/rect.h | 75 ---------------------- 6 files changed, 54 insertions(+), 90 deletions(-) delete mode 100644 src/core/hle/service/nvflinger/ui/rect.h (limited to 'src') diff --git a/src/common/math_util.h b/src/common/math_util.h index 510c4e56d..54485bf53 100644 --- a/src/common/math_util.h +++ b/src/common/math_util.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include @@ -20,10 +21,32 @@ struct Rectangle { constexpr Rectangle() = default; + constexpr Rectangle(T width, T height) : right(width), bottom(height) {} + constexpr Rectangle(T left_, T top_, T right_, T bottom_) : left(left_), top(top_), right(right_), bottom(bottom_) {} - [[nodiscard]] T GetWidth() const { + [[nodiscard]] constexpr T Left() const { + return left; + } + + [[nodiscard]] constexpr T Top() const { + return top; + } + + [[nodiscard]] constexpr T Right() const { + return right; + } + + [[nodiscard]] constexpr T Bottom() const { + return bottom; + } + + [[nodiscard]] constexpr bool IsEmpty() const { + return (GetWidth() <= 0) || (GetHeight() <= 0); + } + + [[nodiscard]] constexpr T GetWidth() const { if constexpr (std::is_floating_point_v) { return std::abs(right - left); } else { @@ -31,7 +54,7 @@ struct Rectangle { } } - [[nodiscard]] T GetHeight() const { + [[nodiscard]] constexpr T GetHeight() const { if constexpr (std::is_floating_point_v) { return std::abs(bottom - top); } else { @@ -39,18 +62,35 @@ struct Rectangle { } } - [[nodiscard]] Rectangle TranslateX(const T x) const { + [[nodiscard]] constexpr Rectangle TranslateX(const T x) const { return Rectangle{left + x, top, right + x, bottom}; } - [[nodiscard]] Rectangle TranslateY(const T y) const { + [[nodiscard]] constexpr Rectangle TranslateY(const T y) const { return Rectangle{left, top + y, right, bottom + y}; } - [[nodiscard]] Rectangle Scale(const float s) const { + [[nodiscard]] constexpr Rectangle Scale(const float s) const { return Rectangle{left, top, static_cast(static_cast(left + GetWidth()) * s), static_cast(static_cast(top + GetHeight()) * s)}; } + + [[nodiscard]] constexpr bool operator==(const Rectangle& rhs) const { + return (left == rhs.left) && (top == rhs.top) && (right == rhs.right) && + (bottom == rhs.bottom); + } + + [[nodiscard]] constexpr bool operator!=(const Rectangle& rhs) const { + return !operator==(rhs); + } + + [[nodiscard]] constexpr bool Intersect(const Rectangle& with, Rectangle* result) const { + result->left = std::max(left, with.left); + result->top = std::max(top, with.top); + result->right = std::min(right, with.right); + result->bottom = std::min(bottom, with.bottom); + return !result->IsEmpty(); + } }; template diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ff8adfc55..6536d0544 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -563,7 +563,6 @@ add_library(core STATIC hle/service/nvflinger/status.h hle/service/nvflinger/ui/fence.h hle/service/nvflinger/ui/graphic_buffer.h - hle/service/nvflinger/ui/rect.h hle/service/nvflinger/window.h hle/service/olsc/olsc.cpp hle/service/olsc/olsc.h diff --git a/src/core/hle/service/nvflinger/buffer_item.h b/src/core/hle/service/nvflinger/buffer_item.h index d60719065..64b82b851 100644 --- a/src/core/hle/service/nvflinger/buffer_item.h +++ b/src/core/hle/service/nvflinger/buffer_item.h @@ -9,8 +9,8 @@ #include #include "common/common_types.h" +#include "common/math_util.h" #include "core/hle/service/nvflinger/ui/fence.h" -#include "core/hle/service/nvflinger/ui/rect.h" #include "core/hle/service/nvflinger/window.h" namespace Service::android { @@ -23,7 +23,7 @@ public: std::shared_ptr graphic_buffer; Fence fence; - Rect crop; + Common::Rectangle crop; NativeWindowTransform transform{}; u32 scaling_mode{}; s64 timestamp{}; diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp index 99f7ec1ac..5ea48431f 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp @@ -441,7 +441,7 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input, QueueBufferOutput* output) { s64 timestamp{}; bool is_auto_timestamp{}; - Rect crop; + Common::Rectangle crop; NativeWindowScalingMode scaling_mode{}; NativeWindowTransform transform; u32 sticky_transform_{}; @@ -509,9 +509,9 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input, crop.Bottom(), transform, scaling_mode); const std::shared_ptr& graphic_buffer(slots[slot].graphic_buffer); - Rect buffer_rect(graphic_buffer->Width(), graphic_buffer->Height()); - Rect cropped_rect; - crop.Intersect(buffer_rect, &cropped_rect); + Common::Rectangle buffer_rect(graphic_buffer->Width(), graphic_buffer->Height()); + Common::Rectangle cropped_rect; + [[maybe_unused]] const bool unused = crop.Intersect(buffer_rect, &cropped_rect); if (cropped_rect != crop) { LOG_ERROR(Service_NVFlinger, "crop rect is not contained within the buffer in slot {}", diff --git a/src/core/hle/service/nvflinger/graphic_buffer_producer.h b/src/core/hle/service/nvflinger/graphic_buffer_producer.h index 58763cf08..98d27871c 100644 --- a/src/core/hle/service/nvflinger/graphic_buffer_producer.h +++ b/src/core/hle/service/nvflinger/graphic_buffer_producer.h @@ -8,8 +8,8 @@ #include "common/common_funcs.h" #include "common/common_types.h" +#include "common/math_util.h" #include "core/hle/service/nvflinger/ui/fence.h" -#include "core/hle/service/nvflinger/ui/rect.h" #include "core/hle/service/nvflinger/window.h" namespace Service::android { @@ -20,7 +20,7 @@ class Parcel; struct QueueBufferInput final { explicit QueueBufferInput(Parcel& parcel); - void Deflate(s64* timestamp_, bool* is_auto_timestamp_, Rect* crop_, + void Deflate(s64* timestamp_, bool* is_auto_timestamp_, Common::Rectangle* crop_, NativeWindowScalingMode* scaling_mode_, NativeWindowTransform* transform_, u32* sticky_transform_, bool* async_, s32* swap_interval_, Fence* fence_) const { *timestamp_ = timestamp; @@ -37,7 +37,7 @@ struct QueueBufferInput final { private: s64 timestamp{}; s32 is_auto_timestamp{}; - Rect crop{}; + Common::Rectangle crop{}; NativeWindowScalingMode scaling_mode{}; NativeWindowTransform transform{}; u32 sticky_transform{}; diff --git a/src/core/hle/service/nvflinger/ui/rect.h b/src/core/hle/service/nvflinger/ui/rect.h deleted file mode 100644 index c7b5f1815..000000000 --- a/src/core/hle/service/nvflinger/ui/rect.h +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// Copyright 2021 yuzu Emulator Project -// Copyright 2006 The Android Open Source Project -// Parts of this implementation were base on: -// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/ui/Rect.h - -#pragma once - -#include -#include - -#include "common/common_types.h" - -namespace Service::android { - -class Rect final { -public: - constexpr Rect() = default; - - constexpr Rect(s32 width_, s32 height_) : right{width_}, bottom{height_} {} - - constexpr s32 Left() const { - return left; - } - - constexpr s32 Top() const { - return top; - } - - constexpr s32 Right() const { - return right; - } - - constexpr s32 Bottom() const { - return bottom; - } - - constexpr bool IsEmpty() const { - return (GetWidth() <= 0) || (GetHeight() <= 0); - } - - constexpr s32 GetWidth() const { - return right - left; - } - - constexpr s32 GetHeight() const { - return bottom - top; - } - - constexpr bool operator==(const Rect& rhs) const { - return (left == rhs.left) && (top == rhs.top) && (right == rhs.right) && - (bottom == rhs.bottom); - } - - constexpr bool operator!=(const Rect& rhs) const { - return !operator==(rhs); - } - - constexpr bool Intersect(const Rect& with, Rect* result) const { - result->left = std::max(left, with.left); - result->top = std::max(top, with.top); - result->right = std::min(right, with.right); - result->bottom = std::min(bottom, with.bottom); - return !result->IsEmpty(); - } - -private: - s32 left{}; - s32 top{}; - s32 right{}; - s32 bottom{}; -}; -static_assert(sizeof(Rect) == 16, "Rect has wrong size"); - -} // namespace Service::android -- cgit v1.2.3 From 3b13f5e43bc6dd89af80ffa857d3fb4aa5118116 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 19 Mar 2022 22:48:49 -0700 Subject: hle: nvflinger: buffer_queue_consumer: AcquireBuffer: Fix typo. --- src/core/hle/service/nvflinger/buffer_queue_consumer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp index cf12cceff..677bec932 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp @@ -49,7 +49,7 @@ Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer, if (expected_present.count() != 0) { constexpr auto MAX_REASONABLE_NSEC = 1000000000LL; // 1 second - // The expected_presenst_ns argument indicates when the buffer is expected to be + // The expected_present argument indicates when the buffer is expected to be // presented on-screen. while (core->queue.size() > 1 && !core->queue[0].is_auto_timestamp) { const auto& buffer_item{core->queue[1]}; -- cgit v1.2.3 From 81eefcaa7619c6807038f021b6da8a6ceabeaf25 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 19 Mar 2022 23:10:04 -0700 Subject: hle: nvflinger: Remove unused unordered_map include. --- src/core/hle/service/nvflinger/nvflinger.h | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 4f93ffe07..ed160f6f9 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -8,7 +8,6 @@ #include #include #include -#include #include #include "common/common_types.h" -- cgit v1.2.3 From 241ecae867347ff710641a3683362ee7f4c6a7a1 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 19 Mar 2022 23:10:46 -0700 Subject: hle: nvdrv: nvdata: Cleanup NvFence static assert. --- src/core/hle/service/nvdrv/nvdata.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h index 33cbd8904..3069c3c80 100644 --- a/src/core/hle/service/nvdrv/nvdata.h +++ b/src/core/hle/service/nvdrv/nvdata.h @@ -20,7 +20,7 @@ struct NvFence { s32 id; u32 value; }; -static_assert(sizeof(NvFence) == 8, "Fence has wrong size"); +static_assert(sizeof(NvFence) == 8, "NvFence has wrong size"); enum class NvResult : u32 { Success = 0x0, -- cgit v1.2.3 From c9d28c30f0a512d2a6fa1e6183d8a725d950881d Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 19 Mar 2022 23:15:13 -0700 Subject: hle: nvdrv: nvdata: buffer_queue_producer: Minor cleanup. --- .../service/nvflinger/buffer_queue_producer.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp index 5ea48431f..078091904 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp @@ -642,34 +642,34 @@ Status BufferQueueProducer::Query(NativeWindow what, s32* out_value) { return Status::NoInit; } - s32 value{}; + u32 value{}; switch (what) { case NativeWindow::Width: - value = static_cast(core->default_width); + value = core->default_width; break; case NativeWindow::Height: - value = static_cast(core->default_height); + value = core->default_height; break; case NativeWindow::Format: - value = static_cast(core->default_buffer_format); + value = static_cast(core->default_buffer_format); break; case NativeWindow::MinUndequeedBuffers: value = core->GetMinUndequeuedBufferCountLocked(false); break; case NativeWindow::StickyTransform: - value = static_cast(sticky_transform); + value = sticky_transform; break; case NativeWindow::ConsumerRunningBehind: value = (core->queue.size() > 1); break; case NativeWindow::ConsumerUsageBits: - value = static_cast(core->consumer_usage_bit); + value = core->consumer_usage_bit; break; case NativeWindow::BufferAge: if (core->buffer_age > INT32_MAX) { value = 0; } else { - value = static_cast(core->buffer_age); + value = static_cast(core->buffer_age); } break; default: @@ -679,7 +679,7 @@ Status BufferQueueProducer::Query(NativeWindow what, s32* out_value) { LOG_DEBUG(Service_NVFlinger, "what = {}, value = {}", what, value); - *out_value = value; + *out_value = static_cast(value); return Status::NoError; } @@ -917,12 +917,12 @@ void BufferQueueProducer::Transact(Kernel::HLERequestContext& ctx, TransactionId status = SetBufferCount(buffer_count); break; } - case TransactionId::GetBufferHistory: { + case TransactionId::GetBufferHistory: LOG_WARNING(Service_NVFlinger, "(STUBBED) called, transaction=GetBufferHistory"); break; - } default: - ASSERT_MSG(false, "Unimplemented"); + ASSERT_MSG(false, "Unimplemented TransactionId {}", code); + break; } parcel_out.Write(status); -- cgit v1.2.3 From 02dbb2ed54a51056f63355be019956fe02793459 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 20 Mar 2022 00:48:02 -0700 Subject: hle: vi: NativeWindow: Fix trivially copyable issues. --- src/core/hle/service/vi/vi.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index e49e1ae28..430cbc546 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -68,11 +68,11 @@ private: const u32 magic = 2; const u32 process_id = 1; const u32 id; - const INSERT_PADDING_WORDS(3); - const std::array dispdrv = {'d', 'i', 's', 'p', 'd', 'r', 'v', '\0'}; - const INSERT_PADDING_WORDS(2); + INSERT_PADDING_WORDS(3); + std::array dispdrv = {'d', 'i', 's', 'p', 'd', 'r', 'v', '\0'}; + INSERT_PADDING_WORDS(2); }; -static_assert(sizeof(NativeWindow) == 0x28, "ParcelData has wrong size"); +static_assert(sizeof(NativeWindow) == 0x28, "NativeWindow has wrong size"); class IHOSBinderDriver final : public ServiceFramework { public: -- cgit v1.2.3 From c64e1ae1041eebd44ef043658f091e204a0b8276 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 20 Mar 2022 00:48:32 -0700 Subject: hle: nvflinger: ConsumerBase: Mark ctor as explicit. --- src/core/hle/service/nvflinger/consumer_base.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/hle/service/nvflinger/consumer_base.h b/src/core/hle/service/nvflinger/consumer_base.h index d72160c2c..9ab949420 100644 --- a/src/core/hle/service/nvflinger/consumer_base.h +++ b/src/core/hle/service/nvflinger/consumer_base.h @@ -26,7 +26,7 @@ public: void Connect(bool controlled_by_app); protected: - ConsumerBase(std::unique_ptr consumer_); + explicit ConsumerBase(std::unique_ptr consumer_); virtual ~ConsumerBase(); virtual void OnFrameAvailable(const BufferItem& item) override; -- cgit v1.2.3