mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	stream buffer
This commit is contained in:
		
							parent
							
								
									935bcdbd20
								
							
						
					
					
						commit
						50598fbbf4
					
				
					 4 changed files with 251 additions and 0 deletions
				
			
		|  | @ -34,6 +34,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/pica_to_gl.h | ||||
|     renderer_opengl/renderer_opengl.cpp | ||||
|     renderer_opengl/renderer_opengl.h | ||||
|  |  | |||
|  | @ -142,6 +142,39 @@ public: | |||
|     GLuint handle = 0; | ||||
| }; | ||||
| 
 | ||||
| class OGLSync : private NonCopyable { | ||||
| public: | ||||
|     OGLSync() = default; | ||||
| 
 | ||||
|     OGLSync(OGLSync&& o) : handle(std::exchange(o.handle, nullptr)) {} | ||||
| 
 | ||||
|     ~OGLSync() { | ||||
|         Release(); | ||||
|     } | ||||
|     OGLSync& operator=(OGLSync&& o) { | ||||
|         Release(); | ||||
|         handle = std::exchange(o.handle, nullptr); | ||||
|         return *this; | ||||
|     } | ||||
| 
 | ||||
|     /// Creates a new internal OpenGL resource and stores the handle
 | ||||
|     void Create() { | ||||
|         if (handle != 0) | ||||
|             return; | ||||
|         handle = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); | ||||
|     } | ||||
| 
 | ||||
|     /// Deletes the internal OpenGL resource
 | ||||
|     void Release() { | ||||
|         if (handle == 0) | ||||
|             return; | ||||
|         glDeleteSync(handle); | ||||
|         handle = 0; | ||||
|     } | ||||
| 
 | ||||
|     GLsync handle = 0; | ||||
| }; | ||||
| 
 | ||||
| class OGLVertexArray : private NonCopyable { | ||||
| public: | ||||
|     OGLVertexArray() = default; | ||||
|  |  | |||
							
								
								
									
										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…
	
	Add table
		Add a link
		
	
		Reference in a new issue