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_shader_util.h | ||||||
|     renderer_opengl/gl_state.cpp |     renderer_opengl/gl_state.cpp | ||||||
|     renderer_opengl/gl_state.h |     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/pica_to_gl.h | ||||||
|     renderer_opengl/renderer_opengl.cpp |     renderer_opengl/renderer_opengl.cpp | ||||||
|     renderer_opengl/renderer_opengl.h |     renderer_opengl/renderer_opengl.h | ||||||
|  |  | ||||||
|  | @ -142,6 +142,39 @@ public: | ||||||
|     GLuint handle = 0; |     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 { | class OGLVertexArray : private NonCopyable { | ||||||
| public: | public: | ||||||
|     OGLVertexArray() = default; |     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