GPU: Implement a Fence Manager.
This commit is contained in:
		@@ -23,6 +23,7 @@ add_library(video_core STATIC
 | 
			
		||||
    engines/shader_bytecode.h
 | 
			
		||||
    engines/shader_header.h
 | 
			
		||||
    engines/shader_type.h
 | 
			
		||||
    fence_manager.h
 | 
			
		||||
    gpu.cpp
 | 
			
		||||
    gpu.h
 | 
			
		||||
    gpu_asynch.cpp
 | 
			
		||||
@@ -51,6 +52,8 @@ add_library(video_core STATIC
 | 
			
		||||
    renderer_opengl/gl_buffer_cache.h
 | 
			
		||||
    renderer_opengl/gl_device.cpp
 | 
			
		||||
    renderer_opengl/gl_device.h
 | 
			
		||||
    renderer_opengl/gl_fence_manager.cpp
 | 
			
		||||
    renderer_opengl/gl_fence_manager.h
 | 
			
		||||
    renderer_opengl/gl_framebuffer_cache.cpp
 | 
			
		||||
    renderer_opengl/gl_framebuffer_cache.h
 | 
			
		||||
    renderer_opengl/gl_rasterizer.cpp
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										97
									
								
								src/video_core/fence_manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								src/video_core/fence_manager.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,97 @@
 | 
			
		||||
// Copyright 2020 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <queue>
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/memory.h"
 | 
			
		||||
#include "core/settings.h"
 | 
			
		||||
#include "video_core/gpu.h"
 | 
			
		||||
#include "video_core/memory_manager.h"
 | 
			
		||||
#include "video_core/rasterizer_interface.h"
 | 
			
		||||
 | 
			
		||||
namespace VideoCommon {
 | 
			
		||||
 | 
			
		||||
class FenceBase {
 | 
			
		||||
public:
 | 
			
		||||
    FenceBase(GPUVAddr address, u32 payload) : address{address}, payload{payload} {}
 | 
			
		||||
 | 
			
		||||
    constexpr GPUVAddr GetAddress() const {
 | 
			
		||||
        return address;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    constexpr u32 GetPayload() const {
 | 
			
		||||
        return payload;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    GPUVAddr address;
 | 
			
		||||
    u32 payload;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename TFence, typename TTextureCache>
 | 
			
		||||
class FenceManager {
 | 
			
		||||
public:
 | 
			
		||||
    void SignalFence(GPUVAddr addr, u32 value) {
 | 
			
		||||
        TryReleasePendingFences();
 | 
			
		||||
        TFence new_fence = CreateFence(addr, value);
 | 
			
		||||
        QueueFence(new_fence);
 | 
			
		||||
        fences.push(new_fence);
 | 
			
		||||
        texture_cache.CommitAsyncFlushes();
 | 
			
		||||
        rasterizer.FlushCommands();
 | 
			
		||||
        rasterizer.SyncGuestHost();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void WaitPendingFences() {
 | 
			
		||||
        while (!fences.empty()) {
 | 
			
		||||
            TFence& current_fence = fences.front();
 | 
			
		||||
            WaitFence(current_fence);
 | 
			
		||||
            texture_cache.PopAsyncFlushes();
 | 
			
		||||
            auto& gpu{system.GPU()};
 | 
			
		||||
            auto& memory_manager{gpu.MemoryManager()};
 | 
			
		||||
            memory_manager.Write<u32>(current_fence->GetAddress(), current_fence->GetPayload());
 | 
			
		||||
            fences.pop();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    FenceManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
 | 
			
		||||
                 TTextureCache& texture_cache)
 | 
			
		||||
        : system{system}, rasterizer{rasterizer}, texture_cache{texture_cache} {}
 | 
			
		||||
 | 
			
		||||
    virtual TFence CreateFence(GPUVAddr addr, u32 value) = 0;
 | 
			
		||||
    virtual void QueueFence(TFence& fence) = 0;
 | 
			
		||||
    virtual bool IsFenceSignaled(TFence& fence) = 0;
 | 
			
		||||
    virtual void WaitFence(TFence& fence) = 0;
 | 
			
		||||
 | 
			
		||||
    Core::System& system;
 | 
			
		||||
    VideoCore::RasterizerInterface& rasterizer;
 | 
			
		||||
    TTextureCache& texture_cache;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void TryReleasePendingFences() {
 | 
			
		||||
        while (!fences.empty()) {
 | 
			
		||||
            TFence& current_fence = fences.front();
 | 
			
		||||
            if (!IsFenceSignaled(current_fence)) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            texture_cache.PopAsyncFlushes();
 | 
			
		||||
            auto& gpu{system.GPU()};
 | 
			
		||||
            auto& memory_manager{gpu.MemoryManager()};
 | 
			
		||||
            memory_manager.Write<u32>(current_fence->GetAddress(), current_fence->GetPayload());
 | 
			
		||||
            fences.pop();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::queue<TFence> fences;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace VideoCommon
 | 
			
		||||
							
								
								
									
										55
									
								
								src/video_core/renderer_opengl/gl_fence_manager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/video_core/renderer_opengl/gl_fence_manager.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
// Copyright 2020 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
 | 
			
		||||
#include "video_core/renderer_opengl/gl_fence_manager.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenGL {
 | 
			
		||||
 | 
			
		||||
GLInnerFence::GLInnerFence(GPUVAddr address, u32 payload)
 | 
			
		||||
    : VideoCommon::FenceBase(address, payload), sync_object{} {}
 | 
			
		||||
 | 
			
		||||
GLInnerFence::~GLInnerFence() = default;
 | 
			
		||||
 | 
			
		||||
void GLInnerFence::Queue() {
 | 
			
		||||
    ASSERT(sync_object.handle == 0);
 | 
			
		||||
    sync_object.Create();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool GLInnerFence::IsSignaled() const {
 | 
			
		||||
    ASSERT(sync_object.handle != 0);
 | 
			
		||||
    GLsizei length;
 | 
			
		||||
    GLint sync_status;
 | 
			
		||||
    glGetSynciv(sync_object.handle, GL_SYNC_STATUS, sizeof(GLint), &length, &sync_status);
 | 
			
		||||
    return sync_status == GL_SIGNALED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLInnerFence::Wait() {
 | 
			
		||||
    ASSERT(sync_object.handle != 0);
 | 
			
		||||
    while (glClientWaitSync(sync_object.handle, 0, 1000) == GL_TIMEOUT_EXPIRED)
 | 
			
		||||
        ;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FenceManagerOpenGL::FenceManagerOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
 | 
			
		||||
                               TextureCacheOpenGL& texture_cache)
 | 
			
		||||
    : GenericFenceManager(system, rasterizer, texture_cache) {}
 | 
			
		||||
 | 
			
		||||
Fence FenceManagerOpenGL::CreateFence(GPUVAddr addr, u32 value) {
 | 
			
		||||
    return std::make_shared<GLInnerFence>(addr, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FenceManagerOpenGL::QueueFence(Fence& fence) {
 | 
			
		||||
    fence->Queue();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool FenceManagerOpenGL::IsFenceSignaled(Fence& fence) {
 | 
			
		||||
    return fence->IsSignaled();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FenceManagerOpenGL::WaitFence(Fence& fence) {
 | 
			
		||||
    fence->Wait();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace OpenGL
 | 
			
		||||
							
								
								
									
										47
									
								
								src/video_core/renderer_opengl/gl_fence_manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/video_core/renderer_opengl/gl_fence_manager.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
// Copyright 2020 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <glad/glad.h>
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "video_core/fence_manager.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_texture_cache.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenGL {
 | 
			
		||||
 | 
			
		||||
class GLInnerFence : public VideoCommon::FenceBase {
 | 
			
		||||
public:
 | 
			
		||||
    GLInnerFence(GPUVAddr address, u32 payload);
 | 
			
		||||
    ~GLInnerFence();
 | 
			
		||||
 | 
			
		||||
    void Queue();
 | 
			
		||||
 | 
			
		||||
    bool IsSignaled() const;
 | 
			
		||||
 | 
			
		||||
    void Wait();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    OGLSync sync_object;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
using Fence = std::shared_ptr<GLInnerFence>;
 | 
			
		||||
using GenericFenceManager = VideoCommon::FenceManager<Fence, TextureCacheOpenGL>;
 | 
			
		||||
 | 
			
		||||
class FenceManagerOpenGL final : public GenericFenceManager {
 | 
			
		||||
public:
 | 
			
		||||
    FenceManagerOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
 | 
			
		||||
                   TextureCacheOpenGL& texture_cache);
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    Fence CreateFence(GPUVAddr addr, u32 value) override;
 | 
			
		||||
    void QueueFence(Fence& fence) override;
 | 
			
		||||
    bool IsFenceSignaled(Fence& fence) override;
 | 
			
		||||
    void WaitFence(Fence& fence) override;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace OpenGL
 | 
			
		||||
@@ -101,7 +101,8 @@ RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWind
 | 
			
		||||
    : RasterizerAccelerated{system.Memory()}, texture_cache{system, *this, device, state_tracker},
 | 
			
		||||
      shader_cache{*this, system, emu_window, device}, query_cache{system, *this}, system{system},
 | 
			
		||||
      screen_info{info}, program_manager{program_manager}, state_tracker{state_tracker},
 | 
			
		||||
      buffer_cache{*this, system, device, STREAM_BUFFER_SIZE} {
 | 
			
		||||
      buffer_cache{*this, system, device, STREAM_BUFFER_SIZE}, fence_manager{system, *this,
 | 
			
		||||
                                                                             texture_cache} {
 | 
			
		||||
    CheckExtensions();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -677,31 +678,11 @@ void RasterizerOpenGL::SyncGuestHost() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SignalFence(GPUVAddr addr, u32 value) {
 | 
			
		||||
    if (!fences.empty()) {
 | 
			
		||||
        const std::pair<GPUVAddr, u32>& current_fence = fences.front();
 | 
			
		||||
        const auto [address, payload] = current_fence;
 | 
			
		||||
        texture_cache.PopAsyncFlushes();
 | 
			
		||||
        auto& gpu{system.GPU()};
 | 
			
		||||
        auto& memory_manager{gpu.MemoryManager()};
 | 
			
		||||
        memory_manager.Write<u32>(address, payload);
 | 
			
		||||
        fences.pop_front();
 | 
			
		||||
    }
 | 
			
		||||
    fences.emplace_back(addr, value);
 | 
			
		||||
    texture_cache.CommitAsyncFlushes();
 | 
			
		||||
    FlushCommands();
 | 
			
		||||
    SyncGuestHost();
 | 
			
		||||
    fence_manager.SignalFence(addr, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::ReleaseFences() {
 | 
			
		||||
    while (!fences.empty()) {
 | 
			
		||||
        const std::pair<GPUVAddr, u32>& current_fence = fences.front();
 | 
			
		||||
        const auto [address, payload] = current_fence;
 | 
			
		||||
        texture_cache.PopAsyncFlushes();
 | 
			
		||||
        auto& gpu{system.GPU()};
 | 
			
		||||
        auto& memory_manager{gpu.MemoryManager()};
 | 
			
		||||
        memory_manager.Write<u32>(address, payload);
 | 
			
		||||
        fences.pop_front();
 | 
			
		||||
    }
 | 
			
		||||
    fence_manager.WaitPendingFences();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::FlushAndInvalidateRegion(VAddr addr, u64 size) {
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,7 @@
 | 
			
		||||
#include "video_core/rasterizer_interface.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_buffer_cache.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_device.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_fence_manager.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_framebuffer_cache.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_query_cache.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
 | 
			
		||||
@@ -226,6 +227,7 @@ private:
 | 
			
		||||
    SamplerCacheOpenGL sampler_cache;
 | 
			
		||||
    FramebufferCacheOpenGL framebuffer_cache;
 | 
			
		||||
    QueryCache query_cache;
 | 
			
		||||
    FenceManagerOpenGL fence_manager;
 | 
			
		||||
 | 
			
		||||
    Core::System& system;
 | 
			
		||||
    ScreenInfo& screen_info;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user