2019-04-10 20:56:12 +02:00
|
|
|
// Copyright 2019 yuzu Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
2019-09-18 06:07:01 +02:00
|
|
|
#include <algorithm>
|
2019-05-24 01:19:56 +02:00
|
|
|
#include <array>
|
2019-04-10 20:56:12 +02:00
|
|
|
#include <cstddef>
|
2020-12-30 06:25:23 +01:00
|
|
|
#include <cstdlib>
|
2019-12-11 04:00:30 +01:00
|
|
|
#include <cstring>
|
2020-05-28 22:06:22 +02:00
|
|
|
#include <limits>
|
2019-11-23 01:22:01 +01:00
|
|
|
#include <optional>
|
2020-12-30 06:25:23 +01:00
|
|
|
#include <span>
|
2021-10-16 08:07:18 +02:00
|
|
|
#include <stdexcept>
|
2019-09-18 06:07:01 +02:00
|
|
|
#include <vector>
|
2019-11-23 01:22:01 +01:00
|
|
|
|
2019-04-10 20:56:12 +02:00
|
|
|
#include <glad/glad.h>
|
|
|
|
|
2019-04-10 23:03:52 +02:00
|
|
|
#include "common/logging/log.h"
|
2019-05-24 01:19:56 +02:00
|
|
|
#include "common/scope_exit.h"
|
2021-04-15 01:07:40 +02:00
|
|
|
#include "common/settings.h"
|
2021-06-23 07:41:00 +02:00
|
|
|
#include "shader_recompiler/stage.h"
|
2019-04-10 20:56:12 +02:00
|
|
|
#include "video_core/renderer_opengl/gl_device.h"
|
2019-05-24 01:19:56 +02:00
|
|
|
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
2019-04-10 20:56:12 +02:00
|
|
|
|
|
|
|
namespace OpenGL {
|
|
|
|
namespace {
|
2020-12-30 06:25:23 +01:00
|
|
|
constexpr std::array LIMIT_UBOS = {
|
2020-05-28 22:06:22 +02:00
|
|
|
GL_MAX_VERTEX_UNIFORM_BLOCKS, GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS,
|
|
|
|
GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS, GL_MAX_GEOMETRY_UNIFORM_BLOCKS,
|
2020-12-30 06:25:23 +01:00
|
|
|
GL_MAX_FRAGMENT_UNIFORM_BLOCKS, GL_MAX_COMPUTE_UNIFORM_BLOCKS,
|
|
|
|
};
|
2019-11-23 01:22:01 +01:00
|
|
|
|
2019-04-10 20:56:12 +02:00
|
|
|
template <typename T>
|
|
|
|
T GetInteger(GLenum pname) {
|
|
|
|
GLint temporary;
|
|
|
|
glGetIntegerv(pname, &temporary);
|
|
|
|
return static_cast<T>(temporary);
|
|
|
|
}
|
2019-08-31 08:03:35 +02:00
|
|
|
|
|
|
|
bool TestProgram(const GLchar* glsl) {
|
|
|
|
const GLuint shader{glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &glsl)};
|
|
|
|
GLint link_status;
|
|
|
|
glGetProgramiv(shader, GL_LINK_STATUS, &link_status);
|
|
|
|
glDeleteProgram(shader);
|
|
|
|
return link_status == GL_TRUE;
|
|
|
|
}
|
|
|
|
|
2019-09-18 06:07:01 +02:00
|
|
|
std::vector<std::string_view> GetExtensions() {
|
|
|
|
GLint num_extensions;
|
|
|
|
glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
|
|
|
|
std::vector<std::string_view> extensions;
|
|
|
|
extensions.reserve(num_extensions);
|
|
|
|
for (GLint index = 0; index < num_extensions; ++index) {
|
|
|
|
extensions.push_back(
|
|
|
|
reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, static_cast<GLuint>(index))));
|
|
|
|
}
|
|
|
|
return extensions;
|
|
|
|
}
|
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
bool HasExtension(std::span<const std::string_view> extensions, std::string_view extension) {
|
|
|
|
return std::ranges::find(extensions, extension) != extensions.end();
|
2019-09-18 06:07:01 +02:00
|
|
|
}
|
|
|
|
|
2021-06-23 07:41:00 +02:00
|
|
|
std::array<u32, Shader::MaxStageTypes> BuildMaxUniformBuffers() noexcept {
|
|
|
|
std::array<u32, Shader::MaxStageTypes> max;
|
|
|
|
std::ranges::transform(LIMIT_UBOS, max.begin(), &GetInteger<u32>);
|
2020-05-28 22:06:22 +02:00
|
|
|
return max;
|
|
|
|
}
|
|
|
|
|
2020-03-15 00:21:26 +01:00
|
|
|
bool IsASTCSupported() {
|
2021-06-23 07:41:00 +02:00
|
|
|
static constexpr std::array targets{
|
|
|
|
GL_TEXTURE_2D,
|
|
|
|
GL_TEXTURE_2D_ARRAY,
|
|
|
|
};
|
|
|
|
static constexpr std::array formats{
|
2020-03-15 00:21:26 +01:00
|
|
|
GL_COMPRESSED_RGBA_ASTC_4x4_KHR, GL_COMPRESSED_RGBA_ASTC_5x4_KHR,
|
|
|
|
GL_COMPRESSED_RGBA_ASTC_5x5_KHR, GL_COMPRESSED_RGBA_ASTC_6x5_KHR,
|
|
|
|
GL_COMPRESSED_RGBA_ASTC_6x6_KHR, GL_COMPRESSED_RGBA_ASTC_8x5_KHR,
|
|
|
|
GL_COMPRESSED_RGBA_ASTC_8x6_KHR, GL_COMPRESSED_RGBA_ASTC_8x8_KHR,
|
|
|
|
GL_COMPRESSED_RGBA_ASTC_10x5_KHR, GL_COMPRESSED_RGBA_ASTC_10x6_KHR,
|
|
|
|
GL_COMPRESSED_RGBA_ASTC_10x8_KHR, GL_COMPRESSED_RGBA_ASTC_10x10_KHR,
|
|
|
|
GL_COMPRESSED_RGBA_ASTC_12x10_KHR, GL_COMPRESSED_RGBA_ASTC_12x12_KHR,
|
|
|
|
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR,
|
|
|
|
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR,
|
|
|
|
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR,
|
|
|
|
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR,
|
|
|
|
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR,
|
|
|
|
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR,
|
|
|
|
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR,
|
|
|
|
};
|
2021-06-23 07:41:00 +02:00
|
|
|
static constexpr std::array required_support{
|
2020-05-29 09:21:57 +02:00
|
|
|
GL_VERTEX_TEXTURE, GL_TESS_CONTROL_TEXTURE, GL_TESS_EVALUATION_TEXTURE,
|
|
|
|
GL_GEOMETRY_TEXTURE, GL_FRAGMENT_TEXTURE, GL_COMPUTE_TEXTURE,
|
|
|
|
};
|
|
|
|
for (const GLenum target : targets) {
|
|
|
|
for (const GLenum format : formats) {
|
|
|
|
for (const GLenum support : required_support) {
|
|
|
|
GLint value;
|
2020-06-25 11:12:56 +02:00
|
|
|
glGetInternalformativ(target, format, support, 1, &value);
|
2020-05-29 09:21:57 +02:00
|
|
|
if (value != GL_FULL_SUPPORT) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
2020-03-15 00:21:26 +01:00
|
|
|
}
|
|
|
|
|
2020-12-30 06:25:23 +01:00
|
|
|
[[nodiscard]] bool IsDebugToolAttached(std::span<const std::string_view> extensions) {
|
|
|
|
const bool nsight = std::getenv("NVTX_INJECTION64_PATH") || std::getenv("NSIGHT_LAUNCHED");
|
|
|
|
return nsight || HasExtension(extensions, "GL_EXT_debug_tool");
|
|
|
|
}
|
2019-04-10 20:56:12 +02:00
|
|
|
} // Anonymous namespace
|
|
|
|
|
2021-01-18 23:04:27 +01:00
|
|
|
Device::Device() {
|
2021-01-17 00:48:58 +01:00
|
|
|
if (!GLAD_GL_VERSION_4_6) {
|
|
|
|
LOG_ERROR(Render_OpenGL, "OpenGL 4.6 is not available");
|
|
|
|
throw std::runtime_error{"Insufficient version"};
|
|
|
|
}
|
2021-06-20 23:26:55 +02:00
|
|
|
vendor_name = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
|
2020-06-06 07:56:42 +02:00
|
|
|
const std::string_view version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
|
2019-09-18 06:07:01 +02:00
|
|
|
const std::vector extensions = GetExtensions();
|
|
|
|
|
2021-06-20 23:26:55 +02:00
|
|
|
const bool is_nvidia = vendor_name == "NVIDIA Corporation";
|
|
|
|
const bool is_amd = vendor_name == "ATI Technologies Inc.";
|
|
|
|
const bool is_intel = vendor_name == "Intel";
|
2019-11-02 08:08:31 +01:00
|
|
|
|
2021-03-23 14:54:35 +01:00
|
|
|
#ifdef __unix__
|
2021-03-21 06:25:45 +01:00
|
|
|
const bool is_linux = true;
|
|
|
|
#else
|
|
|
|
const bool is_linux = false;
|
|
|
|
#endif
|
|
|
|
|
2020-06-06 07:56:42 +02:00
|
|
|
bool disable_fast_buffer_sub_data = false;
|
|
|
|
if (is_nvidia && version == "4.6.0 NVIDIA 443.24") {
|
|
|
|
LOG_WARNING(
|
|
|
|
Render_OpenGL,
|
|
|
|
"Beta driver 443.24 is known to have issues. There might be performance issues.");
|
|
|
|
disable_fast_buffer_sub_data = true;
|
|
|
|
}
|
2021-01-17 00:48:58 +01:00
|
|
|
max_uniform_buffers = BuildMaxUniformBuffers();
|
2020-12-30 06:25:23 +01:00
|
|
|
uniform_buffer_alignment = GetInteger<size_t>(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT);
|
|
|
|
shader_storage_alignment = GetInteger<size_t>(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT);
|
2019-04-30 05:09:51 +02:00
|
|
|
max_vertex_attributes = GetInteger<u32>(GL_MAX_VERTEX_ATTRIBS);
|
|
|
|
max_varyings = GetInteger<u32>(GL_MAX_VARYING_VECTORS);
|
2020-07-16 21:02:46 +02:00
|
|
|
max_compute_shared_memory_size = GetInteger<u32>(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE);
|
2021-05-26 23:32:59 +02:00
|
|
|
max_glasm_storage_buffer_blocks = GetInteger<u32>(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS);
|
2019-08-10 04:50:21 +02:00
|
|
|
has_warp_intrinsics = GLAD_GL_NV_gpu_shader5 && GLAD_GL_NV_shader_thread_group &&
|
|
|
|
GLAD_GL_NV_shader_thread_shuffle;
|
2019-11-08 00:03:50 +01:00
|
|
|
has_shader_ballot = GLAD_GL_ARB_shader_ballot;
|
2019-07-08 01:36:42 +02:00
|
|
|
has_vertex_viewport_layer = GLAD_GL_ARB_shader_viewport_layer_array;
|
2019-09-18 06:07:01 +02:00
|
|
|
has_image_load_formatted = HasExtension(extensions, "GL_EXT_shader_image_load_formatted");
|
2020-06-20 13:41:55 +02:00
|
|
|
has_texture_shadow_lod = HasExtension(extensions, "GL_EXT_texture_shadow_lod");
|
2020-03-15 00:21:26 +01:00
|
|
|
has_astc = IsASTCSupported();
|
2019-04-10 23:03:52 +02:00
|
|
|
has_variable_aoffi = TestVariableAoffi();
|
2019-11-20 03:55:17 +01:00
|
|
|
has_component_indexing_bug = is_amd;
|
2019-08-31 08:03:35 +02:00
|
|
|
has_precise_bug = TestPreciseBug();
|
2021-04-26 18:14:10 +02:00
|
|
|
has_broken_texture_view_formats = is_amd || (!is_linux && is_intel);
|
2020-06-03 23:07:35 +02:00
|
|
|
has_nv_viewport_array2 = GLAD_GL_NV_viewport_array2;
|
2021-06-02 08:02:33 +02:00
|
|
|
has_derivative_control = GLAD_GL_ARB_derivative_control;
|
2020-06-25 06:28:45 +02:00
|
|
|
has_vertex_buffer_unified_memory = GLAD_GL_NV_vertex_buffer_unified_memory;
|
2020-12-30 06:25:23 +01:00
|
|
|
has_debugging_tool_attached = IsDebugToolAttached(extensions);
|
2021-02-24 23:04:51 +01:00
|
|
|
has_depth_buffer_float = HasExtension(extensions, "GL_NV_depth_buffer_float");
|
2021-06-24 22:40:24 +02:00
|
|
|
has_geometry_shader_passthrough = GLAD_GL_NV_geometry_shader_passthrough;
|
2021-05-26 01:55:40 +02:00
|
|
|
has_nv_gpu_shader_5 = GLAD_GL_NV_gpu_shader5;
|
2021-06-23 06:39:21 +02:00
|
|
|
has_shader_int64 = HasExtension(extensions, "GL_ARB_gpu_shader_int64");
|
2021-05-26 01:55:40 +02:00
|
|
|
has_amd_shader_half_float = GLAD_GL_AMD_gpu_shader_half_float;
|
2021-06-13 06:05:19 +02:00
|
|
|
has_sparse_texture_2 = GLAD_GL_ARB_sparse_texture2;
|
2021-05-30 06:53:26 +02:00
|
|
|
warp_size_potentially_larger_than_guest = !is_nvidia && !is_intel;
|
2021-06-15 23:23:57 +02:00
|
|
|
need_fastmath_off = is_nvidia;
|
2020-06-18 08:54:13 +02:00
|
|
|
|
|
|
|
// At the moment of writing this, only Nvidia's driver optimizes BufferSubData on exclusive
|
|
|
|
// uniform buffers as "push constants"
|
|
|
|
has_fast_buffer_sub_data = is_nvidia && !disable_fast_buffer_sub_data;
|
|
|
|
|
2021-07-17 06:59:57 +02:00
|
|
|
shader_backend = Settings::values.shader_backend.GetValue();
|
|
|
|
use_assembly_shaders = shader_backend == Settings::ShaderBackend::GLASM &&
|
|
|
|
GLAD_GL_NV_gpu_program5 && GLAD_GL_NV_compute_program5 &&
|
|
|
|
GLAD_GL_NV_transform_feedback && GLAD_GL_NV_transform_feedback2;
|
|
|
|
if (shader_backend == Settings::ShaderBackend::GLASM && !use_assembly_shaders) {
|
|
|
|
LOG_ERROR(Render_OpenGL, "Assembly shaders enabled but not supported");
|
|
|
|
shader_backend = Settings::ShaderBackend::GLSL;
|
|
|
|
}
|
2021-10-29 01:04:06 +02:00
|
|
|
|
|
|
|
if (shader_backend == Settings::ShaderBackend::GLSL && is_nvidia &&
|
|
|
|
!Settings::values.renderer_debug) {
|
|
|
|
const std::string_view driver_version = version.substr(13);
|
|
|
|
const int version_major =
|
|
|
|
std::atoi(driver_version.substr(0, driver_version.find(".")).data());
|
|
|
|
|
|
|
|
if (version_major >= 495) {
|
|
|
|
LOG_WARNING(Render_OpenGL, "NVIDIA drivers 495 and later causes significant problems "
|
|
|
|
"with yuzu. Forcing GLASM as a mitigation.");
|
|
|
|
shader_backend = Settings::ShaderBackend::GLASM;
|
|
|
|
use_assembly_shaders = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-21 06:25:45 +01:00
|
|
|
// Blocks AMD and Intel OpenGL drivers on Windows from using asynchronous shader compilation.
|
2021-07-20 08:08:06 +02:00
|
|
|
use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue() &&
|
|
|
|
!(is_amd || (is_intel && !is_linux));
|
2021-01-21 00:09:57 +01:00
|
|
|
use_driver_cache = is_nvidia;
|
2020-07-10 05:36:38 +02:00
|
|
|
|
2019-08-31 08:03:35 +02:00
|
|
|
LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi);
|
|
|
|
LOG_INFO(Render_OpenGL, "Renderer_ComponentIndexingBug: {}", has_component_indexing_bug);
|
|
|
|
LOG_INFO(Render_OpenGL, "Renderer_PreciseBug: {}", has_precise_bug);
|
2021-01-04 05:56:44 +01:00
|
|
|
LOG_INFO(Render_OpenGL, "Renderer_BrokenTextureViewFormats: {}",
|
|
|
|
has_broken_texture_view_formats);
|
2021-03-21 06:25:45 +01:00
|
|
|
if (Settings::values.use_asynchronous_shaders.GetValue() && !use_asynchronous_shaders) {
|
|
|
|
LOG_WARNING(Render_OpenGL, "Asynchronous shader compilation enabled but not supported");
|
|
|
|
}
|
2019-04-10 23:03:52 +02:00
|
|
|
}
|
|
|
|
|
2021-06-20 23:26:55 +02:00
|
|
|
std::string Device::GetVendorName() const {
|
|
|
|
if (vendor_name == "NVIDIA Corporation") {
|
|
|
|
return "NVIDIA";
|
|
|
|
}
|
|
|
|
if (vendor_name == "ATI Technologies Inc.") {
|
|
|
|
return "AMD";
|
|
|
|
}
|
2021-06-21 03:12:39 +02:00
|
|
|
if (vendor_name == "Intel") {
|
|
|
|
// For Mesa, `Intel` is an overloaded vendor string that could mean crocus or iris.
|
|
|
|
// Simply return `INTEL` for those as well as the Windows driver.
|
2021-06-20 23:26:55 +02:00
|
|
|
return "INTEL";
|
|
|
|
}
|
2021-06-21 03:12:39 +02:00
|
|
|
if (vendor_name == "Intel Open Source Technology Center") {
|
|
|
|
return "I965";
|
|
|
|
}
|
2021-06-20 23:26:55 +02:00
|
|
|
if (vendor_name == "Mesa Project") {
|
2021-06-21 03:12:39 +02:00
|
|
|
return "I915";
|
2021-06-20 23:26:55 +02:00
|
|
|
}
|
|
|
|
if (vendor_name == "Mesa/X.org") {
|
2021-06-21 03:12:39 +02:00
|
|
|
// This vendor string is overloaded between llvmpipe, softpipe, and virgl, so just return
|
|
|
|
// MESA instead of one of those driver names.
|
|
|
|
return "MESA";
|
2021-06-20 23:26:55 +02:00
|
|
|
}
|
|
|
|
if (vendor_name == "AMD") {
|
|
|
|
return "RADEONSI";
|
|
|
|
}
|
|
|
|
if (vendor_name == "nouveau") {
|
|
|
|
return "NOUVEAU";
|
|
|
|
}
|
2021-06-21 03:12:39 +02:00
|
|
|
if (vendor_name == "X.Org") {
|
|
|
|
return "R600";
|
|
|
|
}
|
|
|
|
if (vendor_name == "Collabora Ltd") {
|
|
|
|
return "ZINK";
|
|
|
|
}
|
|
|
|
if (vendor_name == "Intel Corporation") {
|
|
|
|
return "OPENSWR";
|
|
|
|
}
|
|
|
|
if (vendor_name == "Microsoft Corporation") {
|
|
|
|
return "D3D12";
|
|
|
|
}
|
|
|
|
if (vendor_name == "NVIDIA") {
|
|
|
|
// Mesa's tegra driver reports `NVIDIA`. Only present in this list because the default
|
|
|
|
// strategy would have returned `NVIDIA` here for this driver, the same result as the
|
|
|
|
// proprietary driver.
|
|
|
|
return "TEGRA";
|
|
|
|
}
|
2021-06-20 23:26:55 +02:00
|
|
|
return vendor_name;
|
|
|
|
}
|
|
|
|
|
2019-04-10 23:03:52 +02:00
|
|
|
bool Device::TestVariableAoffi() {
|
2019-08-31 08:03:35 +02:00
|
|
|
return TestProgram(R"(#version 430 core
|
2019-05-27 05:52:49 +02:00
|
|
|
// This is a unit test, please ignore me on apitrace bug reports.
|
2019-04-10 23:03:52 +02:00
|
|
|
uniform sampler2D tex;
|
|
|
|
uniform ivec2 variable_offset;
|
2019-06-12 04:02:50 +02:00
|
|
|
out vec4 output_attribute;
|
2019-04-10 23:03:52 +02:00
|
|
|
void main() {
|
2019-06-12 04:02:50 +02:00
|
|
|
output_attribute = textureOffset(tex, vec2(0), variable_offset);
|
2019-08-31 08:03:35 +02:00
|
|
|
})");
|
2019-04-10 20:56:12 +02:00
|
|
|
}
|
|
|
|
|
2019-08-31 08:03:35 +02:00
|
|
|
bool Device::TestPreciseBug() {
|
|
|
|
return !TestProgram(R"(#version 430 core
|
|
|
|
in vec3 coords;
|
|
|
|
out float out_value;
|
|
|
|
uniform sampler2DShadow tex;
|
|
|
|
void main() {
|
|
|
|
precise float tmp_value = vec4(texture(tex, coords)).x;
|
|
|
|
out_value = tmp_value;
|
|
|
|
})");
|
|
|
|
}
|
|
|
|
|
2019-04-10 20:56:12 +02:00
|
|
|
} // namespace OpenGL
|