From 3f9f047375dd9aae7eadcb957747fa8db01544bf Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 24 Jun 2018 17:42:29 -0400 Subject: gl_rasterizer: Implement AccelerateDisplay to forward textures to framebuffers. --- src/video_core/renderer_opengl/gl_rasterizer.cpp | 25 ++++++++++++++++++--- .../renderer_opengl/gl_rasterizer_cache.cpp | 26 ++++++++++++++++++++++ .../renderer_opengl/gl_rasterizer_cache.h | 11 +++++++++ src/video_core/renderer_opengl/renderer_opengl.cpp | 1 - src/video_core/renderer_opengl/renderer_opengl.h | 2 +- 5 files changed, 60 insertions(+), 5 deletions(-) (limited to 'src/video_core/renderer_opengl') diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index bc463fc30..f9b0ce434 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -468,11 +468,30 @@ bool RasterizerOpenGL::AccelerateFill(const void* config) { return true; } -bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& framebuffer, +bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, u32 pixel_stride, ScreenInfo& screen_info) { - // TODO(bunnei): ImplementMe - return false; + if (!framebuffer_addr) { + return {}; + } + + MICROPROFILE_SCOPE(OpenGL_CacheManagement); + + const auto& surface{res_cache.TryFindFramebufferSurface(framebuffer_addr)}; + if (!surface) { + return {}; + } + + // Verify that the cached surface is the same size and format as the requested framebuffer + const auto& params{surface->GetSurfaceParams()}; + const auto& pixel_format{SurfaceParams::PixelFormatFromGPUPixelFormat(config.pixel_format)}; + ASSERT_MSG(params.width == config.width, "Framebuffer width is different"); + ASSERT_MSG(params.height == config.height, "Framebuffer height is different"); + ASSERT_MSG(params.pixel_format == pixel_format, "Framebuffer pixel_format is different"); + + screen_info.display_texture = surface->Texture().handle; + + return true; } void RasterizerOpenGL::SamplerInfo::Create() { diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 882490f47..919931d64 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -436,3 +436,29 @@ 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. + + 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"); + surfaces.push_back(surface.second); + } + } + + if (surfaces.empty()) { + return {}; + } + + ASSERT_MSG(surfaces.size() == 1, ">1 surface is unsupported"); + + return surfaces[0]; +} diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 9f1209b0f..53ff2722d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -220,6 +220,16 @@ struct SurfaceParams { } } + static PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) { + switch (format) { + case Tegra::FramebufferConfig::PixelFormat::ABGR8: + return PixelFormat::ABGR8; + default: + NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast(format)); + UNREACHABLE(); + } + } + static SurfaceType GetFormatType(PixelFormat pixel_format) { if (static_cast(pixel_format) < MaxPixelFormat) { return SurfaceType::ColorTexture; @@ -302,6 +312,7 @@ public: const MathUtil::Rectangle& viewport); void LoadSurface(const Surface& surface); void FlushSurface(const Surface& surface); + Surface TryFindFramebufferSurface(VAddr cpu_addr) const; private: Surface GetSurface(const SurfaceParams& params); diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index f33766bfd..e3bb2cbb8 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -150,7 +150,6 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf screen_info)) { // Reset the screen info's display texture to its own permanent texture screen_info.display_texture = screen_info.texture.resource.handle; - screen_info.display_texcoords = MathUtil::Rectangle(0.f, 0.f, 1.f, 1.f); Memory::RasterizerFlushVirtualRegion(framebuffer_addr, size_in_bytes, Memory::FlushMode::Flush); diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 2cc6d9a00..21f0d298c 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -27,7 +27,7 @@ struct TextureInfo { /// Structure used for storing information about the display target for the Switch screen struct ScreenInfo { GLuint display_texture; - MathUtil::Rectangle display_texcoords; + const MathUtil::Rectangle display_texcoords{0.0f, 0.0f, 1.0f, 1.0f}; TextureInfo texture; }; -- cgit v1.2.3