9 changed files with 250 additions and 285 deletions
-
2src/video_core/CMakeLists.txt
-
84src/video_core/renderer_opengl/gl_rasterizer.cpp
-
15src/video_core/renderer_opengl/gl_rasterizer.h
-
131src/video_core/renderer_opengl/gl_shader_cache.cpp
-
69src/video_core/renderer_opengl/gl_shader_cache.h
-
4src/video_core/renderer_opengl/gl_shader_gen.cpp
-
75src/video_core/renderer_opengl/gl_shader_gen.h
-
29src/video_core/renderer_opengl/gl_shader_manager.cpp
-
126src/video_core/renderer_opengl/gl_shader_manager.h
@ -0,0 +1,131 @@ |
|||
// Copyright 2018 yuzu Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include "common/assert.h"
|
|||
#include "core/core.h"
|
|||
#include "core/memory.h"
|
|||
#include "video_core/engines/maxwell_3d.h"
|
|||
#include "video_core/renderer_opengl/gl_shader_cache.h"
|
|||
#include "video_core/renderer_opengl/gl_shader_manager.h"
|
|||
|
|||
namespace OpenGL { |
|||
|
|||
/// Gets the address for the specified shader stage program
|
|||
static Tegra::GPUVAddr GetShaderAddress(Maxwell::ShaderProgram program) { |
|||
auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); |
|||
|
|||
GLShader::ProgramCode program_code(GLShader::MAX_PROGRAM_CODE_LENGTH); |
|||
auto& shader_config = gpu.regs.shader_config[static_cast<size_t>(program)]; |
|||
return gpu.regs.code_address.CodeAddress() + shader_config.offset; |
|||
} |
|||
|
|||
/// Gets the shader program code from memory for the specified address
|
|||
static GLShader::ProgramCode GetShaderCode(Tegra::GPUVAddr addr) { |
|||
auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); |
|||
|
|||
GLShader::ProgramCode program_code(GLShader::MAX_PROGRAM_CODE_LENGTH); |
|||
const boost::optional<VAddr> cpu_address{gpu.memory_manager.GpuToCpuAddress(addr)}; |
|||
Memory::ReadBlock(*cpu_address, program_code.data(), program_code.size() * sizeof(u64)); |
|||
|
|||
return program_code; |
|||
} |
|||
|
|||
/// Helper function to set shader uniform block bindings for a single shader stage
|
|||
static void SetShaderUniformBlockBinding(GLuint shader, const char* name, |
|||
Maxwell::ShaderStage binding, size_t expected_size) { |
|||
const GLuint ub_index = glGetUniformBlockIndex(shader, name); |
|||
if (ub_index == GL_INVALID_INDEX) { |
|||
return; |
|||
} |
|||
|
|||
GLint ub_size = 0; |
|||
glGetActiveUniformBlockiv(shader, ub_index, GL_UNIFORM_BLOCK_DATA_SIZE, &ub_size); |
|||
ASSERT_MSG(static_cast<size_t>(ub_size) == expected_size, |
|||
"Uniform block size did not match! Got {}, expected {}", ub_size, expected_size); |
|||
glUniformBlockBinding(shader, ub_index, static_cast<GLuint>(binding)); |
|||
} |
|||
|
|||
/// Sets shader uniform block bindings for an entire shader program
|
|||
static void SetShaderUniformBlockBindings(GLuint shader) { |
|||
SetShaderUniformBlockBinding(shader, "vs_config", Maxwell::ShaderStage::Vertex, |
|||
sizeof(GLShader::MaxwellUniformData)); |
|||
SetShaderUniformBlockBinding(shader, "gs_config", Maxwell::ShaderStage::Geometry, |
|||
sizeof(GLShader::MaxwellUniformData)); |
|||
SetShaderUniformBlockBinding(shader, "fs_config", Maxwell::ShaderStage::Fragment, |
|||
sizeof(GLShader::MaxwellUniformData)); |
|||
} |
|||
|
|||
CachedShader::CachedShader(Tegra::GPUVAddr addr, Maxwell::ShaderProgram program_type) |
|||
: addr{addr}, program_type{program_type}, setup{GetShaderCode(addr)} { |
|||
|
|||
GLShader::ProgramResult program_result; |
|||
GLenum gl_type{}; |
|||
|
|||
switch (program_type) { |
|||
case Maxwell::ShaderProgram::VertexA: |
|||
// VertexB is always enabled, so when VertexA is enabled, we have two vertex shaders.
|
|||
// Conventional HW does not support this, so we combine VertexA and VertexB into one
|
|||
// stage here.
|
|||
setup.SetProgramB(GetShaderCode(GetShaderAddress(Maxwell::ShaderProgram::VertexB))); |
|||
case Maxwell::ShaderProgram::VertexB: |
|||
program_result = GLShader::GenerateVertexShader(setup); |
|||
gl_type = GL_VERTEX_SHADER; |
|||
break; |
|||
case Maxwell::ShaderProgram::Fragment: |
|||
program_result = GLShader::GenerateFragmentShader(setup); |
|||
gl_type = GL_FRAGMENT_SHADER; |
|||
break; |
|||
default: |
|||
LOG_CRITICAL(HW_GPU, "Unimplemented program_type={}", static_cast<u32>(program_type)); |
|||
UNREACHABLE(); |
|||
return; |
|||
} |
|||
|
|||
entries = program_result.second; |
|||
|
|||
OGLShader shader; |
|||
shader.Create(program_result.first.c_str(), gl_type); |
|||
program.Create(true, shader.handle); |
|||
SetShaderUniformBlockBindings(program.handle); |
|||
} |
|||
|
|||
GLuint CachedShader::GetProgramResourceIndex(const std::string& name) { |
|||
auto search{resource_cache.find(name)}; |
|||
if (search == resource_cache.end()) { |
|||
const GLuint index{ |
|||
glGetProgramResourceIndex(program.handle, GL_UNIFORM_BLOCK, name.c_str())}; |
|||
resource_cache[name] = index; |
|||
return index; |
|||
} |
|||
|
|||
return search->second; |
|||
} |
|||
|
|||
GLint CachedShader::GetUniformLocation(const std::string& name) { |
|||
auto search{uniform_cache.find(name)}; |
|||
if (search == uniform_cache.end()) { |
|||
const GLint index{glGetUniformLocation(program.handle, name.c_str())}; |
|||
uniform_cache[name] = index; |
|||
return index; |
|||
} |
|||
|
|||
return search->second; |
|||
} |
|||
|
|||
Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) { |
|||
const Tegra::GPUVAddr program_addr{GetShaderAddress(program)}; |
|||
|
|||
// Look up shader in the cache based on address
|
|||
Shader shader{TryGet(program_addr)}; |
|||
|
|||
if (!shader) { |
|||
// No shader found - create a new one
|
|||
shader = std::make_shared<CachedShader>(program_addr, program); |
|||
Register(shader); |
|||
} |
|||
|
|||
return shader; |
|||
} |
|||
|
|||
} // namespace OpenGL
|
|||
@ -0,0 +1,69 @@ |
|||
// Copyright 2018 yuzu Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include <memory> |
|||
#include <unordered_map> |
|||
|
|||
#include "common/common_types.h" |
|||
#include "video_core/memory_manager.h" |
|||
#include "video_core/rasterizer_cache.h" |
|||
#include "video_core/renderer_opengl/gl_resource_manager.h" |
|||
#include "video_core/renderer_opengl/gl_shader_gen.h" |
|||
|
|||
namespace OpenGL { |
|||
|
|||
class CachedShader; |
|||
using Shader = std::shared_ptr<CachedShader>; |
|||
using Maxwell = Tegra::Engines::Maxwell3D::Regs; |
|||
|
|||
class CachedShader final { |
|||
public: |
|||
CachedShader(Tegra::GPUVAddr addr, Maxwell::ShaderProgram program_type); |
|||
|
|||
/// Gets the address of the shader in guest memory, required for cache management |
|||
Tegra::GPUVAddr GetAddr() const { |
|||
return addr; |
|||
} |
|||
|
|||
/// Gets the size of the shader in guest memory, required for cache management |
|||
size_t GetSizeInBytes() const { |
|||
return sizeof(GLShader::ProgramCode); |
|||
} |
|||
|
|||
/// Gets the shader entries for the shader |
|||
const GLShader::ShaderEntries& GetShaderEntries() const { |
|||
return entries; |
|||
} |
|||
|
|||
/// Gets the GL program handle for the shader |
|||
GLuint GetProgramHandle() const { |
|||
return program.handle; |
|||
} |
|||
|
|||
/// Gets the GL program resource location for the specified resource, caching as needed |
|||
GLuint GetProgramResourceIndex(const std::string& name); |
|||
|
|||
/// Gets the GL uniform location for the specified resource, caching as needed |
|||
GLint GetUniformLocation(const std::string& name); |
|||
|
|||
private: |
|||
Tegra::GPUVAddr addr; |
|||
Maxwell::ShaderProgram program_type; |
|||
GLShader::ShaderSetup setup; |
|||
GLShader::ShaderEntries entries; |
|||
OGLProgram program; |
|||
|
|||
std::unordered_map<std::string, GLuint> resource_cache; |
|||
std::unordered_map<std::string, GLint> uniform_cache; |
|||
}; |
|||
|
|||
class ShaderCacheOpenGL final : public RasterizerCache<Shader> { |
|||
public: |
|||
/// Gets the current specified shader stage program |
|||
Shader GetStageProgram(Maxwell::ShaderProgram program); |
|||
}; |
|||
|
|||
} // namespace OpenGL |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue