Merge pull request #2345 from ReinUsesLisp/multibind
gl_rasterizer: Use ARB_multi_bind to update buffers with a single call per drawcall
This commit is contained in:
commit
97648f4841
4 changed files with 69 additions and 30 deletions
|
@ -299,6 +299,10 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
|
||||||
BaseBindings base_bindings;
|
BaseBindings base_bindings;
|
||||||
std::array<bool, Maxwell::NumClipDistances> clip_distances{};
|
std::array<bool, Maxwell::NumClipDistances> clip_distances{};
|
||||||
|
|
||||||
|
// Prepare packed bindings
|
||||||
|
bind_ubo_pushbuffer.Setup(base_bindings.cbuf);
|
||||||
|
bind_ssbo_pushbuffer.Setup(base_bindings.gmem);
|
||||||
|
|
||||||
for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
|
for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
|
||||||
const auto& shader_config = gpu.regs.shader_config[index];
|
const auto& shader_config = gpu.regs.shader_config[index];
|
||||||
const Maxwell::ShaderProgram program{static_cast<Maxwell::ShaderProgram>(index)};
|
const Maxwell::ShaderProgram program{static_cast<Maxwell::ShaderProgram>(index)};
|
||||||
|
@ -321,8 +325,8 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
|
||||||
&ubo, sizeof(ubo), static_cast<std::size_t>(uniform_buffer_alignment));
|
&ubo, sizeof(ubo), static_cast<std::size_t>(uniform_buffer_alignment));
|
||||||
|
|
||||||
// Bind the emulation info buffer
|
// Bind the emulation info buffer
|
||||||
glBindBufferRange(GL_UNIFORM_BUFFER, base_bindings.cbuf, buffer_cache.GetHandle(), offset,
|
bind_ubo_pushbuffer.Push(buffer_cache.GetHandle(), offset,
|
||||||
static_cast<GLsizeiptr>(sizeof(ubo)));
|
static_cast<GLsizeiptr>(sizeof(ubo)));
|
||||||
|
|
||||||
Shader shader{shader_cache.GetStageProgram(program)};
|
Shader shader{shader_cache.GetStageProgram(program)};
|
||||||
const auto [program_handle, next_bindings] =
|
const auto [program_handle, next_bindings] =
|
||||||
|
@ -366,6 +370,9 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
|
||||||
base_bindings = next_bindings;
|
base_bindings = next_bindings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bind_ubo_pushbuffer.Bind();
|
||||||
|
bind_ssbo_pushbuffer.Bind();
|
||||||
|
|
||||||
SyncClipEnabled(clip_distances);
|
SyncClipEnabled(clip_distances);
|
||||||
|
|
||||||
gpu.dirty_flags.shaders = false;
|
gpu.dirty_flags.shaders = false;
|
||||||
|
@ -900,23 +907,14 @@ void RasterizerOpenGL::SetupConstBuffers(Tegra::Engines::Maxwell3D::Regs::Shader
|
||||||
const auto& shader_stage = maxwell3d.state.shader_stages[static_cast<std::size_t>(stage)];
|
const auto& shader_stage = maxwell3d.state.shader_stages[static_cast<std::size_t>(stage)];
|
||||||
const auto& entries = shader->GetShaderEntries().const_buffers;
|
const auto& entries = shader->GetShaderEntries().const_buffers;
|
||||||
|
|
||||||
constexpr u64 max_binds = Tegra::Engines::Maxwell3D::Regs::MaxConstBuffers;
|
|
||||||
std::array<GLuint, max_binds> bind_buffers;
|
|
||||||
std::array<GLintptr, max_binds> bind_offsets;
|
|
||||||
std::array<GLsizeiptr, max_binds> bind_sizes;
|
|
||||||
|
|
||||||
ASSERT_MSG(entries.size() <= max_binds, "Exceeded expected number of binding points.");
|
|
||||||
|
|
||||||
// Upload only the enabled buffers from the 16 constbuffers of each shader stage
|
// Upload only the enabled buffers from the 16 constbuffers of each shader stage
|
||||||
for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
|
for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
|
||||||
const auto& used_buffer = entries[bindpoint];
|
const auto& used_buffer = entries[bindpoint];
|
||||||
const auto& buffer = shader_stage.const_buffers[used_buffer.GetIndex()];
|
const auto& buffer = shader_stage.const_buffers[used_buffer.GetIndex()];
|
||||||
|
|
||||||
if (!buffer.enabled) {
|
if (!buffer.enabled) {
|
||||||
// With disabled buffers set values as zero to unbind them
|
// Set values to zero to unbind buffers
|
||||||
bind_buffers[bindpoint] = 0;
|
bind_ubo_pushbuffer.Push(0, 0, 0);
|
||||||
bind_offsets[bindpoint] = 0;
|
|
||||||
bind_sizes[bindpoint] = 0;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -944,30 +942,19 @@ void RasterizerOpenGL::SetupConstBuffers(Tegra::Engines::Maxwell3D::Regs::Shader
|
||||||
const GLintptr const_buffer_offset = buffer_cache.UploadMemory(
|
const GLintptr const_buffer_offset = buffer_cache.UploadMemory(
|
||||||
buffer.address, size, static_cast<std::size_t>(uniform_buffer_alignment));
|
buffer.address, size, static_cast<std::size_t>(uniform_buffer_alignment));
|
||||||
|
|
||||||
// Prepare values for multibind
|
bind_ubo_pushbuffer.Push(buffer_cache.GetHandle(), const_buffer_offset, size);
|
||||||
bind_buffers[bindpoint] = buffer_cache.GetHandle();
|
|
||||||
bind_offsets[bindpoint] = const_buffer_offset;
|
|
||||||
bind_sizes[bindpoint] = size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The first binding is reserved for emulation values
|
|
||||||
const GLuint ubo_base_binding = base_bindings.cbuf + 1;
|
|
||||||
glBindBuffersRange(GL_UNIFORM_BUFFER, ubo_base_binding, static_cast<GLsizei>(entries.size()),
|
|
||||||
bind_buffers.data(), bind_offsets.data(), bind_sizes.data());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SetupGlobalRegions(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage,
|
void RasterizerOpenGL::SetupGlobalRegions(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage,
|
||||||
const Shader& shader, GLenum primitive_mode,
|
const Shader& shader, GLenum primitive_mode,
|
||||||
BaseBindings base_bindings) {
|
BaseBindings base_bindings) {
|
||||||
// TODO(Rodrigo): Use ARB_multi_bind here
|
|
||||||
const auto& entries = shader->GetShaderEntries().global_memory_entries;
|
const auto& entries = shader->GetShaderEntries().global_memory_entries;
|
||||||
|
for (std::size_t bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
|
||||||
for (u32 bindpoint = 0; bindpoint < static_cast<u32>(entries.size()); ++bindpoint) {
|
const auto& entry{entries[bindpoint]};
|
||||||
const auto& entry = entries[bindpoint];
|
const auto& region{global_cache.GetGlobalRegion(entry, stage)};
|
||||||
const u32 current_bindpoint = base_bindings.gmem + bindpoint;
|
bind_ssbo_pushbuffer.Push(region->GetBufferHandle(), 0,
|
||||||
const auto& region = global_cache.GetGlobalRegion(entry, stage);
|
static_cast<GLsizeiptr>(region->GetSizeInBytes()));
|
||||||
|
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, current_bindpoint, region->GetBufferHandle());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "video_core/renderer_opengl/gl_shader_cache.h"
|
#include "video_core/renderer_opengl/gl_shader_cache.h"
|
||||||
#include "video_core/renderer_opengl/gl_shader_manager.h"
|
#include "video_core/renderer_opengl/gl_shader_manager.h"
|
||||||
#include "video_core/renderer_opengl/gl_state.h"
|
#include "video_core/renderer_opengl/gl_state.h"
|
||||||
|
#include "video_core/renderer_opengl/utils.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
class System;
|
class System;
|
||||||
|
@ -229,6 +230,9 @@ private:
|
||||||
PrimitiveAssembler primitive_assembler{buffer_cache};
|
PrimitiveAssembler primitive_assembler{buffer_cache};
|
||||||
GLint uniform_buffer_alignment;
|
GLint uniform_buffer_alignment;
|
||||||
|
|
||||||
|
BindBuffersRangePushBuffer bind_ubo_pushbuffer{GL_UNIFORM_BUFFER};
|
||||||
|
BindBuffersRangePushBuffer bind_ssbo_pushbuffer{GL_SHADER_STORAGE_BUFFER};
|
||||||
|
|
||||||
std::size_t CalculateVertexArraysSize() const;
|
std::size_t CalculateVertexArraysSize() const;
|
||||||
|
|
||||||
std::size_t CalculateIndexBufferSize() const;
|
std::size_t CalculateIndexBufferSize() const;
|
||||||
|
|
|
@ -5,11 +5,39 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
|
#include "common/assert.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "video_core/renderer_opengl/utils.h"
|
#include "video_core/renderer_opengl/utils.h"
|
||||||
|
|
||||||
namespace OpenGL {
|
namespace OpenGL {
|
||||||
|
|
||||||
|
BindBuffersRangePushBuffer::BindBuffersRangePushBuffer(GLenum target) : target{target} {}
|
||||||
|
|
||||||
|
BindBuffersRangePushBuffer::~BindBuffersRangePushBuffer() = default;
|
||||||
|
|
||||||
|
void BindBuffersRangePushBuffer::Setup(GLuint first_) {
|
||||||
|
first = first_;
|
||||||
|
buffers.clear();
|
||||||
|
offsets.clear();
|
||||||
|
sizes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindBuffersRangePushBuffer::Push(GLuint buffer, GLintptr offset, GLsizeiptr size) {
|
||||||
|
buffers.push_back(buffer);
|
||||||
|
offsets.push_back(offset);
|
||||||
|
sizes.push_back(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindBuffersRangePushBuffer::Bind() const {
|
||||||
|
const std::size_t count{buffers.size()};
|
||||||
|
DEBUG_ASSERT(count == offsets.size() && count == sizes.size());
|
||||||
|
if (count == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
glBindBuffersRange(target, first, static_cast<GLsizei>(count), buffers.data(), offsets.data(),
|
||||||
|
sizes.data());
|
||||||
|
}
|
||||||
|
|
||||||
void LabelGLObject(GLenum identifier, GLuint handle, VAddr addr, std::string extra_info) {
|
void LabelGLObject(GLenum identifier, GLuint handle, VAddr addr, std::string extra_info) {
|
||||||
if (!GLAD_GL_KHR_debug) {
|
if (!GLAD_GL_KHR_debug) {
|
||||||
return; // We don't need to throw an error as this is just for debugging
|
return; // We don't need to throw an error as this is just for debugging
|
||||||
|
|
|
@ -5,11 +5,31 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
namespace OpenGL {
|
namespace OpenGL {
|
||||||
|
|
||||||
|
class BindBuffersRangePushBuffer {
|
||||||
|
public:
|
||||||
|
BindBuffersRangePushBuffer(GLenum target);
|
||||||
|
~BindBuffersRangePushBuffer();
|
||||||
|
|
||||||
|
void Setup(GLuint first_);
|
||||||
|
|
||||||
|
void Push(GLuint buffer, GLintptr offset, GLsizeiptr size);
|
||||||
|
|
||||||
|
void Bind() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
GLenum target;
|
||||||
|
GLuint first;
|
||||||
|
std::vector<GLuint> buffers;
|
||||||
|
std::vector<GLintptr> offsets;
|
||||||
|
std::vector<GLsizeiptr> sizes;
|
||||||
|
};
|
||||||
|
|
||||||
void LabelGLObject(GLenum identifier, GLuint handle, VAddr addr, std::string extra_info = "");
|
void LabelGLObject(GLenum identifier, GLuint handle, VAddr addr, std::string extra_info = "");
|
||||||
|
|
||||||
} // namespace OpenGL
|
} // namespace OpenGL
|
Loading…
Reference in a new issue