|
|
|
@ -239,6 +239,15 @@ void SetXfbState(VideoCommon::TransformFeedbackState& state, const Maxwell& regs |
|
|
|
} |
|
|
|
} // Anonymous namespace
|
|
|
|
|
|
|
|
struct ShaderCache::Context { |
|
|
|
explicit Context(Core::Frontend::EmuWindow& emu_window) |
|
|
|
: gl_context{emu_window.CreateSharedContext()}, scoped{*gl_context} {} |
|
|
|
|
|
|
|
std::unique_ptr<Core::Frontend::GraphicsContext> gl_context; |
|
|
|
Core::Frontend::GraphicsContext::Scoped scoped; |
|
|
|
ShaderPools pools; |
|
|
|
}; |
|
|
|
|
|
|
|
ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindow& emu_window_, |
|
|
|
Tegra::Engines::Maxwell3D& maxwell3d_, |
|
|
|
Tegra::Engines::KeplerCompute& kepler_compute_, |
|
|
|
@ -247,46 +256,49 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo |
|
|
|
ProgramManager& program_manager_, StateTracker& state_tracker_) |
|
|
|
: VideoCommon::ShaderCache{rasterizer_, gpu_memory_, maxwell3d_, kepler_compute_}, |
|
|
|
emu_window{emu_window_}, device{device_}, texture_cache{texture_cache_}, |
|
|
|
buffer_cache{buffer_cache_}, program_manager{program_manager_}, state_tracker{ |
|
|
|
state_tracker_} { |
|
|
|
profile = Shader::Profile{ |
|
|
|
.supported_spirv = 0x00010000, |
|
|
|
|
|
|
|
.unified_descriptor_binding = false, |
|
|
|
.support_descriptor_aliasing = false, |
|
|
|
.support_int8 = false, |
|
|
|
.support_int16 = false, |
|
|
|
.support_vertex_instance_id = true, |
|
|
|
.support_float_controls = false, |
|
|
|
.support_separate_denorm_behavior = false, |
|
|
|
.support_separate_rounding_mode = false, |
|
|
|
.support_fp16_denorm_preserve = false, |
|
|
|
.support_fp32_denorm_preserve = false, |
|
|
|
.support_fp16_denorm_flush = false, |
|
|
|
.support_fp32_denorm_flush = false, |
|
|
|
.support_fp16_signed_zero_nan_preserve = false, |
|
|
|
.support_fp32_signed_zero_nan_preserve = false, |
|
|
|
.support_fp64_signed_zero_nan_preserve = false, |
|
|
|
.support_explicit_workgroup_layout = false, |
|
|
|
.support_vote = true, |
|
|
|
.support_viewport_index_layer_non_geometry = |
|
|
|
device.HasNvViewportArray2() || device.HasVertexViewportLayer(), |
|
|
|
.support_viewport_mask = device.HasNvViewportArray2(), |
|
|
|
.support_typeless_image_loads = device.HasImageLoadFormatted(), |
|
|
|
.support_demote_to_helper_invocation = false, |
|
|
|
.support_int64_atomics = false, |
|
|
|
.support_derivative_control = device.HasDerivativeControl(), |
|
|
|
|
|
|
|
.warp_size_potentially_larger_than_guest = true, |
|
|
|
|
|
|
|
.lower_left_origin_mode = true, |
|
|
|
.need_declared_frag_colors = true, |
|
|
|
|
|
|
|
.has_broken_spirv_clamp = true, |
|
|
|
.has_broken_unsigned_image_offsets = true, |
|
|
|
.has_broken_signed_operations = true, |
|
|
|
.ignore_nan_fp_comparisons = true, |
|
|
|
}; |
|
|
|
buffer_cache{buffer_cache_}, program_manager{program_manager_}, state_tracker{state_tracker_}, |
|
|
|
use_asynchronous_shaders{device.UseAsynchronousShaders()}, |
|
|
|
profile{ |
|
|
|
.supported_spirv = 0x00010000, |
|
|
|
|
|
|
|
.unified_descriptor_binding = false, |
|
|
|
.support_descriptor_aliasing = false, |
|
|
|
.support_int8 = false, |
|
|
|
.support_int16 = false, |
|
|
|
.support_vertex_instance_id = true, |
|
|
|
.support_float_controls = false, |
|
|
|
.support_separate_denorm_behavior = false, |
|
|
|
.support_separate_rounding_mode = false, |
|
|
|
.support_fp16_denorm_preserve = false, |
|
|
|
.support_fp32_denorm_preserve = false, |
|
|
|
.support_fp16_denorm_flush = false, |
|
|
|
.support_fp32_denorm_flush = false, |
|
|
|
.support_fp16_signed_zero_nan_preserve = false, |
|
|
|
.support_fp32_signed_zero_nan_preserve = false, |
|
|
|
.support_fp64_signed_zero_nan_preserve = false, |
|
|
|
.support_explicit_workgroup_layout = false, |
|
|
|
.support_vote = true, |
|
|
|
.support_viewport_index_layer_non_geometry = |
|
|
|
device.HasNvViewportArray2() || device.HasVertexViewportLayer(), |
|
|
|
.support_viewport_mask = device.HasNvViewportArray2(), |
|
|
|
.support_typeless_image_loads = device.HasImageLoadFormatted(), |
|
|
|
.support_demote_to_helper_invocation = false, |
|
|
|
.support_int64_atomics = false, |
|
|
|
.support_derivative_control = device.HasDerivativeControl(), |
|
|
|
|
|
|
|
.warp_size_potentially_larger_than_guest = true, |
|
|
|
|
|
|
|
.lower_left_origin_mode = true, |
|
|
|
.need_declared_frag_colors = true, |
|
|
|
|
|
|
|
.has_broken_spirv_clamp = true, |
|
|
|
.has_broken_unsigned_image_offsets = true, |
|
|
|
.has_broken_signed_operations = true, |
|
|
|
.ignore_nan_fp_comparisons = true, |
|
|
|
} { |
|
|
|
if (use_asynchronous_shaders) { |
|
|
|
workers = CreateWorkers(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
ShaderCache::~ShaderCache() = default; |
|
|
|
@ -307,29 +319,20 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading, |
|
|
|
} |
|
|
|
shader_cache_filename = transferable_dir / fmt::format("{:016x}.bin", title_id); |
|
|
|
|
|
|
|
struct Context { |
|
|
|
explicit Context(Core::Frontend::EmuWindow& emu_window) |
|
|
|
: gl_context{emu_window.CreateSharedContext()}, scoped{*gl_context} {} |
|
|
|
|
|
|
|
std::unique_ptr<Core::Frontend::GraphicsContext> gl_context; |
|
|
|
Core::Frontend::GraphicsContext::Scoped scoped; |
|
|
|
ShaderPools pools; |
|
|
|
}; |
|
|
|
Common::StatefulThreadWorker<Context> workers( |
|
|
|
std::max(std::thread::hardware_concurrency(), 2U) - 1, "yuzu:ShaderBuilder", |
|
|
|
[this] { return Context{emu_window}; }); |
|
|
|
|
|
|
|
if (!workers) { |
|
|
|
workers = CreateWorkers(); |
|
|
|
} |
|
|
|
struct { |
|
|
|
std::mutex mutex; |
|
|
|
size_t total{0}; |
|
|
|
size_t built{0}; |
|
|
|
bool has_loaded{false}; |
|
|
|
size_t total{}; |
|
|
|
size_t built{}; |
|
|
|
bool has_loaded{}; |
|
|
|
} state; |
|
|
|
|
|
|
|
const auto load_compute{[&](std::ifstream& file, FileEnvironment env) { |
|
|
|
ComputePipelineKey key; |
|
|
|
file.read(reinterpret_cast<char*>(&key), sizeof(key)); |
|
|
|
workers.QueueWork( |
|
|
|
workers->QueueWork( |
|
|
|
[this, key, env = std::move(env), &state, &callback](Context* ctx) mutable { |
|
|
|
ctx->pools.ReleaseContents(); |
|
|
|
auto pipeline{CreateComputePipeline(ctx->pools, key, env)}; |
|
|
|
@ -347,7 +350,7 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading, |
|
|
|
const auto load_graphics{[&](std::ifstream& file, std::vector<FileEnvironment> envs) { |
|
|
|
GraphicsPipelineKey key; |
|
|
|
file.read(reinterpret_cast<char*>(&key), sizeof(key)); |
|
|
|
workers.QueueWork( |
|
|
|
workers->QueueWork( |
|
|
|
[this, key, envs = std::move(envs), &state, &callback](Context* ctx) mutable { |
|
|
|
boost::container::static_vector<Shader::Environment*, 5> env_ptrs; |
|
|
|
for (auto& env : envs) { |
|
|
|
@ -373,7 +376,10 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading, |
|
|
|
state.has_loaded = true; |
|
|
|
lock.unlock(); |
|
|
|
|
|
|
|
workers.WaitForRequests(); |
|
|
|
workers->WaitForRequests(); |
|
|
|
if (!use_asynchronous_shaders) { |
|
|
|
workers.reset(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
GraphicsPipeline* ShaderCache::CurrentGraphicsPipeline() { |
|
|
|
@ -570,4 +576,11 @@ std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline(ShaderPools& |
|
|
|
return nullptr; |
|
|
|
} |
|
|
|
|
|
|
|
std::unique_ptr<Common::StatefulThreadWorker<ShaderCache::Context>> ShaderCache::CreateWorkers() |
|
|
|
const { |
|
|
|
return std::make_unique<Common::StatefulThreadWorker<Context>>( |
|
|
|
std::max(std::thread::hardware_concurrency(), 2U) - 1, "yuzu:ShaderBuilder", |
|
|
|
[this] { return Context{emu_window}; }); |
|
|
|
} |
|
|
|
|
|
|
|
} // namespace OpenGL
|