mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu.git
				synced 2025-05-12 00:45:25 +00:00 
			
		
		
		
	renderer_gl: Port over gl_stream_buffer module from Citra.
This commit is contained in:
		
							parent
							
								
									a1cf5020e6
								
							
						
					
					
						commit
						0e4b9cdde4
					
				@ -18,6 +18,8 @@ add_library(video_core STATIC
 | 
			
		||||
    renderer_opengl/gl_shader_util.h
 | 
			
		||||
    renderer_opengl/gl_state.cpp
 | 
			
		||||
    renderer_opengl/gl_state.h
 | 
			
		||||
    renderer_opengl/gl_stream_buffer.cpp
 | 
			
		||||
    renderer_opengl/gl_stream_buffer.h
 | 
			
		||||
    renderer_opengl/renderer_opengl.cpp
 | 
			
		||||
    renderer_opengl/renderer_opengl.h
 | 
			
		||||
    utils.h
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										182
									
								
								src/video_core/renderer_opengl/gl_stream_buffer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								src/video_core/renderer_opengl/gl_stream_buffer.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,182 @@
 | 
			
		||||
// Copyright 2018 Citra Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include <deque>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "common/alignment.h"
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_state.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_stream_buffer.h"
 | 
			
		||||
 | 
			
		||||
class OrphanBuffer : public OGLStreamBuffer {
 | 
			
		||||
public:
 | 
			
		||||
    explicit OrphanBuffer(GLenum target) : OGLStreamBuffer(target) {}
 | 
			
		||||
    ~OrphanBuffer() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void Create(size_t size, size_t sync_subdivide) override;
 | 
			
		||||
    void Release() override;
 | 
			
		||||
 | 
			
		||||
    std::pair<u8*, GLintptr> Map(size_t size, size_t alignment) override;
 | 
			
		||||
    void Unmap() override;
 | 
			
		||||
 | 
			
		||||
    std::vector<u8> data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class StorageBuffer : public OGLStreamBuffer {
 | 
			
		||||
public:
 | 
			
		||||
    explicit StorageBuffer(GLenum target) : OGLStreamBuffer(target) {}
 | 
			
		||||
    ~StorageBuffer() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void Create(size_t size, size_t sync_subdivide) override;
 | 
			
		||||
    void Release() override;
 | 
			
		||||
 | 
			
		||||
    std::pair<u8*, GLintptr> Map(size_t size, size_t alignment) override;
 | 
			
		||||
    void Unmap() override;
 | 
			
		||||
 | 
			
		||||
    struct Fence {
 | 
			
		||||
        OGLSync sync;
 | 
			
		||||
        size_t offset;
 | 
			
		||||
    };
 | 
			
		||||
    std::deque<Fence> head;
 | 
			
		||||
    std::deque<Fence> tail;
 | 
			
		||||
 | 
			
		||||
    u8* mapped_ptr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
OGLStreamBuffer::OGLStreamBuffer(GLenum target) {
 | 
			
		||||
    gl_target = target;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GLuint OGLStreamBuffer::GetHandle() const {
 | 
			
		||||
    return gl_buffer.handle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::unique_ptr<OGLStreamBuffer> OGLStreamBuffer::MakeBuffer(bool storage_buffer, GLenum target) {
 | 
			
		||||
    if (storage_buffer) {
 | 
			
		||||
        return std::make_unique<StorageBuffer>(target);
 | 
			
		||||
    }
 | 
			
		||||
    return std::make_unique<OrphanBuffer>(target);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
OrphanBuffer::~OrphanBuffer() {
 | 
			
		||||
    Release();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OrphanBuffer::Create(size_t size, size_t /*sync_subdivide*/) {
 | 
			
		||||
    buffer_pos = 0;
 | 
			
		||||
    buffer_size = size;
 | 
			
		||||
    data.resize(buffer_size);
 | 
			
		||||
 | 
			
		||||
    if (gl_buffer.handle == 0) {
 | 
			
		||||
        gl_buffer.Create();
 | 
			
		||||
        glBindBuffer(gl_target, gl_buffer.handle);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    glBufferData(gl_target, static_cast<GLsizeiptr>(buffer_size), nullptr, GL_STREAM_DRAW);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OrphanBuffer::Release() {
 | 
			
		||||
    gl_buffer.Release();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::pair<u8*, GLintptr> OrphanBuffer::Map(size_t size, size_t alignment) {
 | 
			
		||||
    buffer_pos = Common::AlignUp(buffer_pos, alignment);
 | 
			
		||||
 | 
			
		||||
    if (buffer_pos + size > buffer_size) {
 | 
			
		||||
        Create(std::max(buffer_size, size), 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    mapped_size = size;
 | 
			
		||||
    return std::make_pair(&data[buffer_pos], static_cast<GLintptr>(buffer_pos));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OrphanBuffer::Unmap() {
 | 
			
		||||
    glBufferSubData(gl_target, static_cast<GLintptr>(buffer_pos),
 | 
			
		||||
                    static_cast<GLsizeiptr>(mapped_size), &data[buffer_pos]);
 | 
			
		||||
    buffer_pos += mapped_size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
StorageBuffer::~StorageBuffer() {
 | 
			
		||||
    Release();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StorageBuffer::Create(size_t size, size_t sync_subdivide) {
 | 
			
		||||
    if (gl_buffer.handle != 0)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    buffer_pos = 0;
 | 
			
		||||
    buffer_size = size;
 | 
			
		||||
    buffer_sync_subdivide = std::max<size_t>(sync_subdivide, 1);
 | 
			
		||||
 | 
			
		||||
    gl_buffer.Create();
 | 
			
		||||
    glBindBuffer(gl_target, gl_buffer.handle);
 | 
			
		||||
 | 
			
		||||
    glBufferStorage(gl_target, static_cast<GLsizeiptr>(buffer_size), nullptr,
 | 
			
		||||
                    GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT);
 | 
			
		||||
    mapped_ptr = reinterpret_cast<u8*>(
 | 
			
		||||
        glMapBufferRange(gl_target, 0, static_cast<GLsizeiptr>(buffer_size),
 | 
			
		||||
                         GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_FLUSH_EXPLICIT_BIT));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StorageBuffer::Release() {
 | 
			
		||||
    if (gl_buffer.handle == 0)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    glUnmapBuffer(gl_target);
 | 
			
		||||
 | 
			
		||||
    gl_buffer.Release();
 | 
			
		||||
    head.clear();
 | 
			
		||||
    tail.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::pair<u8*, GLintptr> StorageBuffer::Map(size_t size, size_t alignment) {
 | 
			
		||||
    ASSERT(size <= buffer_size);
 | 
			
		||||
 | 
			
		||||
    OGLSync sync;
 | 
			
		||||
 | 
			
		||||
    buffer_pos = Common::AlignUp(buffer_pos, alignment);
 | 
			
		||||
    size_t effective_offset = Common::AlignDown(buffer_pos, buffer_sync_subdivide);
 | 
			
		||||
 | 
			
		||||
    if (!head.empty() &&
 | 
			
		||||
        (effective_offset > head.back().offset || buffer_pos + size > buffer_size)) {
 | 
			
		||||
        ASSERT(head.back().sync.handle == 0);
 | 
			
		||||
        head.back().sync.Create();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (buffer_pos + size > buffer_size) {
 | 
			
		||||
        if (!tail.empty()) {
 | 
			
		||||
            std::swap(sync, tail.back().sync);
 | 
			
		||||
            tail.clear();
 | 
			
		||||
        }
 | 
			
		||||
        std::swap(tail, head);
 | 
			
		||||
        buffer_pos = 0;
 | 
			
		||||
        effective_offset = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    while (!tail.empty() && buffer_pos + size > tail.front().offset) {
 | 
			
		||||
        std::swap(sync, tail.front().sync);
 | 
			
		||||
        tail.pop_front();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (sync.handle != 0) {
 | 
			
		||||
        glClientWaitSync(sync.handle, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
 | 
			
		||||
        sync.Release();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (head.empty() || effective_offset > head.back().offset) {
 | 
			
		||||
        head.emplace_back();
 | 
			
		||||
        head.back().offset = effective_offset;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    mapped_size = size;
 | 
			
		||||
    return std::make_pair(&mapped_ptr[buffer_pos], static_cast<GLintptr>(buffer_pos));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StorageBuffer::Unmap() {
 | 
			
		||||
    glFlushMappedBufferRange(gl_target, static_cast<GLintptr>(buffer_pos),
 | 
			
		||||
                             static_cast<GLsizeiptr>(mapped_size));
 | 
			
		||||
    buffer_pos += mapped_size;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								src/video_core/renderer_opengl/gl_stream_buffer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/video_core/renderer_opengl/gl_stream_buffer.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
			
		||||
// Copyright 2018 Citra Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <glad/glad.h>
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
 | 
			
		||||
 | 
			
		||||
class OGLStreamBuffer : private NonCopyable {
 | 
			
		||||
public:
 | 
			
		||||
    explicit OGLStreamBuffer(GLenum target);
 | 
			
		||||
    virtual ~OGLStreamBuffer() = default;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    static std::unique_ptr<OGLStreamBuffer> MakeBuffer(bool storage_buffer, GLenum target);
 | 
			
		||||
 | 
			
		||||
    virtual void Create(size_t size, size_t sync_subdivide) = 0;
 | 
			
		||||
    virtual void Release() {}
 | 
			
		||||
 | 
			
		||||
    GLuint GetHandle() const;
 | 
			
		||||
 | 
			
		||||
    virtual std::pair<u8*, GLintptr> Map(size_t size, size_t alignment) = 0;
 | 
			
		||||
    virtual void Unmap() = 0;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    OGLBuffer gl_buffer;
 | 
			
		||||
    GLenum gl_target;
 | 
			
		||||
 | 
			
		||||
    size_t buffer_pos = 0;
 | 
			
		||||
    size_t buffer_size = 0;
 | 
			
		||||
    size_t buffer_sync_subdivide = 0;
 | 
			
		||||
    size_t mapped_size = 0;
 | 
			
		||||
};
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user