gl_rasterizer: Use GPU virtual addr when possible for framebuffers.

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