Browse Source
OpenGL: Make use of persistent buffer maps in buffer cache downloads
OpenGL: Make use of persistent buffer maps in buffer cache downloads
Persistent buffer maps were already used by the texture cache, this extends their usage for the buffer cache. In my testing, using the memory maps for uploads was slower than the existing "ImmediateUpload" path, so the memory map usage is limited to downloads for the time being.nce_cpp
15 changed files with 298 additions and 204 deletions
-
4src/video_core/CMakeLists.txt
-
10src/video_core/buffer_cache/buffer_cache.h
-
1src/video_core/buffer_cache/buffer_cache_base.h
-
58src/video_core/renderer_opengl/gl_buffer_cache.cpp
-
29src/video_core/renderer_opengl/gl_buffer_cache.h
-
6src/video_core/renderer_opengl/gl_rasterizer.cpp
-
1src/video_core/renderer_opengl/gl_rasterizer.h
-
134src/video_core/renderer_opengl/gl_staging_buffer_pool.cpp
-
42src/video_core/renderer_opengl/gl_staging_buffer_pool.h
-
63src/video_core/renderer_opengl/gl_stream_buffer.cpp
-
87src/video_core/renderer_opengl/gl_texture_cache.cpp
-
47src/video_core/renderer_opengl/gl_texture_cache.h
-
9src/video_core/renderer_opengl/util_shaders.cpp
-
10src/video_core/renderer_opengl/util_shaders.h
-
1src/video_core/renderer_vulkan/vk_buffer_cache.h
@ -0,0 +1,134 @@ |
|||||
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
|
||||
|
#include <array>
|
||||
|
#include <memory>
|
||||
|
#include <span>
|
||||
|
|
||||
|
#include <glad/glad.h>
|
||||
|
|
||||
|
#include "common/alignment.h"
|
||||
|
#include "common/assert.h"
|
||||
|
#include "video_core/renderer_opengl/gl_staging_buffer_pool.h"
|
||||
|
|
||||
|
namespace OpenGL { |
||||
|
|
||||
|
StagingBufferMap::~StagingBufferMap() { |
||||
|
if (sync) { |
||||
|
sync->Create(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
StagingBuffers::StagingBuffers(GLenum storage_flags_, GLenum map_flags_) |
||||
|
: storage_flags{storage_flags_}, map_flags{map_flags_} {} |
||||
|
|
||||
|
StagingBuffers::~StagingBuffers() = default; |
||||
|
|
||||
|
StagingBufferMap StagingBuffers::RequestMap(size_t requested_size, bool insert_fence) { |
||||
|
const size_t index = RequestBuffer(requested_size); |
||||
|
OGLSync* const sync = insert_fence ? &syncs[index] : nullptr; |
||||
|
return StagingBufferMap{ |
||||
|
.mapped_span = std::span(maps[index], requested_size), |
||||
|
.sync = sync, |
||||
|
.buffer = buffers[index].handle, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
size_t StagingBuffers::RequestBuffer(size_t requested_size) { |
||||
|
if (const std::optional<size_t> index = FindBuffer(requested_size); index) { |
||||
|
return *index; |
||||
|
} |
||||
|
|
||||
|
OGLBuffer& buffer = buffers.emplace_back(); |
||||
|
buffer.Create(); |
||||
|
glNamedBufferStorage(buffer.handle, requested_size, nullptr, |
||||
|
storage_flags | GL_MAP_PERSISTENT_BIT); |
||||
|
maps.push_back(static_cast<u8*>(glMapNamedBufferRange(buffer.handle, 0, requested_size, |
||||
|
map_flags | GL_MAP_PERSISTENT_BIT))); |
||||
|
|
||||
|
syncs.emplace_back(); |
||||
|
sizes.push_back(requested_size); |
||||
|
|
||||
|
ASSERT(syncs.size() == buffers.size() && buffers.size() == maps.size() && |
||||
|
maps.size() == sizes.size()); |
||||
|
|
||||
|
return buffers.size() - 1; |
||||
|
} |
||||
|
|
||||
|
std::optional<size_t> StagingBuffers::FindBuffer(size_t requested_size) { |
||||
|
size_t smallest_buffer = std::numeric_limits<size_t>::max(); |
||||
|
std::optional<size_t> found; |
||||
|
const size_t num_buffers = sizes.size(); |
||||
|
for (size_t index = 0; index < num_buffers; ++index) { |
||||
|
const size_t buffer_size = sizes[index]; |
||||
|
if (buffer_size < requested_size || buffer_size >= smallest_buffer) { |
||||
|
continue; |
||||
|
} |
||||
|
if (syncs[index].handle != 0) { |
||||
|
if (!syncs[index].IsSignaled()) { |
||||
|
continue; |
||||
|
} |
||||
|
syncs[index].Release(); |
||||
|
} |
||||
|
smallest_buffer = buffer_size; |
||||
|
found = index; |
||||
|
} |
||||
|
return found; |
||||
|
} |
||||
|
|
||||
|
StreamBuffer::StreamBuffer() { |
||||
|
static constexpr GLenum flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT; |
||||
|
buffer.Create(); |
||||
|
glObjectLabel(GL_BUFFER, buffer.handle, -1, "Stream Buffer"); |
||||
|
glNamedBufferStorage(buffer.handle, STREAM_BUFFER_SIZE, nullptr, flags); |
||||
|
mapped_pointer = |
||||
|
static_cast<u8*>(glMapNamedBufferRange(buffer.handle, 0, STREAM_BUFFER_SIZE, flags)); |
||||
|
for (OGLSync& sync : fences) { |
||||
|
sync.Create(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
std::pair<std::span<u8>, size_t> StreamBuffer::Request(size_t size) noexcept { |
||||
|
ASSERT(size < REGION_SIZE); |
||||
|
for (size_t region = Region(used_iterator), region_end = Region(iterator); region < region_end; |
||||
|
++region) { |
||||
|
fences[region].Create(); |
||||
|
} |
||||
|
used_iterator = iterator; |
||||
|
|
||||
|
for (size_t region = Region(free_iterator) + 1, |
||||
|
region_end = std::min(Region(iterator + size) + 1, NUM_SYNCS); |
||||
|
region < region_end; ++region) { |
||||
|
glClientWaitSync(fences[region].handle, 0, GL_TIMEOUT_IGNORED); |
||||
|
fences[region].Release(); |
||||
|
} |
||||
|
if (iterator + size >= free_iterator) { |
||||
|
free_iterator = iterator + size; |
||||
|
} |
||||
|
if (iterator + size > STREAM_BUFFER_SIZE) { |
||||
|
for (size_t region = Region(used_iterator); region < NUM_SYNCS; ++region) { |
||||
|
fences[region].Create(); |
||||
|
} |
||||
|
used_iterator = 0; |
||||
|
iterator = 0; |
||||
|
free_iterator = size; |
||||
|
|
||||
|
for (size_t region = 0, region_end = Region(size); region <= region_end; ++region) { |
||||
|
glClientWaitSync(fences[region].handle, 0, GL_TIMEOUT_IGNORED); |
||||
|
fences[region].Release(); |
||||
|
} |
||||
|
} |
||||
|
const size_t offset = iterator; |
||||
|
iterator = Common::AlignUp(iterator + size, MAX_ALIGNMENT); |
||||
|
return {std::span(mapped_pointer + offset, size), offset}; |
||||
|
} |
||||
|
|
||||
|
StagingBufferMap StagingBufferPool::RequestUploadBuffer(size_t size) { |
||||
|
return upload_buffers.RequestMap(size, true); |
||||
|
} |
||||
|
|
||||
|
StagingBufferMap StagingBufferPool::RequestDownloadBuffer(size_t size) { |
||||
|
return download_buffers.RequestMap(size, false); |
||||
|
} |
||||
|
|
||||
|
} // namespace OpenGL
|
||||
@ -1,63 +0,0 @@ |
|||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||
|
|
||||
#include <array>
|
|
||||
#include <memory>
|
|
||||
#include <span>
|
|
||||
|
|
||||
#include <glad/glad.h>
|
|
||||
|
|
||||
#include "common/alignment.h"
|
|
||||
#include "common/assert.h"
|
|
||||
#include "video_core/renderer_opengl/gl_stream_buffer.h"
|
|
||||
|
|
||||
namespace OpenGL { |
|
||||
|
|
||||
StreamBuffer::StreamBuffer() { |
|
||||
static constexpr GLenum flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT; |
|
||||
buffer.Create(); |
|
||||
glObjectLabel(GL_BUFFER, buffer.handle, -1, "Stream Buffer"); |
|
||||
glNamedBufferStorage(buffer.handle, STREAM_BUFFER_SIZE, nullptr, flags); |
|
||||
mapped_pointer = |
|
||||
static_cast<u8*>(glMapNamedBufferRange(buffer.handle, 0, STREAM_BUFFER_SIZE, flags)); |
|
||||
for (OGLSync& sync : fences) { |
|
||||
sync.Create(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
std::pair<std::span<u8>, size_t> StreamBuffer::Request(size_t size) noexcept { |
|
||||
ASSERT(size < REGION_SIZE); |
|
||||
for (size_t region = Region(used_iterator), region_end = Region(iterator); region < region_end; |
|
||||
++region) { |
|
||||
fences[region].Create(); |
|
||||
} |
|
||||
used_iterator = iterator; |
|
||||
|
|
||||
for (size_t region = Region(free_iterator) + 1, |
|
||||
region_end = std::min(Region(iterator + size) + 1, NUM_SYNCS); |
|
||||
region < region_end; ++region) { |
|
||||
glClientWaitSync(fences[region].handle, 0, GL_TIMEOUT_IGNORED); |
|
||||
fences[region].Release(); |
|
||||
} |
|
||||
if (iterator + size >= free_iterator) { |
|
||||
free_iterator = iterator + size; |
|
||||
} |
|
||||
if (iterator + size > STREAM_BUFFER_SIZE) { |
|
||||
for (size_t region = Region(used_iterator); region < NUM_SYNCS; ++region) { |
|
||||
fences[region].Create(); |
|
||||
} |
|
||||
used_iterator = 0; |
|
||||
iterator = 0; |
|
||||
free_iterator = size; |
|
||||
|
|
||||
for (size_t region = 0, region_end = Region(size); region <= region_end; ++region) { |
|
||||
glClientWaitSync(fences[region].handle, 0, GL_TIMEOUT_IGNORED); |
|
||||
fences[region].Release(); |
|
||||
} |
|
||||
} |
|
||||
const size_t offset = iterator; |
|
||||
iterator = Common::AlignUp(iterator + size, MAX_ALIGNMENT); |
|
||||
return {std::span(mapped_pointer + offset, size), offset}; |
|
||||
} |
|
||||
|
|
||||
} // namespace OpenGL
|
|
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue