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,
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<PixelFormat>(format), transform};
const Tegra::FramebufferConfig framebuffer{object->cpu_addr,
object->gpu_addr,
offset,
width,
height,
stride,
static_cast<PixelFormat>(format),
transform};
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;
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<u8>& input, std::vector<u8>& 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(),
+1 -8
View File
@@ -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<u8>& input, std::vector<u8>& output) {
switch (static_cast<IoctlCommand>(command.raw)) {
case IoctlCommand::Create:
@@ -70,7 +63,7 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& 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);
+3 -4
View File
@@ -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<u8>& input, std::vector<u8>& 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;
};
+2 -1
View File
@@ -48,7 +48,8 @@ struct FramebufferConfig {
UNREACHABLE();
}
VAddr address;
VAddr cpu_addr;
Tegra::GPUVAddr gpu_addr;
u32 offset;
u32 width;
u32 height;
+3 -2
View File
@@ -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;
}
@@ -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 {};
@@ -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
@@ -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<Surface> 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);
}
}
@@ -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);
@@ -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();