Browse Source
Merge pull request #2976 from FernandoS27/cache-fast-brx-rebased
Merge pull request #2976 from FernandoS27/cache-fast-brx-rebased
Implement Fast BRX, fix TXQ and addapt the Shader Cache for itpull/15/merge
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 1486 additions and 866 deletions
-
6CMakeModules/GenerateSCMRev.cmake
-
6src/common/CMakeLists.txt
-
11src/common/hash.h
-
7src/video_core/CMakeLists.txt
-
119src/video_core/engines/const_buffer_engine_interface.h
-
20src/video_core/engines/kepler_compute.cpp
-
14src/video_core/engines/kepler_compute.h
-
21src/video_core/engines/maxwell_3d.cpp
-
14src/video_core/engines/maxwell_3d.h
-
9src/video_core/renderer_opengl/gl_rasterizer.cpp
-
525src/video_core/renderer_opengl/gl_shader_cache.cpp
-
77src/video_core/renderer_opengl/gl_shader_cache.h
-
77src/video_core/renderer_opengl/gl_shader_decompiler.cpp
-
7src/video_core/renderer_opengl/gl_shader_decompiler.h
-
431src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
-
44src/video_core/renderer_opengl/gl_shader_disk_cache.h
-
86src/video_core/renderer_opengl/gl_shader_gen.cpp
-
36src/video_core/renderer_opengl/gl_shader_gen.h
-
7src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
-
4src/video_core/shader/ast.cpp
-
110src/video_core/shader/const_buffer_locker.cpp
-
80src/video_core/shader/const_buffer_locker.h
-
363src/video_core/shader/control_flow.cpp
-
63src/video_core/shader/control_flow.h
-
33src/video_core/shader/decode.cpp
-
70src/video_core/shader/decode/texture.cpp
-
21src/video_core/shader/expr.h
-
7src/video_core/shader/shader_ir.cpp
-
24src/video_core/shader/shader_ir.h
@ -0,0 +1,119 @@ |
|||
// Copyright 2019 yuzu Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include <type_traits> |
|||
#include "common/bit_field.h" |
|||
#include "common/common_types.h" |
|||
#include "video_core/engines/shader_bytecode.h" |
|||
#include "video_core/textures/texture.h" |
|||
|
|||
namespace Tegra::Engines { |
|||
|
|||
enum class ShaderType : u32 { |
|||
Vertex = 0, |
|||
TesselationControl = 1, |
|||
TesselationEval = 2, |
|||
Geometry = 3, |
|||
Fragment = 4, |
|||
Compute = 5, |
|||
}; |
|||
|
|||
struct SamplerDescriptor { |
|||
union { |
|||
BitField<0, 20, Tegra::Shader::TextureType> texture_type; |
|||
BitField<20, 1, u32> is_array; |
|||
BitField<21, 1, u32> is_buffer; |
|||
BitField<22, 1, u32> is_shadow; |
|||
u32 raw{}; |
|||
}; |
|||
|
|||
bool operator==(const SamplerDescriptor& rhs) const noexcept { |
|||
return raw == rhs.raw; |
|||
} |
|||
|
|||
bool operator!=(const SamplerDescriptor& rhs) const noexcept { |
|||
return !operator==(rhs); |
|||
} |
|||
|
|||
static SamplerDescriptor FromTicTexture(Tegra::Texture::TextureType tic_texture_type) { |
|||
SamplerDescriptor result; |
|||
switch (tic_texture_type) { |
|||
case Tegra::Texture::TextureType::Texture1D: |
|||
result.texture_type.Assign(Tegra::Shader::TextureType::Texture1D); |
|||
result.is_array.Assign(0); |
|||
result.is_buffer.Assign(0); |
|||
result.is_shadow.Assign(0); |
|||
return result; |
|||
case Tegra::Texture::TextureType::Texture2D: |
|||
result.texture_type.Assign(Tegra::Shader::TextureType::Texture2D); |
|||
result.is_array.Assign(0); |
|||
result.is_buffer.Assign(0); |
|||
result.is_shadow.Assign(0); |
|||
return result; |
|||
case Tegra::Texture::TextureType::Texture3D: |
|||
result.texture_type.Assign(Tegra::Shader::TextureType::Texture3D); |
|||
result.is_array.Assign(0); |
|||
result.is_buffer.Assign(0); |
|||
result.is_shadow.Assign(0); |
|||
return result; |
|||
case Tegra::Texture::TextureType::TextureCubemap: |
|||
result.texture_type.Assign(Tegra::Shader::TextureType::TextureCube); |
|||
result.is_array.Assign(0); |
|||
result.is_buffer.Assign(0); |
|||
result.is_shadow.Assign(0); |
|||
return result; |
|||
case Tegra::Texture::TextureType::Texture1DArray: |
|||
result.texture_type.Assign(Tegra::Shader::TextureType::Texture1D); |
|||
result.is_array.Assign(1); |
|||
result.is_buffer.Assign(0); |
|||
result.is_shadow.Assign(0); |
|||
return result; |
|||
case Tegra::Texture::TextureType::Texture2DArray: |
|||
result.texture_type.Assign(Tegra::Shader::TextureType::Texture2D); |
|||
result.is_array.Assign(1); |
|||
result.is_buffer.Assign(0); |
|||
result.is_shadow.Assign(0); |
|||
return result; |
|||
case Tegra::Texture::TextureType::Texture1DBuffer: |
|||
result.texture_type.Assign(Tegra::Shader::TextureType::Texture1D); |
|||
result.is_array.Assign(0); |
|||
result.is_buffer.Assign(1); |
|||
result.is_shadow.Assign(0); |
|||
return result; |
|||
case Tegra::Texture::TextureType::Texture2DNoMipmap: |
|||
result.texture_type.Assign(Tegra::Shader::TextureType::Texture2D); |
|||
result.is_array.Assign(0); |
|||
result.is_buffer.Assign(0); |
|||
result.is_shadow.Assign(0); |
|||
return result; |
|||
case Tegra::Texture::TextureType::TextureCubeArray: |
|||
result.texture_type.Assign(Tegra::Shader::TextureType::TextureCube); |
|||
result.is_array.Assign(1); |
|||
result.is_buffer.Assign(0); |
|||
result.is_shadow.Assign(0); |
|||
return result; |
|||
default: |
|||
result.texture_type.Assign(Tegra::Shader::TextureType::Texture2D); |
|||
result.is_array.Assign(0); |
|||
result.is_buffer.Assign(0); |
|||
result.is_shadow.Assign(0); |
|||
return result; |
|||
} |
|||
} |
|||
}; |
|||
static_assert(std::is_trivially_copyable_v<SamplerDescriptor>); |
|||
|
|||
class ConstBufferEngineInterface { |
|||
public: |
|||
virtual ~ConstBufferEngineInterface() = default; |
|||
virtual u32 AccessConstBuffer32(ShaderType stage, u64 const_buffer, u64 offset) const = 0; |
|||
virtual SamplerDescriptor AccessBoundSampler(ShaderType stage, u64 offset) const = 0; |
|||
virtual SamplerDescriptor AccessBindlessSampler(ShaderType stage, u64 const_buffer, |
|||
u64 offset) const = 0; |
|||
virtual u32 GetBoundBuffer() const = 0; |
|||
}; |
|||
|
|||
} // namespace Tegra::Engines |
|||
@ -0,0 +1,110 @@ |
|||
// Copyright 2019 yuzu Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#pragma once
|
|||
|
|||
#include <algorithm>
|
|||
#include <memory>
|
|||
#include "common/assert.h"
|
|||
#include "common/common_types.h"
|
|||
#include "video_core/engines/maxwell_3d.h"
|
|||
#include "video_core/shader/const_buffer_locker.h"
|
|||
|
|||
namespace VideoCommon::Shader { |
|||
|
|||
using Tegra::Engines::SamplerDescriptor; |
|||
|
|||
ConstBufferLocker::ConstBufferLocker(Tegra::Engines::ShaderType shader_stage) |
|||
: stage{shader_stage} {} |
|||
|
|||
ConstBufferLocker::ConstBufferLocker(Tegra::Engines::ShaderType shader_stage, |
|||
Tegra::Engines::ConstBufferEngineInterface& engine) |
|||
: stage{shader_stage}, engine{&engine} {} |
|||
|
|||
ConstBufferLocker::~ConstBufferLocker() = default; |
|||
|
|||
std::optional<u32> ConstBufferLocker::ObtainKey(u32 buffer, u32 offset) { |
|||
const std::pair<u32, u32> key = {buffer, offset}; |
|||
const auto iter = keys.find(key); |
|||
if (iter != keys.end()) { |
|||
return iter->second; |
|||
} |
|||
if (!engine) { |
|||
return std::nullopt; |
|||
} |
|||
const u32 value = engine->AccessConstBuffer32(stage, buffer, offset); |
|||
keys.emplace(key, value); |
|||
return value; |
|||
} |
|||
|
|||
std::optional<SamplerDescriptor> ConstBufferLocker::ObtainBoundSampler(u32 offset) { |
|||
const u32 key = offset; |
|||
const auto iter = bound_samplers.find(key); |
|||
if (iter != bound_samplers.end()) { |
|||
return iter->second; |
|||
} |
|||
if (!engine) { |
|||
return std::nullopt; |
|||
} |
|||
const SamplerDescriptor value = engine->AccessBoundSampler(stage, offset); |
|||
bound_samplers.emplace(key, value); |
|||
return value; |
|||
} |
|||
|
|||
std::optional<Tegra::Engines::SamplerDescriptor> ConstBufferLocker::ObtainBindlessSampler( |
|||
u32 buffer, u32 offset) { |
|||
const std::pair key = {buffer, offset}; |
|||
const auto iter = bindless_samplers.find(key); |
|||
if (iter != bindless_samplers.end()) { |
|||
return iter->second; |
|||
} |
|||
if (!engine) { |
|||
return std::nullopt; |
|||
} |
|||
const SamplerDescriptor value = engine->AccessBindlessSampler(stage, buffer, offset); |
|||
bindless_samplers.emplace(key, value); |
|||
return value; |
|||
} |
|||
|
|||
void ConstBufferLocker::InsertKey(u32 buffer, u32 offset, u32 value) { |
|||
keys.insert_or_assign({buffer, offset}, value); |
|||
} |
|||
|
|||
void ConstBufferLocker::InsertBoundSampler(u32 offset, SamplerDescriptor sampler) { |
|||
bound_samplers.insert_or_assign(offset, sampler); |
|||
} |
|||
|
|||
void ConstBufferLocker::InsertBindlessSampler(u32 buffer, u32 offset, SamplerDescriptor sampler) { |
|||
bindless_samplers.insert_or_assign({buffer, offset}, sampler); |
|||
} |
|||
|
|||
bool ConstBufferLocker::IsConsistent() const { |
|||
if (!engine) { |
|||
return false; |
|||
} |
|||
return std::all_of(keys.begin(), keys.end(), |
|||
[this](const auto& pair) { |
|||
const auto [cbuf, offset] = pair.first; |
|||
const auto value = pair.second; |
|||
return value == engine->AccessConstBuffer32(stage, cbuf, offset); |
|||
}) && |
|||
std::all_of(bound_samplers.begin(), bound_samplers.end(), |
|||
[this](const auto& sampler) { |
|||
const auto [key, value] = sampler; |
|||
return value == engine->AccessBoundSampler(stage, key); |
|||
}) && |
|||
std::all_of(bindless_samplers.begin(), bindless_samplers.end(), |
|||
[this](const auto& sampler) { |
|||
const auto [cbuf, offset] = sampler.first; |
|||
const auto value = sampler.second; |
|||
return value == engine->AccessBindlessSampler(stage, cbuf, offset); |
|||
}); |
|||
} |
|||
|
|||
bool ConstBufferLocker::HasEqualKeys(const ConstBufferLocker& rhs) const { |
|||
return keys == rhs.keys && bound_samplers == rhs.bound_samplers && |
|||
bindless_samplers == rhs.bindless_samplers; |
|||
} |
|||
|
|||
} // namespace VideoCommon::Shader
|
|||
@ -0,0 +1,80 @@ |
|||
// Copyright 2019 yuzu Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include <unordered_map> |
|||
#include "common/common_types.h" |
|||
#include "common/hash.h" |
|||
#include "video_core/engines/const_buffer_engine_interface.h" |
|||
|
|||
namespace VideoCommon::Shader { |
|||
|
|||
using KeyMap = std::unordered_map<std::pair<u32, u32>, u32, Common::PairHash>; |
|||
using BoundSamplerMap = std::unordered_map<u32, Tegra::Engines::SamplerDescriptor>; |
|||
using BindlessSamplerMap = |
|||
std::unordered_map<std::pair<u32, u32>, Tegra::Engines::SamplerDescriptor, Common::PairHash>; |
|||
|
|||
/** |
|||
* The ConstBufferLocker is a class use to interface the 3D and compute engines with the shader |
|||
* compiler. with it, the shader can obtain required data from GPU state and store it for disk |
|||
* shader compilation. |
|||
**/ |
|||
class ConstBufferLocker { |
|||
public: |
|||
explicit ConstBufferLocker(Tegra::Engines::ShaderType shader_stage); |
|||
|
|||
explicit ConstBufferLocker(Tegra::Engines::ShaderType shader_stage, |
|||
Tegra::Engines::ConstBufferEngineInterface& engine); |
|||
|
|||
~ConstBufferLocker(); |
|||
|
|||
/// Retrieves a key from the locker, if it's registered, it will give the registered value, if |
|||
/// not it will obtain it from maxwell3d and register it. |
|||
std::optional<u32> ObtainKey(u32 buffer, u32 offset); |
|||
|
|||
std::optional<Tegra::Engines::SamplerDescriptor> ObtainBoundSampler(u32 offset); |
|||
|
|||
std::optional<Tegra::Engines::SamplerDescriptor> ObtainBindlessSampler(u32 buffer, u32 offset); |
|||
|
|||
/// Inserts a key. |
|||
void InsertKey(u32 buffer, u32 offset, u32 value); |
|||
|
|||
/// Inserts a bound sampler key. |
|||
void InsertBoundSampler(u32 offset, Tegra::Engines::SamplerDescriptor sampler); |
|||
|
|||
/// Inserts a bindless sampler key. |
|||
void InsertBindlessSampler(u32 buffer, u32 offset, Tegra::Engines::SamplerDescriptor sampler); |
|||
|
|||
/// Checks keys and samplers against engine's current const buffers. Returns true if they are |
|||
/// the same value, false otherwise; |
|||
bool IsConsistent() const; |
|||
|
|||
/// Returns true if the keys are equal to the other ones in the locker. |
|||
bool HasEqualKeys(const ConstBufferLocker& rhs) const; |
|||
|
|||
/// Gives an getter to the const buffer keys in the database. |
|||
const KeyMap& GetKeys() const { |
|||
return keys; |
|||
} |
|||
|
|||
/// Gets samplers database. |
|||
const BoundSamplerMap& GetBoundSamplers() const { |
|||
return bound_samplers; |
|||
} |
|||
|
|||
/// Gets bindless samplers database. |
|||
const BindlessSamplerMap& GetBindlessSamplers() const { |
|||
return bindless_samplers; |
|||
} |
|||
|
|||
private: |
|||
const Tegra::Engines::ShaderType stage; |
|||
Tegra::Engines::ConstBufferEngineInterface* engine = nullptr; |
|||
KeyMap keys; |
|||
BoundSamplerMap bound_samplers; |
|||
BindlessSamplerMap bindless_samplers; |
|||
}; |
|||
|
|||
} // namespace VideoCommon::Shader |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue