From b614f9d96f0d602d14ac8e8999727c386f5b816a Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 29 Jun 2018 22:59:52 -0400 Subject: [PATCH] gl_rasterizer: Use GPU virtual addr when possible for framebuffers. --- .../service/nvdrv/devices/nvdisp_disp0.cpp | 18 +++++++---- .../service/nvdrv/devices/nvhost_as_gpu.cpp | 10 ++++--- src/core/hle/service/nvdrv/devices/nvmap.cpp | 9 +----- src/core/hle/service/nvdrv/devices/nvmap.h | 7 ++--- src/video_core/gpu.h | 3 +- src/video_core/rasterizer_interface.h | 5 ++-- .../renderer_opengl/gl_rasterizer.cpp | 2 +- .../renderer_opengl/gl_rasterizer.h | 5 ++-- .../renderer_opengl/gl_rasterizer_cache.cpp | 30 ++++++++----------- .../renderer_opengl/gl_rasterizer_cache.h | 6 ++-- .../renderer_opengl/renderer_opengl.cpp | 15 +++++----- 11 files changed, 53 insertions(+), 57 deletions(-) diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 103e66d0c3..0f470b5f90 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -19,14 +19,20 @@ u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector& input, std::vector void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride, NVFlinger::BufferQueue::BufferTransformFlags transform) { - VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle); - NGLOG_WARNING(Service, - "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}", - addr, offset, width, height, stride, format); + + const auto& object{nvmap_dev->GetObject(buffer_handle)}; + ASSERT(object); + ASSERT(object->status == nvmap::Object::Status::Allocated); using PixelFormat = Tegra::FramebufferConfig::PixelFormat; - const Tegra::FramebufferConfig framebuffer{ - addr, offset, width, height, stride, static_cast(format), transform}; + const Tegra::FramebufferConfig framebuffer{object->cpu_addr, + object->gpu_addr, + offset, + width, + height, + stride, + static_cast(format), + transform}; Core::System::GetInstance().perf_stats.EndGameFrame(); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index c1eea861df..d015257754 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -85,8 +85,8 @@ u32 nvhost_as_gpu::Remap(const std::vector& input, std::vector& output) u64 size = static_cast(entry.pages) << 0x10; ASSERT(size <= object->size); - Tegra::GPUVAddr returned = gpu.memory_manager->MapBufferEx(object->addr, offset, size); - ASSERT(returned == offset); + object->gpu_addr = gpu.memory_manager->MapBufferEx(object->cpu_addr, offset, size); + ASSERT(object->gpu_addr == offset); } std::memcpy(output.data(), entries.data(), output.size()); return 0; @@ -122,10 +122,12 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector& input, std::vector& ou auto& gpu = Core::System::GetInstance().GPU(); if (params.flags & 1) { - params.offset = gpu.memory_manager->MapBufferEx(object->addr, params.offset, object->size); + object->gpu_addr = + gpu.memory_manager->MapBufferEx(object->cpu_addr, params.offset, object->size); } else { - params.offset = gpu.memory_manager->MapBufferEx(object->addr, object->size); + object->gpu_addr = gpu.memory_manager->MapBufferEx(object->cpu_addr, object->size); } + params.offset = object->gpu_addr; // Create a new mapping entry for this operation. ASSERT_MSG(buffer_mappings.find(params.offset) == buffer_mappings.end(), diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 23fe981901..1b9c98dea7 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -11,13 +11,6 @@ namespace Service::Nvidia::Devices { -VAddr nvmap::GetObjectAddress(u32 handle) const { - auto object = GetObject(handle); - ASSERT(object); - ASSERT(object->status == Object::Status::Allocated); - return object->addr; -} - u32 nvmap::ioctl(Ioctl command, const std::vector& input, std::vector& output) { switch (static_cast(command.raw)) { case IoctlCommand::Create: @@ -70,7 +63,7 @@ u32 nvmap::IocAlloc(const std::vector& input, std::vector& output) { object->flags = params.flags; object->align = params.align; object->kind = params.kind; - object->addr = params.addr; + object->cpu_addr = params.addr; object->status = Object::Status::Allocated; NGLOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr); diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index 39fafaa7cf..7d077b9954 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h @@ -11,6 +11,7 @@ #include "common/common_types.h" #include "common/swap.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" +#include "video_core/memory_manager.h" namespace Service::Nvidia::Devices { @@ -19,9 +20,6 @@ public: nvmap() = default; ~nvmap() override = default; - /// Returns the allocated address of an nvmap object given its handle. - VAddr GetObjectAddress(u32 handle) const; - u32 ioctl(Ioctl command, const std::vector& input, std::vector& output) override; /// Represents an nvmap object. @@ -32,7 +30,8 @@ public: u32 flags; u32 align; u8 kind; - VAddr addr; + VAddr cpu_addr; + Tegra::GPUVAddr gpu_addr; Status status; u32 refcount; }; diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 7b4e9b8423..7b3a13a79d 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -48,7 +48,8 @@ struct FramebufferConfig { UNREACHABLE(); } - VAddr address; + VAddr cpu_addr; + Tegra::GPUVAddr gpu_addr; u32 offset; u32 width; u32 height; diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index 145e583344..3e61bad4b8 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h @@ -51,8 +51,9 @@ public: } /// Attempt to use a faster method to display the framebuffer to screen - virtual bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, - u32 pixel_stride, ScreenInfo& screen_info) { + virtual bool AccelerateDisplay(const Tegra::FramebufferConfig& config, + Tegra::GPUVAddr framebuffer_addr, u32 pixel_stride, + ScreenInfo& screen_info) { return false; } diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 62ee45a368..77c94798e0 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -482,7 +482,7 @@ bool RasterizerOpenGL::AccelerateFill(const void* config) { } bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config, - VAddr framebuffer_addr, u32 pixel_stride, + Tegra::GPUVAddr framebuffer_addr, u32 pixel_stride, ScreenInfo& screen_info) { if (!framebuffer_addr) { return {}; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 621200f03f..6e3fb2023e 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -36,8 +36,9 @@ public: bool AccelerateDisplayTransfer(const void* config) override; bool AccelerateTextureCopy(const void* config) override; bool AccelerateFill(const void* config) override; - bool AccelerateDisplay(const Tegra::FramebufferConfig& framebuffer, VAddr framebuffer_addr, - u32 pixel_stride, ScreenInfo& screen_info) override; + bool AccelerateDisplay(const Tegra::FramebufferConfig& framebuffer, + Tegra::GPUVAddr framebuffer_addr, u32 pixel_stride, + ScreenInfo& screen_info) override; bool AccelerateDrawBatch(bool is_indexed) override; /// OpenGL shader generated for a given Maxwell register state diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 63f5999eae..4746b54ad3 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -33,8 +33,10 @@ struct FormatTuple { /*static*/ SurfaceParams SurfaceParams::CreateForTexture( const Tegra::Texture::FullTextureInfo& config) { + const auto& gpu{Core::System::GetInstance().GPU()}; SurfaceParams params{}; params.addr = config.tic.Address(); + params.cpu_addr = gpu.memory_manager->GpuToCpuAddress(params.addr).get_value_or(0); params.is_tiled = config.tic.IsTiled(); params.block_height = params.is_tiled ? config.tic.BlockHeight() : 0, params.pixel_format = PixelFormatFromTextureFormat(config.tic.format); @@ -50,8 +52,10 @@ struct FormatTuple { /*static*/ SurfaceParams SurfaceParams::CreateForFramebuffer( const Tegra::Engines::Maxwell3D::Regs::RenderTargetConfig& config) { + const auto& gpu{Core::System::GetInstance().GPU()}; SurfaceParams params{}; params.addr = config.Address(); + params.cpu_addr = *gpu.memory_manager->GpuToCpuAddress(params.addr); params.is_tiled = true; params.block_height = Tegra::Texture::TICEntry::DefaultBlockHeight; params.pixel_format = PixelFormatFromRenderTargetFormat(config.format); @@ -97,11 +101,6 @@ static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType return {}; } -VAddr SurfaceParams::GetCpuAddr() const { - const auto& gpu = Core::System::GetInstance().GPU(); - return *gpu.memory_manager->GpuToCpuAddress(addr); -} - static bool IsPixelFormatASTC(PixelFormat format) { switch (format) { case PixelFormat::ASTC_2D_4X4: @@ -228,7 +227,7 @@ MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64 void CachedSurface::LoadGLBuffer() { ASSERT(params.type != SurfaceType::Fill); - u8* const texture_src_data = Memory::GetPointer(params.GetCpuAddr()); + u8* const texture_src_data = Memory::GetPointer(params.cpu_addr); ASSERT(texture_src_data); @@ -254,7 +253,7 @@ void CachedSurface::LoadGLBuffer() { MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); void CachedSurface::FlushGLBuffer() { - u8* const dst_buffer = Memory::GetPointer(params.GetCpuAddr()); + u8* const dst_buffer = Memory::GetPointer(params.cpu_addr); ASSERT(dst_buffer); ASSERT(gl_buffer.size() == @@ -450,7 +449,7 @@ void RasterizerCacheOpenGL::MarkSurfaceAsDirty(const Surface& surface) { } Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params) { - if (params.addr == 0 || params.height * params.width == 0) { + if (params.cpu_addr == 0 || params.height * params.width == 0) { return {}; } @@ -473,19 +472,16 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params) { return surface; } -Surface RasterizerCacheOpenGL::TryFindFramebufferSurface(VAddr cpu_addr) const { - // Tries to find the GPU address of a framebuffer based on the CPU address. This is because - // final output framebuffers are specified by CPU address, but internally our GPU cache uses - // GPU addresses. We iterate through all cached framebuffers, and compare their starting CPU - // address to the one provided. This is obviously not great, and won't work if the - // framebuffer overlaps surfaces. +Surface RasterizerCacheOpenGL::TryFindFramebufferSurface(Tegra::GPUVAddr gpu_addr) const { + // Tries to find a framebuffer based on a GPU address. We iterate through all cached + // framebuffers, and compare their starting GPU address to the one provided. This is obviously + // not great, and won't work if the framebuffer overlaps surfaces. std::vector surfaces; for (const auto& surface : surface_cache) { const auto& params = surface.second->GetSurfaceParams(); - const VAddr surface_cpu_addr = params.GetCpuAddr(); - if (cpu_addr >= surface_cpu_addr && cpu_addr < (surface_cpu_addr + params.size_in_bytes)) { - ASSERT_MSG(cpu_addr == surface_cpu_addr, "overlapping surfaces are unsupported"); + if (gpu_addr >= params.addr && gpu_addr < (params.addr + params.size_in_bytes)) { + ASSERT_MSG(gpu_addr == params.addr, "overlapping surfaces are unsupported"); surfaces.push_back(surface.second); } } diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 85e7c88889..a06129e73b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -256,9 +256,6 @@ struct SurfaceParams { GetFormatBpp(pixel_format) / CHAR_BIT; } - /// Returns the CPU virtual address for this surface - VAddr GetCpuAddr() const; - /// Returns true if the specified region overlaps with this surface's region in Switch memory bool IsOverlappingRegion(Tegra::GPUVAddr region_addr, size_t region_size) const { return addr <= (region_addr + region_size) && region_addr <= (addr + size_in_bytes); @@ -272,6 +269,7 @@ struct SurfaceParams { const Tegra::Engines::Maxwell3D::Regs::RenderTargetConfig& config); Tegra::GPUVAddr addr; + VAddr cpu_addr; bool is_tiled; u32 block_height; PixelFormat pixel_format; @@ -350,7 +348,7 @@ public: void MarkSurfaceAsDirty(const Surface& surface); /// Tries to find a framebuffer GPU address based on the provided CPU address - Surface TryFindFramebufferSurface(VAddr cpu_addr) const; + Surface TryFindFramebufferSurface(Tegra::GPUVAddr gpu_addr) const; /// Write any cached resources overlapping the region back to memory (if dirty) void FlushRegion(Tegra::GPUVAddr addr, size_t size); diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index e3bb2cbb87..c75a7bb7e1 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -137,8 +137,6 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf ScreenInfo& screen_info) { const u32 bytes_per_pixel{Tegra::FramebufferConfig::BytesPerPixel(framebuffer.pixel_format)}; const u64 size_in_bytes{framebuffer.stride * framebuffer.height * bytes_per_pixel}; - const VAddr framebuffer_addr{framebuffer.address + framebuffer.offset}; - // Framebuffer orientation handling framebuffer_transform_flags = framebuffer.transform_flags; @@ -146,17 +144,18 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf // only allows rows to have a memory alignement of 4. ASSERT(framebuffer.stride % 4 == 0); - if (!Rasterizer()->AccelerateDisplay(framebuffer, framebuffer_addr, framebuffer.stride, - screen_info)) { + if (!Rasterizer()->AccelerateDisplay(framebuffer, framebuffer.gpu_addr + framebuffer.offset, + framebuffer.stride, screen_info)) { + // Reset the screen info's display texture to its own permanent texture screen_info.display_texture = screen_info.texture.resource.handle; - Memory::RasterizerFlushVirtualRegion(framebuffer_addr, size_in_bytes, - Memory::FlushMode::Flush); + const VAddr cpu_addr{framebuffer.cpu_addr + framebuffer.offset}; + Memory::RasterizerFlushVirtualRegion(cpu_addr, size_in_bytes, Memory::FlushMode::Flush); VideoCore::MortonCopyPixels128(framebuffer.width, framebuffer.height, bytes_per_pixel, 4, - Memory::GetPointer(framebuffer_addr), - gl_framebuffer_data.data(), true); + Memory::GetPointer(cpu_addr), gl_framebuffer_data.data(), + true); state.texture_units[0].texture_2d = screen_info.texture.resource.handle; state.Apply();