mirror of
https://gitlab.com/suyu-emu/suyu.git
synced 2024-03-15 23:15:44 +00:00
gl_rasterizer: Implement global memory management
This commit is contained in:
parent
3b84e04af1
commit
9f803299de
|
@ -4,8 +4,13 @@
|
||||||
|
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "core/core.h"
|
||||||
|
#include "core/memory.h"
|
||||||
#include "video_core/renderer_opengl/gl_global_cache.h"
|
#include "video_core/renderer_opengl/gl_global_cache.h"
|
||||||
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
||||||
|
#include "video_core/renderer_opengl/gl_shader_decompiler.h"
|
||||||
#include "video_core/renderer_opengl/utils.h"
|
#include "video_core/renderer_opengl/utils.h"
|
||||||
|
|
||||||
namespace OpenGL {
|
namespace OpenGL {
|
||||||
|
@ -18,7 +23,72 @@ CachedGlobalRegion::CachedGlobalRegion(VAddr addr, u32 size) : addr{addr}, size{
|
||||||
LabelGLObject(GL_BUFFER, buffer.handle, addr, "GlobalMemory");
|
LabelGLObject(GL_BUFFER, buffer.handle, addr, "GlobalMemory");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CachedGlobalRegion::Reload(u32 size_) {
|
||||||
|
constexpr auto max_size = static_cast<u32>(RasterizerOpenGL::MaxGlobalMemorySize);
|
||||||
|
|
||||||
|
size = size_;
|
||||||
|
if (size > max_size) {
|
||||||
|
size = max_size;
|
||||||
|
LOG_CRITICAL(HW_GPU, "Global region size {} exceeded the expected size {}!", size_,
|
||||||
|
max_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(Rodrigo): Get rid of Memory::GetPointer with a staging buffer
|
||||||
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer.handle);
|
||||||
|
glBufferData(GL_SHADER_STORAGE_BUFFER, size, Memory::GetPointer(addr), GL_DYNAMIC_DRAW);
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalRegion GlobalRegionCacheOpenGL::TryGetReservedGlobalRegion(VAddr addr, u32 size) const {
|
||||||
|
const auto search{reserve.find(addr)};
|
||||||
|
if (search == reserve.end()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return search->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalRegion GlobalRegionCacheOpenGL::GetUncachedGlobalRegion(VAddr addr, u32 size) {
|
||||||
|
GlobalRegion region{TryGetReservedGlobalRegion(addr, size)};
|
||||||
|
if (!region) {
|
||||||
|
// No reserved surface available, create a new one and reserve it
|
||||||
|
region = std::make_shared<CachedGlobalRegion>(addr, size);
|
||||||
|
ReserveGlobalRegion(region);
|
||||||
|
}
|
||||||
|
region->Reload(size);
|
||||||
|
return region;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalRegionCacheOpenGL::ReserveGlobalRegion(const GlobalRegion& region) {
|
||||||
|
reserve[region->GetAddr()] = region;
|
||||||
|
}
|
||||||
|
|
||||||
GlobalRegionCacheOpenGL::GlobalRegionCacheOpenGL(RasterizerOpenGL& rasterizer)
|
GlobalRegionCacheOpenGL::GlobalRegionCacheOpenGL(RasterizerOpenGL& rasterizer)
|
||||||
: RasterizerCache{rasterizer} {}
|
: RasterizerCache{rasterizer} {}
|
||||||
|
|
||||||
|
GlobalRegion GlobalRegionCacheOpenGL::GetGlobalRegion(
|
||||||
|
const GLShader::GlobalMemoryEntry& global_region,
|
||||||
|
Tegra::Engines::Maxwell3D::Regs::ShaderStage stage) {
|
||||||
|
|
||||||
|
auto& gpu{Core::System::GetInstance().GPU()};
|
||||||
|
const auto cbufs = gpu.Maxwell3D().state.shader_stages[static_cast<u64>(stage)];
|
||||||
|
const auto cbuf_addr = gpu.MemoryManager().GpuToCpuAddress(
|
||||||
|
cbufs.const_buffers[global_region.GetCbufIndex()].address + global_region.GetCbufOffset());
|
||||||
|
ASSERT(cbuf_addr);
|
||||||
|
|
||||||
|
const auto actual_addr_gpu = Memory::Read64(*cbuf_addr);
|
||||||
|
const auto size = Memory::Read32(*cbuf_addr + 8);
|
||||||
|
const auto actual_addr = gpu.MemoryManager().GpuToCpuAddress(actual_addr_gpu);
|
||||||
|
ASSERT(actual_addr);
|
||||||
|
|
||||||
|
// Look up global region in the cache based on address
|
||||||
|
GlobalRegion region = TryGet(*actual_addr);
|
||||||
|
|
||||||
|
if (!region) {
|
||||||
|
// No global region found - create a new one
|
||||||
|
region = GetUncachedGlobalRegion(*actual_addr, size);
|
||||||
|
Register(region);
|
||||||
|
}
|
||||||
|
|
||||||
|
return region;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace OpenGL
|
} // namespace OpenGL
|
||||||
|
|
|
@ -5,9 +5,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#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/engines/maxwell_3d.h"
|
||||||
#include "video_core/rasterizer_cache.h"
|
#include "video_core/rasterizer_cache.h"
|
||||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||||
|
|
||||||
|
@ -40,6 +44,9 @@ public:
|
||||||
return buffer.handle;
|
return buffer.handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reloads the global region from guest memory
|
||||||
|
void Reload(u32 size_);
|
||||||
|
|
||||||
// TODO(Rodrigo): When global memory is written (STG), implement flushing
|
// TODO(Rodrigo): When global memory is written (STG), implement flushing
|
||||||
void Flush() override {
|
void Flush() override {
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
|
@ -55,6 +62,17 @@ private:
|
||||||
class GlobalRegionCacheOpenGL final : public RasterizerCache<GlobalRegion> {
|
class GlobalRegionCacheOpenGL final : public RasterizerCache<GlobalRegion> {
|
||||||
public:
|
public:
|
||||||
explicit GlobalRegionCacheOpenGL(RasterizerOpenGL& rasterizer);
|
explicit GlobalRegionCacheOpenGL(RasterizerOpenGL& rasterizer);
|
||||||
|
|
||||||
|
/// Gets the current specified shader stage program
|
||||||
|
GlobalRegion GetGlobalRegion(const GLShader::GlobalMemoryEntry& descriptor,
|
||||||
|
Tegra::Engines::Maxwell3D::Regs::ShaderStage stage);
|
||||||
|
|
||||||
|
private:
|
||||||
|
GlobalRegion TryGetReservedGlobalRegion(VAddr addr, u32 size) const;
|
||||||
|
GlobalRegion GetUncachedGlobalRegion(VAddr addr, u32 size);
|
||||||
|
void ReserveGlobalRegion(const GlobalRegion& region);
|
||||||
|
|
||||||
|
std::unordered_map<VAddr, GlobalRegion> reserve;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace OpenGL
|
} // namespace OpenGL
|
||||||
|
|
|
@ -300,6 +300,7 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
|
||||||
// Next available bindpoints to use when uploading the const buffers and textures to the GLSL
|
// Next available bindpoints to use when uploading the const buffers and textures to the GLSL
|
||||||
// shaders. The constbuffer bindpoint starts after the shader stage configuration bind points.
|
// shaders. The constbuffer bindpoint starts after the shader stage configuration bind points.
|
||||||
u32 current_constbuffer_bindpoint = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage;
|
u32 current_constbuffer_bindpoint = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage;
|
||||||
|
u32 current_gmem_bindpoint = 0;
|
||||||
u32 current_texture_bindpoint = 0;
|
u32 current_texture_bindpoint = 0;
|
||||||
std::array<bool, Maxwell::NumClipDistances> clip_distances{};
|
std::array<bool, Maxwell::NumClipDistances> clip_distances{};
|
||||||
|
|
||||||
|
@ -358,6 +359,10 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
|
||||||
SetupConstBuffers(static_cast<Maxwell::ShaderStage>(stage), shader, primitive_mode,
|
SetupConstBuffers(static_cast<Maxwell::ShaderStage>(stage), shader, primitive_mode,
|
||||||
current_constbuffer_bindpoint);
|
current_constbuffer_bindpoint);
|
||||||
|
|
||||||
|
// Configure global memory regions for this shader stage.
|
||||||
|
current_gmem_bindpoint = SetupGlobalRegions(static_cast<Maxwell::ShaderStage>(stage),
|
||||||
|
shader, primitive_mode, current_gmem_bindpoint);
|
||||||
|
|
||||||
// Configure the textures for this shader stage.
|
// Configure the textures for this shader stage.
|
||||||
current_texture_bindpoint = SetupTextures(static_cast<Maxwell::ShaderStage>(stage), shader,
|
current_texture_bindpoint = SetupTextures(static_cast<Maxwell::ShaderStage>(stage), shader,
|
||||||
primitive_mode, current_texture_bindpoint);
|
primitive_mode, current_texture_bindpoint);
|
||||||
|
@ -993,6 +998,23 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shad
|
||||||
return current_bindpoint + static_cast<u32>(entries.size());
|
return current_bindpoint + static_cast<u32>(entries.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 RasterizerOpenGL::SetupGlobalRegions(Maxwell::ShaderStage stage, Shader& shader,
|
||||||
|
GLenum primitive_mode, u32 current_bindpoint) {
|
||||||
|
for (const auto& global_region : shader->GetShaderEntries().global_memory_entries) {
|
||||||
|
const auto& region =
|
||||||
|
global_cache.GetGlobalRegion(global_region, static_cast<Maxwell::ShaderStage>(stage));
|
||||||
|
const GLuint block_index{shader->GetProgramResourceIndex(global_region)};
|
||||||
|
ASSERT(block_index != GL_INVALID_INDEX);
|
||||||
|
|
||||||
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, current_bindpoint, region->GetBufferHandle());
|
||||||
|
glShaderStorageBlockBinding(shader->GetProgramHandle(primitive_mode), block_index,
|
||||||
|
current_bindpoint);
|
||||||
|
++current_bindpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
return current_bindpoint;
|
||||||
|
}
|
||||||
|
|
||||||
u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
|
u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
|
||||||
GLenum primitive_mode, u32 current_unit) {
|
GLenum primitive_mode, u32 current_unit) {
|
||||||
MICROPROFILE_SCOPE(OpenGL_Texture);
|
MICROPROFILE_SCOPE(OpenGL_Texture);
|
||||||
|
|
|
@ -137,6 +137,16 @@ private:
|
||||||
u32 SetupConstBuffers(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, Shader& shader,
|
u32 SetupConstBuffers(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, Shader& shader,
|
||||||
GLenum primitive_mode, u32 current_bindpoint);
|
GLenum primitive_mode, u32 current_bindpoint);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the current global memory regions to use for the draw command.
|
||||||
|
* @param stage The shader stage to configure buffers for.
|
||||||
|
* @param shader The shader object that contains the specified stage.
|
||||||
|
* @param current_bindpoint The offset at which to start counting new buffer bindpoints.
|
||||||
|
* @returns The next available bindpoint for use in the next shader stage.
|
||||||
|
*/
|
||||||
|
u32 SetupGlobalRegions(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, Shader& shader,
|
||||||
|
GLenum primitive_mode, u32 current_bindpoint);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures the current textures to use for the draw command.
|
* Configures the current textures to use for the draw command.
|
||||||
* @param stage The shader stage to configure textures for.
|
* @param stage The shader stage to configure textures for.
|
||||||
|
|
|
@ -108,11 +108,23 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint CachedShader::GetProgramResourceIndex(const GLShader::ConstBufferEntry& buffer) {
|
GLuint CachedShader::GetProgramResourceIndex(const GLShader::ConstBufferEntry& buffer) {
|
||||||
const auto search{resource_cache.find(buffer.GetHash())};
|
const auto search{cbuf_resource_cache.find(buffer.GetHash())};
|
||||||
if (search == resource_cache.end()) {
|
if (search == cbuf_resource_cache.end()) {
|
||||||
const GLuint index{
|
const GLuint index{
|
||||||
glGetProgramResourceIndex(program.handle, GL_UNIFORM_BLOCK, buffer.GetName().c_str())};
|
glGetProgramResourceIndex(program.handle, GL_UNIFORM_BLOCK, buffer.GetName().c_str())};
|
||||||
resource_cache[buffer.GetHash()] = index;
|
cbuf_resource_cache[buffer.GetHash()] = index;
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return search->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint CachedShader::GetProgramResourceIndex(const GLShader::GlobalMemoryEntry& global_mem) {
|
||||||
|
const auto search{gmem_resource_cache.find(global_mem.GetHash())};
|
||||||
|
if (search == gmem_resource_cache.end()) {
|
||||||
|
const GLuint index{glGetProgramResourceIndex(program.handle, GL_SHADER_STORAGE_BLOCK,
|
||||||
|
global_mem.GetName().c_str())};
|
||||||
|
gmem_resource_cache[global_mem.GetHash()] = index;
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,9 @@ public:
|
||||||
/// Gets the GL program resource location for the specified resource, caching as needed
|
/// Gets the GL program resource location for the specified resource, caching as needed
|
||||||
GLuint GetProgramResourceIndex(const GLShader::ConstBufferEntry& buffer);
|
GLuint GetProgramResourceIndex(const GLShader::ConstBufferEntry& buffer);
|
||||||
|
|
||||||
|
/// Gets the GL program resource location for the specified resource, caching as needed
|
||||||
|
GLuint GetProgramResourceIndex(const GLShader::GlobalMemoryEntry& global_mem);
|
||||||
|
|
||||||
/// Gets the GL uniform location for the specified resource, caching as needed
|
/// Gets the GL uniform location for the specified resource, caching as needed
|
||||||
GLint GetUniformLocation(const GLShader::SamplerEntry& sampler);
|
GLint GetUniformLocation(const GLShader::SamplerEntry& sampler);
|
||||||
|
|
||||||
|
@ -107,7 +110,8 @@ private:
|
||||||
OGLProgram triangles_adjacency;
|
OGLProgram triangles_adjacency;
|
||||||
} geometry_programs;
|
} geometry_programs;
|
||||||
|
|
||||||
std::map<u32, GLuint> resource_cache;
|
std::map<u32, GLuint> cbuf_resource_cache;
|
||||||
|
std::map<u32, GLuint> gmem_resource_cache;
|
||||||
std::map<u32, GLint> uniform_cache;
|
std::map<u32, GLint> uniform_cache;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue