diff options
Diffstat (limited to 'src/video_core/renderer_opengl')
35 files changed, 601 insertions, 464 deletions
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp index d4dd10bb6..08f4d69ab 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp @@ -1,6 +1,5 @@ -// Copyright 2018 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> #include <span> @@ -135,6 +134,20 @@ BufferCacheRuntime::BufferCacheRuntime(const Device& device_) buffer.Create(); glNamedBufferData(buffer.handle, 0x10'000, nullptr, GL_STREAM_COPY); } + + device_access_memory = [this]() -> u64 { + if (device.CanReportMemoryUsage()) { + return device.GetCurrentDedicatedVideoMemory() + 512_MiB; + } + return 2_GiB; // Return minimum requirements + }(); +} + +u64 BufferCacheRuntime::GetDeviceMemoryUsage() const { + if (device.CanReportMemoryUsage()) { + return device_access_memory - device.GetCurrentDedicatedVideoMemory(); + } + return 2_GiB; } void BufferCacheRuntime::CopyBuffer(Buffer& dst_buffer, Buffer& src_buffer, @@ -155,7 +168,7 @@ void BufferCacheRuntime::BindIndexBuffer(Buffer& buffer, u32 offset, u32 size) { if (has_unified_vertex_buffers) { buffer.MakeResident(GL_READ_ONLY); glBufferAddressRangeNV(GL_ELEMENT_ARRAY_ADDRESS_NV, 0, buffer.HostGpuAddr() + offset, - static_cast<GLsizeiptr>(size)); + static_cast<GLsizeiptr>(Common::AlignUp(size, 4))); } else { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer.Handle()); index_buffer_offset = offset; diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h index 060d36427..a8c3f8b67 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.h +++ b/src/video_core/renderer_opengl/gl_buffer_cache.h @@ -1,15 +1,12 @@ -// Copyright 2018 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include <array> #include <span> -#include "common/alignment.h" #include "common/common_types.h" -#include "common/dynamic_library.h" #include "video_core/buffer_cache/buffer_cache.h" #include "video_core/rasterizer_interface.h" #include "video_core/renderer_opengl/gl_device.h" @@ -91,6 +88,8 @@ public: void BindImageBuffer(Buffer& buffer, u32 offset, u32 size, VideoCore::Surface::PixelFormat format); + u64 GetDeviceMemoryUsage() const; + void BindFastUniformBuffer(size_t stage, u32 binding_index, u32 size) { const GLuint handle = fast_uniforms[stage][binding_index].handle; const GLsizeiptr gl_size = static_cast<GLsizeiptr>(size); @@ -153,6 +152,14 @@ public: use_storage_buffers = use_storage_buffers_; } + u64 GetDeviceLocalMemory() const { + return device_access_memory; + } + + bool CanReportMemoryUsage() const { + return device.CanReportMemoryUsage(); + } + private: static constexpr std::array PABO_LUT{ GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV, GL_TESS_CONTROL_PROGRAM_PARAMETER_BUFFER_NV, @@ -186,6 +193,8 @@ private: std::array<OGLBuffer, VideoCommon::NUM_COMPUTE_UNIFORM_BUFFERS> copy_compute_uniforms; u32 index_buffer_offset = 0; + + u64 device_access_memory; }; struct BufferCacheParams { diff --git a/src/video_core/renderer_opengl/gl_compute_pipeline.cpp b/src/video_core/renderer_opengl/gl_compute_pipeline.cpp index 5c1f21c65..26d066004 100644 --- a/src/video_core/renderer_opengl/gl_compute_pipeline.cpp +++ b/src/video_core/renderer_opengl/gl_compute_pipeline.cpp @@ -1,6 +1,5 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <cstring> @@ -29,12 +28,11 @@ bool ComputePipelineKey::operator==(const ComputePipelineKey& rhs) const noexcep } ComputePipeline::ComputePipeline(const Device& device, TextureCache& texture_cache_, - BufferCache& buffer_cache_, Tegra::MemoryManager& gpu_memory_, - Tegra::Engines::KeplerCompute& kepler_compute_, - ProgramManager& program_manager_, const Shader::Info& info_, - std::string code, std::vector<u32> code_v) - : texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, gpu_memory{gpu_memory_}, - kepler_compute{kepler_compute_}, program_manager{program_manager_}, info{info_} { + BufferCache& buffer_cache_, ProgramManager& program_manager_, + const Shader::Info& info_, std::string code, + std::vector<u32> code_v) + : texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, + program_manager{program_manager_}, info{info_} { switch (device.GetShaderBackend()) { case Settings::ShaderBackend::GLSL: source_program = CreateProgram(code, GL_COMPUTE_SHADER); @@ -87,7 +85,7 @@ void ComputePipeline::Configure() { GLsizei texture_binding{}; GLsizei image_binding{}; - const auto& qmd{kepler_compute.launch_description}; + const auto& qmd{kepler_compute->launch_description}; const auto& cbufs{qmd.const_buffer_config}; const bool via_header_index{qmd.linked_tsc != 0}; const auto read_handle{[&](const auto& desc, u32 index) { @@ -102,12 +100,13 @@ void ComputePipeline::Configure() { const u32 secondary_offset{desc.secondary_cbuf_offset + index_offset}; const GPUVAddr separate_addr{cbufs[desc.secondary_cbuf_index].Address() + secondary_offset}; - const u32 lhs_raw{gpu_memory.Read<u32>(addr)}; - const u32 rhs_raw{gpu_memory.Read<u32>(separate_addr)}; + const u32 lhs_raw{gpu_memory->Read<u32>(addr) << desc.shift_left}; + const u32 rhs_raw{gpu_memory->Read<u32>(separate_addr) + << desc.secondary_shift_left}; return TexturePair(lhs_raw | rhs_raw, via_header_index); } } - return TexturePair(gpu_memory.Read<u32>(addr), via_header_index); + return TexturePair(gpu_memory->Read<u32>(addr), via_header_index); }}; const auto add_image{[&](const auto& desc, bool blacklist) { for (u32 index = 0; index < desc.count; ++index) { diff --git a/src/video_core/renderer_opengl/gl_compute_pipeline.h b/src/video_core/renderer_opengl/gl_compute_pipeline.h index 50c676365..6534dec32 100644 --- a/src/video_core/renderer_opengl/gl_compute_pipeline.h +++ b/src/video_core/renderer_opengl/gl_compute_pipeline.h @@ -1,12 +1,10 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include <array> #include <type_traits> -#include <utility> #include "common/common_types.h" #include "shader_recompiler/shader_info.h" @@ -51,10 +49,8 @@ static_assert(std::is_trivially_constructible_v<ComputePipelineKey>); class ComputePipeline { public: explicit ComputePipeline(const Device& device, TextureCache& texture_cache_, - BufferCache& buffer_cache_, Tegra::MemoryManager& gpu_memory_, - Tegra::Engines::KeplerCompute& kepler_compute_, - ProgramManager& program_manager_, const Shader::Info& info_, - std::string code, std::vector<u32> code_v); + BufferCache& buffer_cache_, ProgramManager& program_manager_, + const Shader::Info& info_, std::string code, std::vector<u32> code_v); void Configure(); @@ -62,11 +58,17 @@ public: return writes_global_memory; } + void SetEngine(Tegra::Engines::KeplerCompute* kepler_compute_, + Tegra::MemoryManager* gpu_memory_) { + kepler_compute = kepler_compute_; + gpu_memory = gpu_memory_; + } + private: TextureCache& texture_cache; BufferCache& buffer_cache; - Tegra::MemoryManager& gpu_memory; - Tegra::Engines::KeplerCompute& kepler_compute; + Tegra::MemoryManager* gpu_memory; + Tegra::Engines::KeplerCompute* kepler_compute; ProgramManager& program_manager; Shader::Info info; diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index e62912a22..1663e277d 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp @@ -1,13 +1,10 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> #include <array> #include <cstddef> #include <cstdlib> -#include <cstring> -#include <limits> #include <optional> #include <span> #include <stdexcept> @@ -15,13 +12,15 @@ #include <glad/glad.h> +#include "common/literals.h" #include "common/logging/log.h" -#include "common/scope_exit.h" #include "common/settings.h" #include "shader_recompiler/stage.h" #include "video_core/renderer_opengl/gl_device.h" #include "video_core/renderer_opengl/gl_resource_manager.h" +using namespace Common::Literals; + namespace OpenGL { namespace { constexpr std::array LIMIT_UBOS = { @@ -168,6 +167,7 @@ Device::Device() { has_sparse_texture_2 = GLAD_GL_ARB_sparse_texture2; warp_size_potentially_larger_than_guest = !is_nvidia && !is_intel; need_fastmath_off = is_nvidia; + can_report_memory = GLAD_GL_NVX_gpu_memory_info; // At the moment of writing this, only Nvidia's driver optimizes BufferSubData on exclusive // uniform buffers as "push constants" @@ -279,4 +279,10 @@ void main() { })"); } +u64 Device::GetCurrentDedicatedVideoMemory() const { + GLint cur_avail_mem_kb = 0; + glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &cur_avail_mem_kb); + return static_cast<u64>(cur_avail_mem_kb) * 1_KiB; +} + } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h index 95c2e8d38..5ef51ebcf 100644 --- a/src/video_core/renderer_opengl/gl_device.h +++ b/src/video_core/renderer_opengl/gl_device.h @@ -1,6 +1,5 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -20,6 +19,8 @@ public: [[nodiscard]] std::string GetVendorName() const; + u64 GetCurrentDedicatedVideoMemory() const; + u32 GetMaxUniformBuffers(Shader::Stage stage) const noexcept { return max_uniform_buffers[static_cast<size_t>(stage)]; } @@ -168,6 +169,10 @@ public: return vendor_name == "ATI Technologies Inc."; } + bool CanReportMemoryUsage() const { + return can_report_memory; + } + private: static bool TestVariableAoffi(); static bool TestPreciseBug(); @@ -210,6 +215,7 @@ private: bool need_fastmath_off{}; bool has_cbuf_ftou_bug{}; bool has_bool_ref_bug{}; + bool can_report_memory{}; std::string vendor_name; }; diff --git a/src/video_core/renderer_opengl/gl_fence_manager.cpp b/src/video_core/renderer_opengl/gl_fence_manager.cpp index 151290101..91463f854 100644 --- a/src/video_core/renderer_opengl/gl_fence_manager.cpp +++ b/src/video_core/renderer_opengl/gl_fence_manager.cpp @@ -1,6 +1,5 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include "common/assert.h" @@ -11,10 +10,7 @@ namespace OpenGL { -GLInnerFence::GLInnerFence(u32 payload_, bool is_stubbed_) : FenceBase{payload_, is_stubbed_} {} - -GLInnerFence::GLInnerFence(GPUVAddr address_, u32 payload_, bool is_stubbed_) - : FenceBase{address_, payload_, is_stubbed_} {} +GLInnerFence::GLInnerFence(bool is_stubbed_) : FenceBase{is_stubbed_} {} GLInnerFence::~GLInnerFence() = default; @@ -31,9 +27,8 @@ bool GLInnerFence::IsSignaled() const { return true; } ASSERT(sync_object.handle != 0); - GLsizei length; GLint sync_status; - glGetSynciv(sync_object.handle, GL_SYNC_STATUS, sizeof(GLint), &length, &sync_status); + glGetSynciv(sync_object.handle, GL_SYNC_STATUS, 1, nullptr, &sync_status); return sync_status == GL_SIGNALED; } @@ -50,12 +45,8 @@ FenceManagerOpenGL::FenceManagerOpenGL(VideoCore::RasterizerInterface& rasterize BufferCache& buffer_cache_, QueryCache& query_cache_) : GenericFenceManager{rasterizer_, gpu_, texture_cache_, buffer_cache_, query_cache_} {} -Fence FenceManagerOpenGL::CreateFence(u32 value, bool is_stubbed) { - return std::make_shared<GLInnerFence>(value, is_stubbed); -} - -Fence FenceManagerOpenGL::CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) { - return std::make_shared<GLInnerFence>(addr, value, is_stubbed); +Fence FenceManagerOpenGL::CreateFence(bool is_stubbed) { + return std::make_shared<GLInnerFence>(is_stubbed); } void FenceManagerOpenGL::QueueFence(Fence& fence) { diff --git a/src/video_core/renderer_opengl/gl_fence_manager.h b/src/video_core/renderer_opengl/gl_fence_manager.h index e714aa115..f1446e732 100644 --- a/src/video_core/renderer_opengl/gl_fence_manager.h +++ b/src/video_core/renderer_opengl/gl_fence_manager.h @@ -1,6 +1,5 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -17,8 +16,7 @@ namespace OpenGL { class GLInnerFence : public VideoCommon::FenceBase { public: - explicit GLInnerFence(u32 payload_, bool is_stubbed_); - explicit GLInnerFence(GPUVAddr address_, u32 payload_, bool is_stubbed_); + explicit GLInnerFence(bool is_stubbed_); ~GLInnerFence(); void Queue(); @@ -41,8 +39,7 @@ public: QueryCache& query_cache); protected: - Fence CreateFence(u32 value, bool is_stubbed) override; - Fence CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) override; + Fence CreateFence(bool is_stubbed) override; void QueueFence(Fence& fence) override; bool IsFenceSignaled(Fence& fence) const override; void WaitFence(Fence& fence) override; diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp index f8495896c..41493a7da 100644 --- a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp +++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp @@ -1,6 +1,5 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> #include <array> @@ -49,7 +48,7 @@ GLenum Stage(size_t stage_index) { case 4: return GL_FRAGMENT_SHADER; } - UNREACHABLE_MSG("{}", stage_index); + ASSERT_MSG(false, "{}", stage_index); return GL_NONE; } @@ -66,7 +65,7 @@ GLenum AssemblyStage(size_t stage_index) { case 4: return GL_FRAGMENT_PROGRAM_NV; } - UNREACHABLE_MSG("{}", stage_index); + ASSERT_MSG(false, "{}", stage_index); return GL_NONE; } @@ -170,15 +169,15 @@ ConfigureFuncPtr ConfigureFunc(const std::array<Shader::Info, 5>& infos, u32 ena } } // Anonymous namespace -GraphicsPipeline::GraphicsPipeline( - const Device& device, TextureCache& texture_cache_, BufferCache& buffer_cache_, - Tegra::MemoryManager& gpu_memory_, Tegra::Engines::Maxwell3D& maxwell3d_, - ProgramManager& program_manager_, StateTracker& state_tracker_, ShaderWorker* thread_worker, - VideoCore::ShaderNotify* shader_notify, std::array<std::string, 5> sources, - std::array<std::vector<u32>, 5> sources_spirv, const std::array<const Shader::Info*, 5>& infos, - const GraphicsPipelineKey& key_) - : texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, - gpu_memory{gpu_memory_}, maxwell3d{maxwell3d_}, program_manager{program_manager_}, +GraphicsPipeline::GraphicsPipeline(const Device& device, TextureCache& texture_cache_, + BufferCache& buffer_cache_, ProgramManager& program_manager_, + StateTracker& state_tracker_, ShaderWorker* thread_worker, + VideoCore::ShaderNotify* shader_notify, + std::array<std::string, 5> sources, + std::array<std::vector<u32>, 5> sources_spirv, + const std::array<const Shader::Info*, 5>& infos, + const GraphicsPipelineKey& key_) + : texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, program_manager{program_manager_}, state_tracker{state_tracker_}, key{key_} { if (shader_notify) { shader_notify->MarkShaderBuilding(); @@ -243,10 +242,6 @@ GraphicsPipeline::GraphicsPipeline( case Settings::ShaderBackend::GLASM: if (!sources[stage].empty()) { assembly_programs[stage] = CompileProgram(sources[stage], AssemblyStage(stage)); - if (in_parallel) { - // Make sure program is built before continuing when building in parallel - glGetString(GL_PROGRAM_ERROR_STRING_NV); - } } break; case Settings::ShaderBackend::SPIRV: @@ -256,20 +251,18 @@ GraphicsPipeline::GraphicsPipeline( break; } } - if (in_parallel && backend != Settings::ShaderBackend::GLASM) { - // Make sure programs have built if we are building shaders in parallel - for (OGLProgram& program : source_programs) { - if (program.handle != 0) { - GLint status{}; - glGetProgramiv(program.handle, GL_LINK_STATUS, &status); - } - } + if (in_parallel) { + std::scoped_lock lock{built_mutex}; + built_fence.Create(); + // Flush this context to ensure compilation commands and fence are in the GPU pipe. + glFlush(); + built_condvar.notify_one(); + } else { + is_built = true; } if (shader_notify) { shader_notify->MarkShaderComplete(); } - is_built = true; - built_condvar.notify_one(); }}; if (thread_worker) { thread_worker->QueueWork(std::move(func)); @@ -292,7 +285,7 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) { buffer_cache.runtime.SetBaseStorageBindings(base_storage_bindings); buffer_cache.runtime.SetEnableStorageBuffers(use_storage_buffers); - const auto& regs{maxwell3d.regs}; + const auto& regs{maxwell3d->regs}; const bool via_header_index{regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex}; const auto config_stage{[&](size_t stage) LAMBDA_FORCEINLINE { const Shader::Info& info{stage_infos[stage]}; @@ -306,7 +299,7 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) { ++ssbo_index; } } - const auto& cbufs{maxwell3d.state.shader_stages[stage].const_buffers}; + const auto& cbufs{maxwell3d->state.shader_stages[stage].const_buffers}; const auto read_handle{[&](const auto& desc, u32 index) { ASSERT(cbufs[desc.cbuf_index].enabled); const u32 index_offset{index << desc.size_shift}; @@ -319,13 +312,14 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) { const u32 second_offset{desc.secondary_cbuf_offset + index_offset}; const GPUVAddr separate_addr{cbufs[desc.secondary_cbuf_index].address + second_offset}; - const u32 lhs_raw{gpu_memory.Read<u32>(addr)}; - const u32 rhs_raw{gpu_memory.Read<u32>(separate_addr)}; + const u32 lhs_raw{gpu_memory->Read<u32>(addr) << desc.shift_left}; + const u32 rhs_raw{gpu_memory->Read<u32>(separate_addr) + << desc.secondary_shift_left}; const u32 raw{lhs_raw | rhs_raw}; return TexturePair(raw, via_header_index); } } - return TexturePair(gpu_memory.Read<u32>(addr), via_header_index); + return TexturePair(gpu_memory->Read<u32>(addr), via_header_index); }}; const auto add_image{[&](const auto& desc, bool blacklist) LAMBDA_FORCEINLINE { for (u32 index = 0; index < desc.count; ++index) { @@ -440,7 +434,7 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) { buffer_cache.UpdateGraphicsBuffers(is_indexed); buffer_cache.BindHostGeometryBuffers(is_indexed); - if (!is_built.load(std::memory_order::relaxed)) { + if (!IsBuilt()) { WaitForBuild(); } const bool use_assembly{assembly_programs[0].handle != 0}; @@ -585,8 +579,26 @@ void GraphicsPipeline::GenerateTransformFeedbackState() { } void GraphicsPipeline::WaitForBuild() { - std::unique_lock lock{built_mutex}; - built_condvar.wait(lock, [this] { return is_built.load(std::memory_order::relaxed); }); + if (built_fence.handle == 0) { + std::unique_lock lock{built_mutex}; + built_condvar.wait(lock, [this] { return built_fence.handle != 0; }); + } + ASSERT(glClientWaitSync(built_fence.handle, 0, GL_TIMEOUT_IGNORED) != GL_WAIT_FAILED); + is_built = true; +} + +bool GraphicsPipeline::IsBuilt() noexcept { + if (is_built) { + return true; + } + if (built_fence.handle == 0) { + return false; + } + // Timeout of zero means this is non-blocking + const auto sync_status = glClientWaitSync(built_fence.handle, 0, 0); + ASSERT(sync_status != GL_WAIT_FAILED); + is_built = sync_status != GL_TIMEOUT_EXPIRED; + return is_built; } } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.h b/src/video_core/renderer_opengl/gl_graphics_pipeline.h index 4e28d9a42..a0f0e63cb 100644 --- a/src/video_core/renderer_opengl/gl_graphics_pipeline.h +++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.h @@ -1,6 +1,5 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -14,7 +13,6 @@ #include "common/common_types.h" #include "shader_recompiler/shader_info.h" #include "video_core/engines/maxwell_3d.h" -#include "video_core/memory_manager.h" #include "video_core/renderer_opengl/gl_buffer_cache.h" #include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/gl_texture_cache.h" @@ -73,10 +71,9 @@ static_assert(std::is_trivially_constructible_v<GraphicsPipelineKey>); class GraphicsPipeline { public: explicit GraphicsPipeline(const Device& device, TextureCache& texture_cache_, - BufferCache& buffer_cache_, Tegra::MemoryManager& gpu_memory_, - Tegra::Engines::Maxwell3D& maxwell3d_, - ProgramManager& program_manager_, StateTracker& state_tracker_, - ShaderWorker* thread_worker, VideoCore::ShaderNotify* shader_notify, + BufferCache& buffer_cache_, ProgramManager& program_manager_, + StateTracker& state_tracker_, ShaderWorker* thread_worker, + VideoCore::ShaderNotify* shader_notify, std::array<std::string, 5> sources, std::array<std::vector<u32>, 5> sources_spirv, const std::array<const Shader::Info*, 5>& infos, @@ -100,9 +97,7 @@ public: return writes_global_memory; } - [[nodiscard]] bool IsBuilt() const noexcept { - return is_built.load(std::memory_order::relaxed); - } + [[nodiscard]] bool IsBuilt() noexcept; template <typename Spec> static auto MakeConfigureSpecFunc() { @@ -111,6 +106,11 @@ public: }; } + void SetEngine(Tegra::Engines::Maxwell3D* maxwell3d_, Tegra::MemoryManager* gpu_memory_) { + maxwell3d = maxwell3d_; + gpu_memory = gpu_memory_; + } + private: template <typename Spec> void ConfigureImpl(bool is_indexed); @@ -123,8 +123,8 @@ private: TextureCache& texture_cache; BufferCache& buffer_cache; - Tegra::MemoryManager& gpu_memory; - Tegra::Engines::Maxwell3D& maxwell3d; + Tegra::MemoryManager* gpu_memory; + Tegra::Engines::Maxwell3D* maxwell3d; ProgramManager& program_manager; StateTracker& state_tracker; const GraphicsPipelineKey key; @@ -154,7 +154,8 @@ private: std::mutex built_mutex; std::condition_variable built_condvar; - std::atomic_bool is_built{false}; + OGLSync built_fence{}; + bool is_built{false}; }; } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_query_cache.cpp b/src/video_core/renderer_opengl/gl_query_cache.cpp index acebbf5f4..5070db441 100644 --- a/src/video_core/renderer_opengl/gl_query_cache.cpp +++ b/src/video_core/renderer_opengl/gl_query_cache.cpp @@ -1,17 +1,13 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> -#include <cstring> #include <memory> -#include <unordered_map> #include <utility> #include <vector> #include <glad/glad.h> -#include "common/assert.h" #include "core/core.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/memory_manager.h" @@ -30,9 +26,8 @@ constexpr GLenum GetTarget(VideoCore::QueryType type) { } // Anonymous namespace -QueryCache::QueryCache(RasterizerOpenGL& rasterizer_, Tegra::Engines::Maxwell3D& maxwell3d_, - Tegra::MemoryManager& gpu_memory_) - : QueryCacheBase(rasterizer_, maxwell3d_, gpu_memory_), gl_rasterizer{rasterizer_} {} +QueryCache::QueryCache(RasterizerOpenGL& rasterizer_) + : QueryCacheBase(rasterizer_), gl_rasterizer{rasterizer_} {} QueryCache::~QueryCache() = default; diff --git a/src/video_core/renderer_opengl/gl_query_cache.h b/src/video_core/renderer_opengl/gl_query_cache.h index 7bbe5cfe9..14ce59990 100644 --- a/src/video_core/renderer_opengl/gl_query_cache.h +++ b/src/video_core/renderer_opengl/gl_query_cache.h @@ -1,6 +1,5 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -29,8 +28,7 @@ using CounterStream = VideoCommon::CounterStreamBase<QueryCache, HostCounter>; class QueryCache final : public VideoCommon::QueryCacheBase<QueryCache, CachedQuery, CounterStream, HostCounter> { public: - explicit QueryCache(RasterizerOpenGL& rasterizer_, Tegra::Engines::Maxwell3D& maxwell3d_, - Tegra::MemoryManager& gpu_memory_); + explicit QueryCache(RasterizerOpenGL& rasterizer_); ~QueryCache(); OGLQuery AllocateQuery(VideoCore::QueryType type); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 142412a8e..c2d80605d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -1,14 +1,11 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: 2015 Citra Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> #include <array> #include <bitset> #include <memory> -#include <string> #include <string_view> -#include <tuple> #include <utility> #include <glad/glad.h> @@ -17,8 +14,9 @@ #include "common/logging/log.h" #include "common/math_util.h" #include "common/microprofile.h" +#include "common/scope_exit.h" #include "common/settings.h" -#include "core/memory.h" +#include "video_core/control/channel_state.h" #include "video_core/engines/kepler_compute.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/memory_manager.h" @@ -58,22 +56,20 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra Core::Memory::Memory& cpu_memory_, const Device& device_, ScreenInfo& screen_info_, ProgramManager& program_manager_, StateTracker& state_tracker_) - : RasterizerAccelerated(cpu_memory_), gpu(gpu_), maxwell3d(gpu.Maxwell3D()), - kepler_compute(gpu.KeplerCompute()), gpu_memory(gpu.MemoryManager()), device(device_), - screen_info(screen_info_), program_manager(program_manager_), state_tracker(state_tracker_), + : RasterizerAccelerated(cpu_memory_), gpu(gpu_), device(device_), screen_info(screen_info_), + program_manager(program_manager_), state_tracker(state_tracker_), texture_cache_runtime(device, program_manager, state_tracker), - texture_cache(texture_cache_runtime, *this, maxwell3d, kepler_compute, gpu_memory), - buffer_cache_runtime(device), - buffer_cache(*this, maxwell3d, kepler_compute, gpu_memory, cpu_memory_, buffer_cache_runtime), - shader_cache(*this, emu_window_, maxwell3d, kepler_compute, gpu_memory, device, texture_cache, - buffer_cache, program_manager, state_tracker, gpu.ShaderNotify()), - query_cache(*this, maxwell3d, gpu_memory), accelerate_dma(buffer_cache), + texture_cache(texture_cache_runtime, *this), buffer_cache_runtime(device), + buffer_cache(*this, cpu_memory_, buffer_cache_runtime), + shader_cache(*this, emu_window_, device, texture_cache, buffer_cache, program_manager, + state_tracker, gpu.ShaderNotify()), + query_cache(*this), accelerate_dma(buffer_cache), fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache) {} RasterizerOpenGL::~RasterizerOpenGL() = default; void RasterizerOpenGL::SyncVertexFormats() { - auto& flags = maxwell3d.dirty.flags; + auto& flags = maxwell3d->dirty.flags; if (!flags[Dirty::VertexFormats]) { return; } @@ -91,7 +87,7 @@ void RasterizerOpenGL::SyncVertexFormats() { } flags[Dirty::VertexFormat0 + index] = false; - const auto attrib = maxwell3d.regs.vertex_attrib_format[index]; + const auto attrib = maxwell3d->regs.vertex_attrib_format[index]; const auto gl_index = static_cast<GLuint>(index); // Disable constant attributes. @@ -115,13 +111,13 @@ void RasterizerOpenGL::SyncVertexFormats() { } void RasterizerOpenGL::SyncVertexInstances() { - auto& flags = maxwell3d.dirty.flags; + auto& flags = maxwell3d->dirty.flags; if (!flags[Dirty::VertexInstances]) { return; } flags[Dirty::VertexInstances] = false; - const auto& regs = maxwell3d.regs; + const auto& regs = maxwell3d->regs; for (std::size_t index = 0; index < NUM_SUPPORTED_VERTEX_ATTRIBUTES; ++index) { if (!flags[Dirty::VertexInstance0 + index]) { continue; @@ -142,11 +138,11 @@ void RasterizerOpenGL::LoadDiskResources(u64 title_id, std::stop_token stop_load void RasterizerOpenGL::Clear() { MICROPROFILE_SCOPE(OpenGL_Clears); - if (!maxwell3d.ShouldExecute()) { + if (!maxwell3d->ShouldExecute()) { return; } - const auto& regs = maxwell3d.regs; + const auto& regs = maxwell3d->regs; bool use_color{}; bool use_depth{}; bool use_stencil{}; @@ -212,28 +208,33 @@ void RasterizerOpenGL::Clear() { void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) { MICROPROFILE_SCOPE(OpenGL_Drawing); + SCOPE_EXIT({ gpu.TickWork(); }); query_cache.UpdateCounters(); GraphicsPipeline* const pipeline{shader_cache.CurrentGraphicsPipeline()}; if (!pipeline) { return; } + + gpu.TickWork(); + std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; + pipeline->SetEngine(maxwell3d, gpu_memory); pipeline->Configure(is_indexed); SyncState(); - const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(maxwell3d.regs.draw.topology); + const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(maxwell3d->regs.draw.topology); BeginTransformFeedback(pipeline, primitive_mode); - const GLuint base_instance = static_cast<GLuint>(maxwell3d.regs.vb_base_instance); + const GLuint base_instance = static_cast<GLuint>(maxwell3d->regs.vb_base_instance); const GLsizei num_instances = - static_cast<GLsizei>(is_instanced ? maxwell3d.mme_draw.instance_count : 1); + static_cast<GLsizei>(is_instanced ? maxwell3d->mme_draw.instance_count : 1); if (is_indexed) { - const GLint base_vertex = static_cast<GLint>(maxwell3d.regs.vb_element_base); - const GLsizei num_vertices = static_cast<GLsizei>(maxwell3d.regs.index_array.count); + const GLint base_vertex = static_cast<GLint>(maxwell3d->regs.vb_element_base); + const GLsizei num_vertices = static_cast<GLsizei>(maxwell3d->regs.index_array.count); const GLvoid* const offset = buffer_cache_runtime.IndexOffset(); - const GLenum format = MaxwellToGL::IndexFormat(maxwell3d.regs.index_array.format); + const GLenum format = MaxwellToGL::IndexFormat(maxwell3d->regs.index_array.format); if (num_instances == 1 && base_instance == 0 && base_vertex == 0) { glDrawElements(primitive_mode, num_vertices, format, offset); } else if (num_instances == 1 && base_instance == 0) { @@ -252,8 +253,8 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) { base_instance); } } else { - const GLint base_vertex = static_cast<GLint>(maxwell3d.regs.vertex_buffer.first); - const GLsizei num_vertices = static_cast<GLsizei>(maxwell3d.regs.vertex_buffer.count); + const GLint base_vertex = static_cast<GLint>(maxwell3d->regs.vertex_buffer.first); + const GLsizei num_vertices = static_cast<GLsizei>(maxwell3d->regs.vertex_buffer.count); if (num_instances == 1 && base_instance == 0) { glDrawArrays(primitive_mode, base_vertex, num_vertices); } else if (base_instance == 0) { @@ -267,8 +268,6 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) { ++num_queued_commands; has_written_global_memory |= pipeline->WritesGlobalMemory(); - - gpu.TickWork(); } void RasterizerOpenGL::DispatchCompute() { @@ -276,8 +275,9 @@ void RasterizerOpenGL::DispatchCompute() { if (!pipeline) { return; } + pipeline->SetEngine(kepler_compute, gpu_memory); pipeline->Configure(); - const auto& qmd{kepler_compute.launch_description}; + const auto& qmd{kepler_compute->launch_description}; glDispatchCompute(qmd.grid_dim_x, qmd.grid_dim_y, qmd.grid_dim_z); ++num_queued_commands; has_written_global_memory |= pipeline->WritesGlobalMemory(); @@ -362,7 +362,7 @@ void RasterizerOpenGL::OnCPUWrite(VAddr addr, u64 size) { } } -void RasterizerOpenGL::SyncGuestHost() { +void RasterizerOpenGL::InvalidateGPUCache() { MICROPROFILE_SCOPE(OpenGL_CacheManagement); shader_cache.SyncGuestHost(); { @@ -383,40 +383,30 @@ void RasterizerOpenGL::UnmapMemory(VAddr addr, u64 size) { shader_cache.OnCPUWrite(addr, size); } -void RasterizerOpenGL::ModifyGPUMemory(GPUVAddr addr, u64 size) { +void RasterizerOpenGL::ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) { { std::scoped_lock lock{texture_cache.mutex}; - texture_cache.UnmapGPUMemory(addr, size); + texture_cache.UnmapGPUMemory(as_id, addr, size); } } -void RasterizerOpenGL::SignalSemaphore(GPUVAddr addr, u32 value) { - if (!gpu.IsAsync()) { - gpu_memory.Write<u32>(addr, value); - return; - } - fence_manager.SignalSemaphore(addr, value); +void RasterizerOpenGL::SignalFence(std::function<void()>&& func) { + fence_manager.SignalFence(std::move(func)); +} + +void RasterizerOpenGL::SyncOperation(std::function<void()>&& func) { + fence_manager.SyncOperation(std::move(func)); } void RasterizerOpenGL::SignalSyncPoint(u32 value) { - if (!gpu.IsAsync()) { - gpu.IncrementSyncPoint(value); - return; - } fence_manager.SignalSyncPoint(value); } void RasterizerOpenGL::SignalReference() { - if (!gpu.IsAsync()) { - return; - } fence_manager.SignalOrdering(); } void RasterizerOpenGL::ReleaseFences() { - if (!gpu.IsAsync()) { - return; - } fence_manager.WaitPendingFences(); } @@ -433,6 +423,7 @@ void RasterizerOpenGL::WaitForIdle() { } void RasterizerOpenGL::FragmentBarrier() { + glTextureBarrier(); glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT | GL_TEXTURE_FETCH_BARRIER_BIT); } @@ -485,13 +476,13 @@ Tegra::Engines::AccelerateDMAInterface& RasterizerOpenGL::AccessAccelerateDMA() } void RasterizerOpenGL::AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, - std::span<u8> memory) { - auto cpu_addr = gpu_memory.GpuToCpuAddress(address); + std::span<const u8> memory) { + auto cpu_addr = gpu_memory->GpuToCpuAddress(address); if (!cpu_addr) [[unlikely]] { - gpu_memory.WriteBlock(address, memory.data(), copy_size); + gpu_memory->WriteBlock(address, memory.data(), copy_size); return; } - gpu_memory.WriteBlockUnsafe(address, memory.data(), copy_size); + gpu_memory->WriteBlockUnsafe(address, memory.data(), copy_size); { std::unique_lock<std::mutex> lock{buffer_cache.mutex}; if (!buffer_cache.InlineMemory(*cpu_addr, copy_size, memory)) { @@ -522,6 +513,8 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config, // ASSERT_MSG(image_view->size.width == config.width, "Framebuffer width is different"); // ASSERT_MSG(image_view->size.height == config.height, "Framebuffer height is different"); + screen_info.texture.width = image_view->size.width; + screen_info.texture.height = image_view->size.height; screen_info.display_texture = image_view->Handle(Shader::TextureType::Color2D); screen_info.display_srgb = VideoCore::Surface::IsPixelFormatSRGB(image_view->format); return true; @@ -552,19 +545,25 @@ void RasterizerOpenGL::SyncState() { } void RasterizerOpenGL::SyncViewport() { - auto& flags = maxwell3d.dirty.flags; - const auto& regs = maxwell3d.regs; + auto& flags = maxwell3d->dirty.flags; + const auto& regs = maxwell3d->regs; const bool rescale_viewports = flags[VideoCommon::Dirty::RescaleViewports]; const bool dirty_viewport = flags[Dirty::Viewports] || rescale_viewports; const bool dirty_clip_control = flags[Dirty::ClipControl]; - if (dirty_clip_control || flags[Dirty::FrontFace]) { + if (dirty_viewport || dirty_clip_control || flags[Dirty::FrontFace]) { flags[Dirty::FrontFace] = false; GLenum mode = MaxwellToGL::FrontFace(regs.front_face); - if (regs.screen_y_control.triangle_rast_flip != 0 && - regs.viewport_transform[0].scale_y < 0.0f) { + bool flip_faces = true; + if (regs.screen_y_control.triangle_rast_flip != 0) { + flip_faces = !flip_faces; + } + if (regs.viewport_transform[0].scale_y < 0.0f) { + flip_faces = !flip_faces; + } + if (flip_faces) { switch (mode) { case GL_CW: mode = GL_CCW; @@ -652,23 +651,23 @@ void RasterizerOpenGL::SyncViewport() { } void RasterizerOpenGL::SyncDepthClamp() { - auto& flags = maxwell3d.dirty.flags; + auto& flags = maxwell3d->dirty.flags; if (!flags[Dirty::DepthClampEnabled]) { return; } flags[Dirty::DepthClampEnabled] = false; - oglEnable(GL_DEPTH_CLAMP, maxwell3d.regs.view_volume_clip_control.depth_clamp_disabled == 0); + oglEnable(GL_DEPTH_CLAMP, maxwell3d->regs.view_volume_clip_control.depth_clamp_disabled == 0); } void RasterizerOpenGL::SyncClipEnabled(u32 clip_mask) { - auto& flags = maxwell3d.dirty.flags; + auto& flags = maxwell3d->dirty.flags; if (!flags[Dirty::ClipDistances] && !flags[VideoCommon::Dirty::Shaders]) { return; } flags[Dirty::ClipDistances] = false; - clip_mask &= maxwell3d.regs.clip_distance_enabled; + clip_mask &= maxwell3d->regs.clip_distance_enabled; if (clip_mask == last_clip_distance_mask) { return; } @@ -684,8 +683,8 @@ void RasterizerOpenGL::SyncClipCoef() { } void RasterizerOpenGL::SyncCullMode() { - auto& flags = maxwell3d.dirty.flags; - const auto& regs = maxwell3d.regs; + auto& flags = maxwell3d->dirty.flags; + const auto& regs = maxwell3d->regs; if (flags[Dirty::CullTest]) { flags[Dirty::CullTest] = false; @@ -700,23 +699,23 @@ void RasterizerOpenGL::SyncCullMode() { } void RasterizerOpenGL::SyncPrimitiveRestart() { - auto& flags = maxwell3d.dirty.flags; + auto& flags = maxwell3d->dirty.flags; if (!flags[Dirty::PrimitiveRestart]) { return; } flags[Dirty::PrimitiveRestart] = false; - if (maxwell3d.regs.primitive_restart.enabled) { + if (maxwell3d->regs.primitive_restart.enabled) { glEnable(GL_PRIMITIVE_RESTART); - glPrimitiveRestartIndex(maxwell3d.regs.primitive_restart.index); + glPrimitiveRestartIndex(maxwell3d->regs.primitive_restart.index); } else { glDisable(GL_PRIMITIVE_RESTART); } } void RasterizerOpenGL::SyncDepthTestState() { - auto& flags = maxwell3d.dirty.flags; - const auto& regs = maxwell3d.regs; + auto& flags = maxwell3d->dirty.flags; + const auto& regs = maxwell3d->regs; if (flags[Dirty::DepthMask]) { flags[Dirty::DepthMask] = false; @@ -735,13 +734,13 @@ void RasterizerOpenGL::SyncDepthTestState() { } void RasterizerOpenGL::SyncStencilTestState() { - auto& flags = maxwell3d.dirty.flags; + auto& flags = maxwell3d->dirty.flags; if (!flags[Dirty::StencilTest]) { return; } flags[Dirty::StencilTest] = false; - const auto& regs = maxwell3d.regs; + const auto& regs = maxwell3d->regs; oglEnable(GL_STENCIL_TEST, regs.stencil_enable); glStencilFuncSeparate(GL_FRONT, MaxwellToGL::ComparisonOp(regs.stencil_front_func_func), @@ -766,23 +765,23 @@ void RasterizerOpenGL::SyncStencilTestState() { } void RasterizerOpenGL::SyncRasterizeEnable() { - auto& flags = maxwell3d.dirty.flags; + auto& flags = maxwell3d->dirty.flags; if (!flags[Dirty::RasterizeEnable]) { return; } flags[Dirty::RasterizeEnable] = false; - oglEnable(GL_RASTERIZER_DISCARD, maxwell3d.regs.rasterize_enable == 0); + oglEnable(GL_RASTERIZER_DISCARD, maxwell3d->regs.rasterize_enable == 0); } void RasterizerOpenGL::SyncPolygonModes() { - auto& flags = maxwell3d.dirty.flags; + auto& flags = maxwell3d->dirty.flags; if (!flags[Dirty::PolygonModes]) { return; } flags[Dirty::PolygonModes] = false; - const auto& regs = maxwell3d.regs; + const auto& regs = maxwell3d->regs; if (regs.fill_rectangle) { if (!GLAD_GL_NV_fill_rectangle) { LOG_ERROR(Render_OpenGL, "GL_NV_fill_rectangle used and not supported"); @@ -815,7 +814,7 @@ void RasterizerOpenGL::SyncPolygonModes() { } void RasterizerOpenGL::SyncColorMask() { - auto& flags = maxwell3d.dirty.flags; + auto& flags = maxwell3d->dirty.flags; if (!flags[Dirty::ColorMasks]) { return; } @@ -824,7 +823,7 @@ void RasterizerOpenGL::SyncColorMask() { const bool force = flags[Dirty::ColorMaskCommon]; flags[Dirty::ColorMaskCommon] = false; - const auto& regs = maxwell3d.regs; + const auto& regs = maxwell3d->regs; if (regs.color_mask_common) { if (!force && !flags[Dirty::ColorMask0]) { return; @@ -849,30 +848,30 @@ void RasterizerOpenGL::SyncColorMask() { } void RasterizerOpenGL::SyncMultiSampleState() { - auto& flags = maxwell3d.dirty.flags; + auto& flags = maxwell3d->dirty.flags; if (!flags[Dirty::MultisampleControl]) { return; } flags[Dirty::MultisampleControl] = false; - const auto& regs = maxwell3d.regs; + const auto& regs = maxwell3d->regs; oglEnable(GL_SAMPLE_ALPHA_TO_COVERAGE, regs.multisample_control.alpha_to_coverage); oglEnable(GL_SAMPLE_ALPHA_TO_ONE, regs.multisample_control.alpha_to_one); } void RasterizerOpenGL::SyncFragmentColorClampState() { - auto& flags = maxwell3d.dirty.flags; + auto& flags = maxwell3d->dirty.flags; if (!flags[Dirty::FragmentClampColor]) { return; } flags[Dirty::FragmentClampColor] = false; - glClampColor(GL_CLAMP_FRAGMENT_COLOR, maxwell3d.regs.frag_color_clamp ? GL_TRUE : GL_FALSE); + glClampColor(GL_CLAMP_FRAGMENT_COLOR, maxwell3d->regs.frag_color_clamp ? GL_TRUE : GL_FALSE); } void RasterizerOpenGL::SyncBlendState() { - auto& flags = maxwell3d.dirty.flags; - const auto& regs = maxwell3d.regs; + auto& flags = maxwell3d->dirty.flags; + const auto& regs = maxwell3d->regs; if (flags[Dirty::BlendColor]) { flags[Dirty::BlendColor] = false; @@ -929,13 +928,13 @@ void RasterizerOpenGL::SyncBlendState() { } void RasterizerOpenGL::SyncLogicOpState() { - auto& flags = maxwell3d.dirty.flags; + auto& flags = maxwell3d->dirty.flags; if (!flags[Dirty::LogicOp]) { return; } flags[Dirty::LogicOp] = false; - const auto& regs = maxwell3d.regs; + const auto& regs = maxwell3d->regs; if (regs.logic_op.enable) { glEnable(GL_COLOR_LOGIC_OP); glLogicOp(MaxwellToGL::LogicOp(regs.logic_op.operation)); @@ -945,7 +944,7 @@ void RasterizerOpenGL::SyncLogicOpState() { } void RasterizerOpenGL::SyncScissorTest() { - auto& flags = maxwell3d.dirty.flags; + auto& flags = maxwell3d->dirty.flags; if (!flags[Dirty::Scissors] && !flags[VideoCommon::Dirty::RescaleScissors]) { return; } @@ -954,7 +953,7 @@ void RasterizerOpenGL::SyncScissorTest() { const bool force = flags[VideoCommon::Dirty::RescaleScissors]; flags[VideoCommon::Dirty::RescaleScissors] = false; - const auto& regs = maxwell3d.regs; + const auto& regs = maxwell3d->regs; const auto& resolution = Settings::values.resolution_info; const bool is_rescaling{texture_cache.IsRescaling()}; @@ -990,39 +989,39 @@ void RasterizerOpenGL::SyncScissorTest() { } void RasterizerOpenGL::SyncPointState() { - auto& flags = maxwell3d.dirty.flags; + auto& flags = maxwell3d->dirty.flags; if (!flags[Dirty::PointSize]) { return; } flags[Dirty::PointSize] = false; - oglEnable(GL_POINT_SPRITE, maxwell3d.regs.point_sprite_enable); - oglEnable(GL_PROGRAM_POINT_SIZE, maxwell3d.regs.vp_point_size.enable); + oglEnable(GL_POINT_SPRITE, maxwell3d->regs.point_sprite_enable); + oglEnable(GL_PROGRAM_POINT_SIZE, maxwell3d->regs.vp_point_size.enable); const bool is_rescaling{texture_cache.IsRescaling()}; const float scale = is_rescaling ? Settings::values.resolution_info.up_factor : 1.0f; - glPointSize(std::max(1.0f, maxwell3d.regs.point_size * scale)); + glPointSize(std::max(1.0f, maxwell3d->regs.point_size * scale)); } void RasterizerOpenGL::SyncLineState() { - auto& flags = maxwell3d.dirty.flags; + auto& flags = maxwell3d->dirty.flags; if (!flags[Dirty::LineWidth]) { return; } flags[Dirty::LineWidth] = false; - const auto& regs = maxwell3d.regs; + const auto& regs = maxwell3d->regs; oglEnable(GL_LINE_SMOOTH, regs.line_smooth_enable); glLineWidth(regs.line_smooth_enable ? regs.line_width_smooth : regs.line_width_aliased); } void RasterizerOpenGL::SyncPolygonOffset() { - auto& flags = maxwell3d.dirty.flags; + auto& flags = maxwell3d->dirty.flags; if (!flags[Dirty::PolygonOffset]) { return; } flags[Dirty::PolygonOffset] = false; - const auto& regs = maxwell3d.regs; + const auto& regs = maxwell3d->regs; oglEnable(GL_POLYGON_OFFSET_FILL, regs.polygon_offset_fill_enable); oglEnable(GL_POLYGON_OFFSET_LINE, regs.polygon_offset_line_enable); oglEnable(GL_POLYGON_OFFSET_POINT, regs.polygon_offset_point_enable); @@ -1036,13 +1035,13 @@ void RasterizerOpenGL::SyncPolygonOffset() { } void RasterizerOpenGL::SyncAlphaTest() { - auto& flags = maxwell3d.dirty.flags; + auto& flags = maxwell3d->dirty.flags; if (!flags[Dirty::AlphaTest]) { return; } flags[Dirty::AlphaTest] = false; - const auto& regs = maxwell3d.regs; + const auto& regs = maxwell3d->regs; if (regs.alpha_test_enabled) { glEnable(GL_ALPHA_TEST); glAlphaFunc(MaxwellToGL::ComparisonOp(regs.alpha_test_func), regs.alpha_test_ref); @@ -1052,17 +1051,17 @@ void RasterizerOpenGL::SyncAlphaTest() { } void RasterizerOpenGL::SyncFramebufferSRGB() { - auto& flags = maxwell3d.dirty.flags; + auto& flags = maxwell3d->dirty.flags; if (!flags[Dirty::FramebufferSRGB]) { return; } flags[Dirty::FramebufferSRGB] = false; - oglEnable(GL_FRAMEBUFFER_SRGB, maxwell3d.regs.framebuffer_srgb); + oglEnable(GL_FRAMEBUFFER_SRGB, maxwell3d->regs.framebuffer_srgb); } void RasterizerOpenGL::BeginTransformFeedback(GraphicsPipeline* program, GLenum primitive_mode) { - const auto& regs = maxwell3d.regs; + const auto& regs = maxwell3d->regs; if (regs.tfb_enabled == 0) { return; } @@ -1081,11 +1080,48 @@ void RasterizerOpenGL::BeginTransformFeedback(GraphicsPipeline* program, GLenum } void RasterizerOpenGL::EndTransformFeedback() { - if (maxwell3d.regs.tfb_enabled != 0) { + if (maxwell3d->regs.tfb_enabled != 0) { glEndTransformFeedback(); } } +void RasterizerOpenGL::InitializeChannel(Tegra::Control::ChannelState& channel) { + CreateChannel(channel); + { + std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; + texture_cache.CreateChannel(channel); + buffer_cache.CreateChannel(channel); + } + shader_cache.CreateChannel(channel); + query_cache.CreateChannel(channel); + state_tracker.SetupTables(channel); +} + +void RasterizerOpenGL::BindChannel(Tegra::Control::ChannelState& channel) { + const s32 channel_id = channel.bind_id; + BindToChannel(channel_id); + { + std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; + texture_cache.BindToChannel(channel_id); + buffer_cache.BindToChannel(channel_id); + } + shader_cache.BindToChannel(channel_id); + query_cache.BindToChannel(channel_id); + state_tracker.ChangeChannel(channel); + state_tracker.InvalidateState(); +} + +void RasterizerOpenGL::ReleaseChannel(s32 channel_id) { + EraseChannel(channel_id); + { + std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; + texture_cache.EraseChannel(channel_id); + buffer_cache.EraseChannel(channel_id); + } + shader_cache.EraseChannel(channel_id); + query_cache.EraseChannel(channel_id); +} + AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_) : buffer_cache{buffer_cache_} {} bool AccelerateDMA::BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 98f6fd342..45131b785 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -1,24 +1,18 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: 2015 Citra Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include <array> -#include <atomic> #include <cstddef> -#include <memory> #include <optional> -#include <tuple> -#include <utility> #include <boost/container/static_vector.hpp> #include <glad/glad.h> #include "common/common_types.h" -#include "video_core/engines/const_buffer_info.h" -#include "video_core/engines/maxwell_3d.h" +#include "video_core/control/channel_state_cache.h" #include "video_core/engines/maxwell_dma.h" #include "video_core/rasterizer_accelerated.h" #include "video_core/rasterizer_interface.h" @@ -26,12 +20,8 @@ #include "video_core/renderer_opengl/gl_device.h" #include "video_core/renderer_opengl/gl_fence_manager.h" #include "video_core/renderer_opengl/gl_query_cache.h" -#include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/gl_shader_cache.h" -#include "video_core/renderer_opengl/gl_shader_manager.h" -#include "video_core/renderer_opengl/gl_state_tracker.h" #include "video_core/renderer_opengl/gl_texture_cache.h" -#include "video_core/textures/texture.h" namespace Core::Memory { class Memory; @@ -69,7 +59,8 @@ private: BufferCache& buffer_cache; }; -class RasterizerOpenGL : public VideoCore::RasterizerAccelerated { +class RasterizerOpenGL : public VideoCore::RasterizerAccelerated, + protected VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> { public: explicit RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, Core::Memory::Memory& cpu_memory_, const Device& device_, @@ -89,10 +80,11 @@ public: bool MustFlushRegion(VAddr addr, u64 size) override; void InvalidateRegion(VAddr addr, u64 size) override; void OnCPUWrite(VAddr addr, u64 size) override; - void SyncGuestHost() override; + void InvalidateGPUCache() override; void UnmapMemory(VAddr addr, u64 size) override; - void ModifyGPUMemory(GPUVAddr addr, u64 size) override; - void SignalSemaphore(GPUVAddr addr, u32 value) override; + void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override; + void SignalFence(std::function<void()>&& func) override; + void SyncOperation(std::function<void()>&& func) override; void SignalSyncPoint(u32 value) override; void SignalReference() override; void ReleaseFences() override; @@ -107,7 +99,7 @@ public: const Tegra::Engines::Fermi2D::Config& copy_config) override; Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override; void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, - std::span<u8> memory) override; + std::span<const u8> memory) override; bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, u32 pixel_stride) override; void LoadDiskResources(u64 title_id, std::stop_token stop_loading, @@ -118,6 +110,12 @@ public: return num_queued_commands > 0; } + void InitializeChannel(Tegra::Control::ChannelState& channel) override; + + void BindChannel(Tegra::Control::ChannelState& channel) override; + + void ReleaseChannel(s32 channel_id) override; + private: static constexpr size_t MAX_TEXTURES = 192; static constexpr size_t MAX_IMAGES = 48; @@ -202,9 +200,6 @@ private: void EndTransformFeedback(); Tegra::GPU& gpu; - Tegra::Engines::Maxwell3D& maxwell3d; - Tegra::Engines::KeplerCompute& kepler_compute; - Tegra::MemoryManager& gpu_memory; const Device& device; ScreenInfo& screen_info; diff --git a/src/video_core/renderer_opengl/gl_resource_manager.cpp b/src/video_core/renderer_opengl/gl_resource_manager.cpp index 5e7101d28..3a664fdec 100644 --- a/src/video_core/renderer_opengl/gl_resource_manager.cpp +++ b/src/video_core/renderer_opengl/gl_resource_manager.cpp @@ -1,11 +1,8 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: 2015 Citra Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <string_view> -#include <utility> #include <glad/glad.h> -#include "common/common_types.h" #include "common/microprofile.h" #include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/gl_shader_util.h" diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h index 84e07f8bd..bc05ba4bd 100644 --- a/src/video_core/renderer_opengl/gl_resource_manager.h +++ b/src/video_core/renderer_opengl/gl_resource_manager.h @@ -1,6 +1,5 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: 2015 Citra Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index f71e01a34..5a29a41d2 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -1,6 +1,5 @@ -// Copyright 2018 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <atomic> #include <fstream> @@ -14,10 +13,8 @@ #include "common/fs/fs.h" #include "common/fs/path_util.h" #include "common/logging/log.h" -#include "common/scope_exit.h" #include "common/settings.h" #include "common/thread_worker.h" -#include "core/core.h" #include "shader_recompiler/backend/glasm/emit_glasm.h" #include "shader_recompiler/backend/glsl/emit_glsl.h" #include "shader_recompiler/backend/spirv/emit_spirv.h" @@ -29,7 +26,6 @@ #include "video_core/engines/maxwell_3d.h" #include "video_core/memory_manager.h" #include "video_core/renderer_opengl/gl_rasterizer.h" -#include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/gl_shader_cache.h" #include "video_core/renderer_opengl/gl_shader_util.h" #include "video_core/renderer_opengl/gl_state_tracker.h" @@ -53,7 +49,7 @@ using VideoCommon::LoadPipelines; using VideoCommon::SerializePipeline; using Context = ShaderContext::Context; -constexpr u32 CACHE_VERSION = 5; +constexpr u32 CACHE_VERSION = 6; template <typename Container> auto MakeSpan(Container& container) { @@ -89,7 +85,7 @@ Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineKey& key, case Maxwell::TessellationPrimitive::Quads: return Shader::TessPrimitive::Quads; } - UNREACHABLE(); + ASSERT(false); return Shader::TessPrimitive::Triangles; }(); info.tess_spacing = [&] { @@ -101,7 +97,7 @@ Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineKey& key, case Maxwell::TessellationSpacing::FractionalEven: return Shader::TessSpacing::FractionalEven; } - UNREACHABLE(); + ASSERT(false); return Shader::TessSpacing::Equal; }(); break; @@ -155,16 +151,13 @@ void SetXfbState(VideoCommon::TransformFeedbackState& state, const Maxwell& regs } // Anonymous namespace ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindow& emu_window_, - Tegra::Engines::Maxwell3D& maxwell3d_, - Tegra::Engines::KeplerCompute& kepler_compute_, - Tegra::MemoryManager& gpu_memory_, const Device& device_, - TextureCache& texture_cache_, BufferCache& buffer_cache_, - ProgramManager& program_manager_, StateTracker& state_tracker_, - VideoCore::ShaderNotify& shader_notify_) - : 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_}, - shader_notify{shader_notify_}, use_asynchronous_shaders{device.UseAsynchronousShaders()}, + const Device& device_, TextureCache& texture_cache_, + BufferCache& buffer_cache_, ProgramManager& program_manager_, + StateTracker& state_tracker_, VideoCore::ShaderNotify& shader_notify_) + : VideoCommon::ShaderCache{rasterizer_}, emu_window{emu_window_}, device{device_}, + texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, program_manager{program_manager_}, + state_tracker{state_tracker_}, shader_notify{shader_notify_}, + use_asynchronous_shaders{device.UseAsynchronousShaders()}, profile{ .supported_spirv = 0x00010000, @@ -261,7 +254,7 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading, [this, key, env = std::move(env), &state, &callback](Context* ctx) mutable { ctx->pools.ReleaseContents(); auto pipeline{CreateComputePipeline(ctx->pools, key, env)}; - std::lock_guard lock{state.mutex}; + std::scoped_lock lock{state.mutex}; if (pipeline) { compute_cache.emplace(key, std::move(pipeline)); } @@ -283,7 +276,7 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading, } ctx->pools.ReleaseContents(); auto pipeline{CreateGraphicsPipeline(ctx->pools, key, MakeSpan(env_ptrs), false)}; - std::lock_guard lock{state.mutex}; + std::scoped_lock lock{state.mutex}; if (pipeline) { graphics_cache.emplace(key, std::move(pipeline)); } @@ -303,7 +296,7 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading, state.has_loaded = true; lock.unlock(); - workers->WaitForRequests(); + workers->WaitForRequests(stop_loading); if (!use_asynchronous_shaders) { workers.reset(); } @@ -314,7 +307,7 @@ GraphicsPipeline* ShaderCache::CurrentGraphicsPipeline() { current_pipeline = nullptr; return nullptr; } - const auto& regs{maxwell3d.regs}; + const auto& regs{maxwell3d->regs}; graphics_key.raw = 0; graphics_key.early_z.Assign(regs.force_early_fragment_tests != 0 ? 1 : 0); graphics_key.gs_input_topology.Assign(graphics_key.unique_hashes[4] != 0 @@ -355,13 +348,13 @@ GraphicsPipeline* ShaderCache::BuiltPipeline(GraphicsPipeline* pipeline) const n } // If something is using depth, we can assume that games are not rendering anything which // will be used one time. - if (maxwell3d.regs.zeta_enable) { + if (maxwell3d->regs.zeta_enable) { return nullptr; } // If games are using a small index count, we can assume these are full screen quads. // Usually these shaders are only used once for building textures so we can assume they // can't be built async - if (maxwell3d.regs.index_array.count <= 6 || maxwell3d.regs.vertex_buffer.count <= 6) { + if (maxwell3d->regs.index_array.count <= 6 || maxwell3d->regs.vertex_buffer.count <= 6) { return pipeline; } return nullptr; @@ -372,7 +365,7 @@ ComputePipeline* ShaderCache::CurrentComputePipeline() { if (!shader) { return nullptr; } - const auto& qmd{kepler_compute.launch_description}; + const auto& qmd{kepler_compute->launch_description}; const ComputePipelineKey key{ .unique_hash = shader->unique_hash, .shared_memory_size = qmd.shared_alloc, @@ -484,9 +477,9 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline( previous_program = &program; } auto* const thread_worker{build_in_parallel ? workers.get() : nullptr}; - return std::make_unique<GraphicsPipeline>( - device, texture_cache, buffer_cache, gpu_memory, maxwell3d, program_manager, state_tracker, - thread_worker, &shader_notify, sources, sources_spirv, infos, key); + return std::make_unique<GraphicsPipeline>(device, texture_cache, buffer_cache, program_manager, + state_tracker, thread_worker, &shader_notify, sources, + sources_spirv, infos, key); } catch (Shader::Exception& exception) { LOG_ERROR(Render_OpenGL, "{}", exception.what()); @@ -495,9 +488,9 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline( std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline( const ComputePipelineKey& key, const VideoCommon::ShaderInfo* shader) { - const GPUVAddr program_base{kepler_compute.regs.code_loc.Address()}; - const auto& qmd{kepler_compute.launch_description}; - ComputeEnvironment env{kepler_compute, gpu_memory, program_base, qmd.program_start}; + const GPUVAddr program_base{kepler_compute->regs.code_loc.Address()}; + const auto& qmd{kepler_compute->launch_description}; + ComputeEnvironment env{*kepler_compute, *gpu_memory, program_base, qmd.program_start}; env.SetCachedSize(shader->size_bytes); main_pools.ReleaseContents(); @@ -540,9 +533,8 @@ std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline( break; } - return std::make_unique<ComputePipeline>(device, texture_cache, buffer_cache, gpu_memory, - kepler_compute, program_manager, program.info, code, - code_spirv); + return std::make_unique<ComputePipeline>(device, texture_cache, buffer_cache, program_manager, + program.info, code, code_spirv); } catch (Shader::Exception& exception) { LOG_ERROR(Render_OpenGL, "{}", exception.what()); return nullptr; @@ -550,7 +542,7 @@ std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline( std::unique_ptr<ShaderWorker> ShaderCache::CreateWorkers() const { return std::make_unique<ShaderWorker>(std::max(std::thread::hardware_concurrency(), 2U) - 1, - "yuzu:ShaderBuilder", + "GlShaderBuilder", [this] { return Context{emu_window}; }); } diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h index a34110b37..89f181fe3 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_cache.h @@ -1,21 +1,15 @@ -// Copyright 2018 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once -#include <array> #include <filesystem> #include <stop_token> #include <unordered_map> -#include <glad/glad.h> - #include "common/common_types.h" #include "common/thread_worker.h" -#include "shader_recompiler/frontend/ir/value.h" #include "shader_recompiler/host_translate_info.h" -#include "shader_recompiler/object_pool.h" #include "shader_recompiler/profile.h" #include "video_core/renderer_opengl/gl_compute_pipeline.h" #include "video_core/renderer_opengl/gl_graphics_pipeline.h" @@ -36,12 +30,9 @@ using ShaderWorker = Common::StatefulThreadWorker<ShaderContext::Context>; class ShaderCache : public VideoCommon::ShaderCache { public: explicit ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindow& emu_window_, - Tegra::Engines::Maxwell3D& maxwell3d_, - Tegra::Engines::KeplerCompute& kepler_compute_, - Tegra::MemoryManager& gpu_memory_, const Device& device_, - TextureCache& texture_cache_, BufferCache& buffer_cache_, - ProgramManager& program_manager_, StateTracker& state_tracker_, - VideoCore::ShaderNotify& shader_notify_); + const Device& device_, TextureCache& texture_cache_, + BufferCache& buffer_cache_, ProgramManager& program_manager_, + StateTracker& state_tracker_, VideoCore::ShaderNotify& shader_notify_); ~ShaderCache(); void LoadDiskResources(u64 title_id, std::stop_token stop_loading, diff --git a/src/video_core/renderer_opengl/gl_shader_context.h b/src/video_core/renderer_opengl/gl_shader_context.h index 6ff34e5d6..ca2bd8e8e 100644 --- a/src/video_core/renderer_opengl/gl_shader_context.h +++ b/src/video_core/renderer_opengl/gl_shader_context.h @@ -1,6 +1,5 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp index 399959afb..d9c29d8b7 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.cpp +++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp @@ -1,3 +1,2 @@ -// Copyright 2018 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index d7ef0775d..a84f5aeb3 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h @@ -1,6 +1,5 @@ -// Copyright 2018 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once diff --git a/src/video_core/renderer_opengl/gl_shader_util.cpp b/src/video_core/renderer_opengl/gl_shader_util.cpp index d432072ad..a0d9d10ef 100644 --- a/src/video_core/renderer_opengl/gl_shader_util.cpp +++ b/src/video_core/renderer_opengl/gl_shader_util.cpp @@ -1,12 +1,10 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: 2014 Citra Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <string_view> #include <vector> #include <glad/glad.h> -#include "common/assert.h" #include "common/logging/log.h" #include "common/settings.h" #include "video_core/renderer_opengl/gl_shader_util.h" @@ -19,6 +17,7 @@ static OGLProgram LinkSeparableProgram(GLuint shader) { glProgramParameteri(program.handle, GL_PROGRAM_SEPARABLE, GL_TRUE); glAttachShader(program.handle, shader); glLinkProgram(program.handle); + glDetachShader(program.handle, shader); if (!Settings::values.renderer_debug) { return program; } diff --git a/src/video_core/renderer_opengl/gl_shader_util.h b/src/video_core/renderer_opengl/gl_shader_util.h index 4e1a2a8e1..43ebcdeba 100644 --- a/src/video_core/renderer_opengl/gl_shader_util.h +++ b/src/video_core/renderer_opengl/gl_shader_util.h @@ -1,18 +1,13 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: 2014 Citra Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include <span> -#include <string> #include <string_view> -#include <vector> #include <glad/glad.h> -#include "common/assert.h" -#include "common/logging/log.h" #include "video_core/renderer_opengl/gl_resource_manager.h" namespace OpenGL { diff --git a/src/video_core/renderer_opengl/gl_state_tracker.cpp b/src/video_core/renderer_opengl/gl_state_tracker.cpp index 586da84e3..a8f3a0f57 100644 --- a/src/video_core/renderer_opengl/gl_state_tracker.cpp +++ b/src/video_core/renderer_opengl/gl_state_tracker.cpp @@ -1,6 +1,5 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> #include <array> @@ -8,8 +7,8 @@ #include "common/common_types.h" #include "core/core.h" +#include "video_core/control/channel_state.h" #include "video_core/engines/maxwell_3d.h" -#include "video_core/gpu.h" #include "video_core/renderer_opengl/gl_state_tracker.h" #define OFF(field_name) MAXWELL3D_REG_INDEX(field_name) @@ -203,9 +202,8 @@ void SetupDirtyMisc(Tables& tables) { } // Anonymous namespace -StateTracker::StateTracker(Tegra::GPU& gpu) : flags{gpu.Maxwell3D().dirty.flags} { - auto& dirty = gpu.Maxwell3D().dirty; - auto& tables = dirty.tables; +void StateTracker::SetupTables(Tegra::Control::ChannelState& channel_state) { + auto& tables{channel_state.maxwell_3d->dirty.tables}; SetupDirtyFlags(tables); SetupDirtyColorMasks(tables); SetupDirtyViewports(tables); @@ -231,4 +229,14 @@ StateTracker::StateTracker(Tegra::GPU& gpu) : flags{gpu.Maxwell3D().dirty.flags} SetupDirtyMisc(tables); } +void StateTracker::ChangeChannel(Tegra::Control::ChannelState& channel_state) { + flags = &channel_state.maxwell_3d->dirty.flags; +} + +void StateTracker::InvalidateState() { + flags->set(); +} + +StateTracker::StateTracker() : flags{&default_flags} {} + } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_state_tracker.h b/src/video_core/renderer_opengl/gl_state_tracker.h index 5864c7c07..19bcf3f35 100644 --- a/src/video_core/renderer_opengl/gl_state_tracker.h +++ b/src/video_core/renderer_opengl/gl_state_tracker.h @@ -1,6 +1,5 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -9,13 +8,14 @@ #include <glad/glad.h> #include "common/common_types.h" -#include "core/core.h" #include "video_core/dirty_flags.h" #include "video_core/engines/maxwell_3d.h" namespace Tegra { -class GPU; +namespace Control { +struct ChannelState; } +} // namespace Tegra namespace OpenGL { @@ -85,7 +85,7 @@ static_assert(Last <= std::numeric_limits<u8>::max()); class StateTracker { public: - explicit StateTracker(Tegra::GPU& gpu); + explicit StateTracker(); void BindIndexBuffer(GLuint new_index_buffer) { if (index_buffer == new_index_buffer) { @@ -123,94 +123,107 @@ public: } void NotifyScreenDrawVertexArray() { - flags[OpenGL::Dirty::VertexFormats] = true; - flags[OpenGL::Dirty::VertexFormat0 + 0] = true; - flags[OpenGL::Dirty::VertexFormat0 + 1] = true; + (*flags)[OpenGL::Dirty::VertexFormats] = true; + (*flags)[OpenGL::Dirty::VertexFormat0 + 0] = true; + (*flags)[OpenGL::Dirty::VertexFormat0 + 1] = true; - flags[VideoCommon::Dirty::VertexBuffers] = true; - flags[VideoCommon::Dirty::VertexBuffer0] = true; + (*flags)[VideoCommon::Dirty::VertexBuffers] = true; + (*flags)[VideoCommon::Dirty::VertexBuffer0] = true; - flags[OpenGL::Dirty::VertexInstances] = true; - flags[OpenGL::Dirty::VertexInstance0 + 0] = true; - flags[OpenGL::Dirty::VertexInstance0 + 1] = true; + (*flags)[OpenGL::Dirty::VertexInstances] = true; + (*flags)[OpenGL::Dirty::VertexInstance0 + 0] = true; + (*flags)[OpenGL::Dirty::VertexInstance0 + 1] = true; } void NotifyPolygonModes() { - flags[OpenGL::Dirty::PolygonModes] = true; - flags[OpenGL::Dirty::PolygonModeFront] = true; - flags[OpenGL::Dirty::PolygonModeBack] = true; + (*flags)[OpenGL::Dirty::PolygonModes] = true; + (*flags)[OpenGL::Dirty::PolygonModeFront] = true; + (*flags)[OpenGL::Dirty::PolygonModeBack] = true; } void NotifyViewport0() { - flags[OpenGL::Dirty::Viewports] = true; - flags[OpenGL::Dirty::Viewport0] = true; + (*flags)[OpenGL::Dirty::Viewports] = true; + (*flags)[OpenGL::Dirty::Viewport0] = true; } void NotifyScissor0() { - flags[OpenGL::Dirty::Scissors] = true; - flags[OpenGL::Dirty::Scissor0] = true; + (*flags)[OpenGL::Dirty::Scissors] = true; + (*flags)[OpenGL::Dirty::Scissor0] = true; } void NotifyColorMask(size_t index) { - flags[OpenGL::Dirty::ColorMasks] = true; - flags[OpenGL::Dirty::ColorMask0 + index] = true; + (*flags)[OpenGL::Dirty::ColorMasks] = true; + (*flags)[OpenGL::Dirty::ColorMask0 + index] = true; } void NotifyBlend0() { - flags[OpenGL::Dirty::BlendStates] = true; - flags[OpenGL::Dirty::BlendState0] = true; + (*flags)[OpenGL::Dirty::BlendStates] = true; + (*flags)[OpenGL::Dirty::BlendState0] = true; } void NotifyFramebuffer() { - flags[VideoCommon::Dirty::RenderTargets] = true; + (*flags)[VideoCommon::Dirty::RenderTargets] = true; } void NotifyFrontFace() { - flags[OpenGL::Dirty::FrontFace] = true; + (*flags)[OpenGL::Dirty::FrontFace] = true; } void NotifyCullTest() { - flags[OpenGL::Dirty::CullTest] = true; + (*flags)[OpenGL::Dirty::CullTest] = true; } void NotifyDepthMask() { - flags[OpenGL::Dirty::DepthMask] = true; + (*flags)[OpenGL::Dirty::DepthMask] = true; } void NotifyDepthTest() { - flags[OpenGL::Dirty::DepthTest] = true; + (*flags)[OpenGL::Dirty::DepthTest] = true; } void NotifyStencilTest() { - flags[OpenGL::Dirty::StencilTest] = true; + (*flags)[OpenGL::Dirty::StencilTest] = true; } void NotifyPolygonOffset() { - flags[OpenGL::Dirty::PolygonOffset] = true; + (*flags)[OpenGL::Dirty::PolygonOffset] = true; } void NotifyRasterizeEnable() { - flags[OpenGL::Dirty::RasterizeEnable] = true; + (*flags)[OpenGL::Dirty::RasterizeEnable] = true; } void NotifyFramebufferSRGB() { - flags[OpenGL::Dirty::FramebufferSRGB] = true; + (*flags)[OpenGL::Dirty::FramebufferSRGB] = true; } void NotifyLogicOp() { - flags[OpenGL::Dirty::LogicOp] = true; + (*flags)[OpenGL::Dirty::LogicOp] = true; } void NotifyClipControl() { - flags[OpenGL::Dirty::ClipControl] = true; + (*flags)[OpenGL::Dirty::ClipControl] = true; } void NotifyAlphaTest() { - flags[OpenGL::Dirty::AlphaTest] = true; + (*flags)[OpenGL::Dirty::AlphaTest] = true; } + void NotifyRange(u8 start, u8 end) { + for (auto flag = start; flag <= end; flag++) { + (*flags)[flag] = true; + } + } + + void SetupTables(Tegra::Control::ChannelState& channel_state); + + void ChangeChannel(Tegra::Control::ChannelState& channel_state); + + void InvalidateState(); + private: - Tegra::Engines::Maxwell3D::DirtyState::Flags& flags; + Tegra::Engines::Maxwell3D::DirtyState::Flags* flags; + Tegra::Engines::Maxwell3D::DirtyState::Flags default_flags{}; GLuint framebuffer = 0; GLuint index_buffer = 0; diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.cpp b/src/video_core/renderer_opengl/gl_stream_buffer.cpp index 77b3ee0fe..2005c8993 100644 --- a/src/video_core/renderer_opengl/gl_stream_buffer.cpp +++ b/src/video_core/renderer_opengl/gl_stream_buffer.cpp @@ -1,6 +1,5 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <array> #include <memory> diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.h b/src/video_core/renderer_opengl/gl_stream_buffer.h index 2e67922a6..8fe927aaf 100644 --- a/src/video_core/renderer_opengl/gl_stream_buffer.h +++ b/src/video_core/renderer_opengl/gl_stream_buffer.h @@ -1,11 +1,9 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include <array> -#include <memory> #include <span> #include <utility> diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 3c1f79a27..99cd11d1e 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp @@ -1,6 +1,5 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> #include <array> @@ -84,7 +83,7 @@ GLenum ImageTarget(const VideoCommon::ImageInfo& info) { case ImageType::Buffer: return GL_TEXTURE_BUFFER; } - UNREACHABLE_MSG("Invalid image type={}", info.type); + ASSERT_MSG(false, "Invalid image type={}", info.type); return GL_NONE; } @@ -94,6 +93,7 @@ GLenum ImageTarget(Shader::TextureType type, int num_samples = 1) { case Shader::TextureType::Color1D: return GL_TEXTURE_1D; case Shader::TextureType::Color2D: + case Shader::TextureType::Color2DRect: return is_multisampled ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; case Shader::TextureType::ColorCube: return GL_TEXTURE_CUBE_MAP; @@ -108,7 +108,7 @@ GLenum ImageTarget(Shader::TextureType type, int num_samples = 1) { case Shader::TextureType::Buffer: return GL_TEXTURE_BUFFER; } - UNREACHABLE_MSG("Invalid image view type={}", type); + ASSERT_MSG(false, "Invalid image view type={}", type); return GL_NONE; } @@ -120,7 +120,7 @@ GLenum TextureMode(PixelFormat format, bool is_first) { case PixelFormat::S8_UINT_D24_UNORM: return is_first ? GL_STENCIL_INDEX : GL_DEPTH_COMPONENT; default: - UNREACHABLE(); + ASSERT(false); return GL_DEPTH_COMPONENT; } } @@ -141,7 +141,7 @@ GLint Swizzle(SwizzleSource source) { case SwizzleSource::OneFloat: return GL_ONE; } - UNREACHABLE_MSG("Invalid swizzle source={}", source); + ASSERT_MSG(false, "Invalid swizzle source={}", source); return GL_NONE; } @@ -182,6 +182,26 @@ GLenum AttachmentType(PixelFormat format) { } } +GLint ConvertA5B5G5R1_UNORM(SwizzleSource source) { + switch (source) { + case SwizzleSource::Zero: + return GL_ZERO; + case SwizzleSource::R: + return GL_ALPHA; + case SwizzleSource::G: + return GL_BLUE; + case SwizzleSource::B: + return GL_GREEN; + case SwizzleSource::A: + return GL_RED; + case SwizzleSource::OneInt: + case SwizzleSource::OneFloat: + return GL_ONE; + } + ASSERT_MSG(false, "Invalid swizzle source={}", source); + return GL_NONE; +} + void ApplySwizzle(GLuint handle, PixelFormat format, std::array<SwizzleSource, 4> swizzle) { switch (format) { case PixelFormat::D24_UNORM_S8_UINT: @@ -192,6 +212,12 @@ void ApplySwizzle(GLuint handle, PixelFormat format, std::array<SwizzleSource, 4 TextureMode(format, swizzle[0] == SwizzleSource::R)); std::ranges::transform(swizzle, swizzle.begin(), ConvertGreenRed); break; + case PixelFormat::A5B5G5R1_UNORM: { + std::array<GLint, 4> gl_swizzle; + std::ranges::transform(swizzle, gl_swizzle.begin(), ConvertA5B5G5R1_UNORM); + glTextureParameteriv(handle, GL_TEXTURE_SWIZZLE_RGBA, gl_swizzle.data()); + return; + } default: break; } @@ -356,10 +382,10 @@ OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_form glTextureStorage3D(handle, gl_num_levels, gl_internal_format, width, height, depth); break; case GL_TEXTURE_BUFFER: - UNREACHABLE(); + ASSERT(false); break; default: - UNREACHABLE_MSG("Invalid target=0x{:x}", target); + ASSERT_MSG(false, "Invalid target=0x{:x}", target); break; } return texture; @@ -395,7 +421,7 @@ OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_form case Shader::ImageFormat::R32G32B32A32_UINT: return GL_RGBA32UI; } - UNREACHABLE_MSG("Invalid image format={}", format); + ASSERT_MSG(false, "Invalid image format={}", format); return GL_R32UI; } @@ -409,8 +435,8 @@ ImageBufferMap::~ImageBufferMap() { TextureCacheRuntime::TextureCacheRuntime(const Device& device_, ProgramManager& program_manager, StateTracker& state_tracker_) - : device{device_}, state_tracker{state_tracker_}, - util_shaders(program_manager), resolution{Settings::values.resolution_info} { + : device{device_}, state_tracker{state_tracker_}, util_shaders(program_manager), + format_conversion_pass{util_shaders}, resolution{Settings::values.resolution_info} { static constexpr std::array TARGETS{GL_TEXTURE_1D_ARRAY, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_3D}; for (size_t i = 0; i < TARGETS.size(); ++i) { const GLenum target = TARGETS[i]; @@ -477,6 +503,7 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, ProgramManager& set_view(Shader::TextureType::ColorArray1D, null_image_1d_array.handle); set_view(Shader::TextureType::ColorArray2D, null_image_view_2d_array.handle); set_view(Shader::TextureType::ColorArrayCube, null_image_cube_array.handle); + set_view(Shader::TextureType::Color2DRect, null_image_view_2d.handle); if (resolution.active) { for (size_t i = 0; i < rescale_draw_fbos.size(); ++i) { @@ -484,6 +511,13 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, ProgramManager& rescale_read_fbos[i].Create(); } } + + device_access_memory = [this]() -> u64 { + if (device.CanReportMemoryUsage()) { + return device.GetCurrentDedicatedVideoMemory() + 512_MiB; + } + return 2_GiB; // Return minimum requirements + }(); } TextureCacheRuntime::~TextureCacheRuntime() = default; @@ -500,13 +534,11 @@ ImageBufferMap TextureCacheRuntime::DownloadStagingBuffer(size_t size) { return download_buffers.RequestMap(size, false); } -u64 TextureCacheRuntime::GetDeviceLocalMemory() const { - if (GLAD_GL_NVX_gpu_memory_info) { - GLint cur_avail_mem_kb = 0; - glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &cur_avail_mem_kb); - return static_cast<u64>(cur_avail_mem_kb) * 1_KiB; +u64 TextureCacheRuntime::GetDeviceMemoryUsage() const { + if (device.CanReportMemoryUsage()) { + return device_access_memory - device.GetCurrentDedicatedVideoMemory(); } - return 2_GiB; // Return minimum requirements + return 2_GiB; } void TextureCacheRuntime::CopyImage(Image& dst_image, Image& src_image, @@ -549,7 +581,7 @@ void TextureCacheRuntime::EmulateCopyImage(Image& dst, Image& src, } else if (IsPixelFormatBGR(dst.info.format) || IsPixelFormatBGR(src.info.format)) { format_conversion_pass.ConvertImage(dst, src, copies); } else { - UNREACHABLE(); + ASSERT(false); } } @@ -590,7 +622,7 @@ void TextureCacheRuntime::AccelerateImageUpload(Image& image, const ImageBufferM case ImageType::Linear: return util_shaders.PitchUpload(image, map, swizzles); default: - UNREACHABLE(); + ASSERT(false); break; } } @@ -609,7 +641,7 @@ FormatProperties TextureCacheRuntime::FormatInfo(ImageType type, GLenum internal case ImageType::e3D: return format_properties[2].at(internal_format); default: - UNREACHABLE(); + ASSERT(false); return FormatProperties{}; } } @@ -686,6 +718,7 @@ Image::Image(TextureCacheRuntime& runtime_, const VideoCommon::ImageInfo& info_, } if (IsConverted(runtime->device, info.format, info.type)) { flags |= ImageFlagBits::Converted; + flags |= ImageFlagBits::CostlyLoad; gl_internal_format = IsPixelFormatSRGB(info.format) ? GL_SRGB8_ALPHA8 : GL_RGBA8; gl_format = GL_RGBA; gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; @@ -857,7 +890,7 @@ void Image::CopyBufferToImage(const VideoCommon::BufferImageCopy& copy, size_t b } break; default: - UNREACHABLE(); + ASSERT(false); } } @@ -893,7 +926,7 @@ void Image::CopyImageToBuffer(const VideoCommon::BufferImageCopy& copy, size_t b depth = copy.image_extent.depth; break; default: - UNREACHABLE(); + ASSERT(false); } // Compressed formats don't have a pixel format or type const bool is_compressed = gl_format == GL_NONE; @@ -919,7 +952,7 @@ void Image::Scale(bool up_scale) { case SurfaceType::DepthStencil: return GL_DEPTH_STENCIL_ATTACHMENT; default: - UNREACHABLE(); + ASSERT(false); return GL_COLOR_ATTACHMENT0; } }(); @@ -934,7 +967,7 @@ void Image::Scale(bool up_scale) { case SurfaceType::DepthStencil: return GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; default: - UNREACHABLE(); + ASSERT(false); return GL_COLOR_BUFFER_BIT; } }(); @@ -949,7 +982,7 @@ void Image::Scale(bool up_scale) { case SurfaceType::DepthStencil: return 3; default: - UNREACHABLE(); + ASSERT(false); return 0; } }(); @@ -1014,7 +1047,7 @@ bool Image::ScaleUp(bool ignore) { return false; } if (info.type == ImageType::Linear) { - UNREACHABLE(); + ASSERT(false); return false; } flags |= ImageFlagBits::Rescaled; @@ -1079,6 +1112,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI flat_range.extent.layers = 1; [[fallthrough]]; case ImageViewType::e2D: + case ImageViewType::Rect: if (True(flags & VideoCommon::ImageViewFlagBits::Slice)) { // 2D and 2D array views on a 3D textures are used exclusively for render targets ASSERT(info.range.extent.levels == 1); @@ -1104,11 +1138,8 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI SetupView(Shader::TextureType::ColorCube); SetupView(Shader::TextureType::ColorArrayCube); break; - case ImageViewType::Rect: - UNIMPLEMENTED(); - break; case ImageViewType::Buffer: - UNREACHABLE(); + ASSERT(false); break; } switch (info.type) { @@ -1119,6 +1150,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI default_handle = Handle(Shader::TextureType::ColorArray1D); break; case ImageViewType::e2D: + case ImageViewType::Rect: default_handle = Handle(Shader::TextureType::Color2D); break; case ImageViewType::e2DArray: @@ -1179,6 +1211,7 @@ GLuint ImageView::MakeView(Shader::TextureType view_type, GLenum view_format) { case Shader::TextureType::Color1D: case Shader::TextureType::Color2D: case Shader::TextureType::ColorCube: + case Shader::TextureType::Color2DRect: view_range = flat_range; break; case Shader::TextureType::ColorArray1D: @@ -1219,7 +1252,6 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const TSCEntry& config) { const GLint seamless = config.cubemap_interface_filtering ? GL_TRUE : GL_FALSE; UNIMPLEMENTED_IF(config.cubemap_anisotropy != 1); - UNIMPLEMENTED_IF(config.float_coord_normalization != 0); sampler.Create(); const GLuint handle = sampler.handle; @@ -1288,7 +1320,7 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM buffer_bits |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; break; default: - UNREACHABLE(); + ASSERT(false); buffer_bits |= GL_DEPTH_BUFFER_BIT; break; } @@ -1319,6 +1351,9 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM Framebuffer::~Framebuffer() = default; +FormatConversionPass::FormatConversionPass(UtilShaders& util_shaders_) + : util_shaders{util_shaders_} {} + void FormatConversionPass::ConvertImage(Image& dst_image, Image& src_image, std::span<const VideoCommon::ImageCopy> copies) { const GLenum dst_target = ImageTarget(dst_image.info); @@ -1351,6 +1386,12 @@ void FormatConversionPass::ConvertImage(Image& dst_image, Image& src_image, dst_origin.z, region.width, region.height, region.depth, dst_image.GlFormat(), dst_image.GlType(), nullptr); } + + // Swap component order of S8D24 to ABGR8 reinterprets + if (src_image.info.format == PixelFormat::D24_UNORM_S8_UINT && + dst_image.info.format == PixelFormat::A8B8G8R8_UNORM) { + util_shaders.ConvertS8D24(dst_image, copies); + } } } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index 7f425631f..113528e9b 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h @@ -1,6 +1,5 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -10,6 +9,7 @@ #include <glad/glad.h> #include "shader_recompiler/shader_info.h" +#include "video_core/renderer_opengl/gl_device.h" #include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/util_shaders.h" #include "video_core/texture_cache/image_view_base.h" @@ -21,7 +21,6 @@ struct ResolutionScalingInfo; namespace OpenGL { -class Device; class ProgramManager; class StateTracker; @@ -55,13 +54,14 @@ struct FormatProperties { class FormatConversionPass { public: - FormatConversionPass() = default; + explicit FormatConversionPass(UtilShaders& util_shaders); ~FormatConversionPass() = default; void ConvertImage(Image& dst_image, Image& src_image, std::span<const VideoCommon::ImageCopy> copies); private: + UtilShaders& util_shaders; OGLBuffer intermediate_pbo; size_t pbo_size{}; }; @@ -83,7 +83,15 @@ public: ImageBufferMap DownloadStagingBuffer(size_t size); - u64 GetDeviceLocalMemory() const; + u64 GetDeviceLocalMemory() const { + return device_access_memory; + } + + u64 GetDeviceMemoryUsage() const; + + bool CanReportMemoryUsage() const { + return device.CanReportMemoryUsage(); + } bool ShouldReinterpret([[maybe_unused]] Image& dst, [[maybe_unused]] Image& src) { return true; @@ -172,6 +180,7 @@ private: std::array<OGLFramebuffer, 4> rescale_draw_fbos; std::array<OGLFramebuffer, 4> rescale_read_fbos; const Settings::ResolutionScalingInfo& resolution; + u64 device_access_memory; }; class Image : public VideoCommon::ImageBase { diff --git a/src/video_core/renderer_opengl/gl_texture_cache_base.cpp b/src/video_core/renderer_opengl/gl_texture_cache_base.cpp index 385358fea..64416fd51 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache_base.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache_base.cpp @@ -1,6 +1,5 @@ -// Copyright 2021 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include "video_core/renderer_opengl/gl_texture_cache.h" #include "video_core/texture_cache/texture_cache.h" diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index daba42ed9..004421236 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h @@ -1,6 +1,5 @@ -// Copyright 2018 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -30,6 +29,7 @@ constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> FORMAT_TAB {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV}, // A2B10G10R10_UNORM {GL_RGB10_A2UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV}, // A2B10G10R10_UINT {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV}, // A1B5G5R5_UNORM + {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1}, // A5B5G5R1_UNORM {GL_R8, GL_RED, GL_UNSIGNED_BYTE}, // R8_UNORM {GL_R8_SNORM, GL_RED, GL_BYTE}, // R8_SNORM {GL_R8I, GL_RED_INTEGER, GL_BYTE}, // R8_SINT @@ -87,6 +87,7 @@ constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> FORMAT_TAB {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT}, // BC3_SRGB {GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM}, // BC7_SRGB {GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV}, // A4B4G4R4_UNORM + {GL_R8, GL_RED, GL_UNSIGNED_BYTE}, // G4R4_UNORM {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR}, // ASTC_2D_4X4_SRGB {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR}, // ASTC_2D_8X8_SRGB {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR}, // ASTC_2D_8X5_SRGB @@ -97,6 +98,9 @@ constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> FORMAT_TAB {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR}, // ASTC_2D_10X8_SRGB {GL_COMPRESSED_RGBA_ASTC_6x6_KHR}, // ASTC_2D_6X6_UNORM {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR}, // ASTC_2D_6X6_SRGB + {GL_COMPRESSED_RGBA_ASTC_10x6_KHR}, // ASTC_2D_10X6_UNORM + {GL_COMPRESSED_RGBA_ASTC_10x5_KHR}, // ASTC_2D_10X5_UNORM + {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR}, // ASTC_2D_10X5_SRGB {GL_COMPRESSED_RGBA_ASTC_10x10_KHR}, // ASTC_2D_10X10_UNORM {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR}, // ASTC_2D_10X10_SRGB {GL_COMPRESSED_RGBA_ASTC_12x12_KHR}, // ASTC_2D_12X12_UNORM @@ -184,6 +188,8 @@ inline GLenum VertexFormat(Maxwell::VertexAttribute attrib) { case Maxwell::VertexAttribute::Size::Size_32_32_32: case Maxwell::VertexAttribute::Size::Size_32_32_32_32: return GL_FLOAT; + case Maxwell::VertexAttribute::Size::Size_11_11_10: + return GL_UNSIGNED_INT_10F_11F_11F_REV; default: break; } @@ -203,7 +209,7 @@ inline GLenum IndexFormat(Maxwell::IndexFormat index_format) { case Maxwell::IndexFormat::UnsignedInt: return GL_UNSIGNED_INT; } - UNREACHABLE_MSG("Invalid index_format={}", index_format); + ASSERT_MSG(false, "Invalid index_format={}", index_format); return {}; } @@ -240,7 +246,7 @@ inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) { case Maxwell::PrimitiveTopology::Patches: return GL_PATCHES; } - UNREACHABLE_MSG("Invalid topology={}", topology); + ASSERT_MSG(false, "Invalid topology={}", topology); return GL_POINTS; } @@ -268,8 +274,8 @@ inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode, } break; } - UNREACHABLE_MSG("Invalid texture filter mode={} and mipmap filter mode={}", filter_mode, - mipmap_filter_mode); + ASSERT_MSG(false, "Invalid texture filter mode={} and mipmap filter mode={}", filter_mode, + mipmap_filter_mode); return GL_NEAREST; } @@ -547,7 +553,7 @@ inline GLenum PolygonMode(Maxwell::PolygonMode polygon_mode) { case Maxwell::PolygonMode::Fill: return GL_FILL; } - UNREACHABLE_MSG("Invalid polygon mode={}", polygon_mode); + ASSERT_MSG(false, "Invalid polygon mode={}", polygon_mode); return GL_FILL; } @@ -560,7 +566,7 @@ inline GLenum ReductionFilter(Tegra::Texture::SamplerReduction filter) { case Tegra::Texture::SamplerReduction::Max: return GL_MAX; } - UNREACHABLE_MSG("Invalid reduction filter={}", static_cast<int>(filter)); + ASSERT_MSG(false, "Invalid reduction filter={}", static_cast<int>(filter)); return GL_WEIGHTED_AVERAGE_ARB; } diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index f81c1b233..8bd5eba7e 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -1,11 +1,9 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: 2014 Citra Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> #include <cstddef> #include <cstdlib> -#include <cstring> #include <memory> #include <glad/glad.h> @@ -15,11 +13,9 @@ #include "common/microprofile.h" #include "common/settings.h" #include "common/telemetry.h" -#include "core/core.h" #include "core/core_timing.h" #include "core/frontend/emu_window.h" #include "core/memory.h" -#include "core/perf_stats.h" #include "core/telemetry_session.h" #include "video_core/host_shaders/fxaa_frag.h" #include "video_core/host_shaders/fxaa_vert.h" @@ -82,7 +78,7 @@ const char* GetSource(GLenum source) { case GL_DEBUG_SOURCE_OTHER: return "OTHER"; default: - UNREACHABLE(); + ASSERT(false); return "Unknown source"; } } @@ -104,7 +100,7 @@ const char* GetType(GLenum type) { case GL_DEBUG_TYPE_MARKER: return "MARKER"; default: - UNREACHABLE(); + ASSERT(false); return "Unknown type"; } } @@ -135,7 +131,7 @@ RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_, Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_, std::unique_ptr<Core::Frontend::GraphicsContext> context_) : RendererBase{emu_window_, std::move(context_)}, telemetry_session{telemetry_session_}, - emu_window{emu_window_}, cpu_memory{cpu_memory_}, gpu{gpu_}, state_tracker{gpu}, + emu_window{emu_window_}, cpu_memory{cpu_memory_}, gpu{gpu_}, state_tracker{}, program_manager{device}, rasterizer(emu_window, gpu, cpu_memory, device, screen_info, program_manager, state_tracker) { if (Settings::values.renderer_debug && GLAD_GL_KHR_debug) { @@ -211,6 +207,8 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf // Framebuffer orientation handling framebuffer_transform_flags = framebuffer.transform_flags; framebuffer_crop_rect = framebuffer.crop_rect; + framebuffer_width = framebuffer.width; + framebuffer_height = framebuffer.height; const VAddr framebuffer_addr{framebuffer.address + framebuffer.offset}; screen_info.was_accelerated = @@ -326,12 +324,12 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, GLint internal_format; switch (framebuffer.pixel_format) { - case Tegra::FramebufferConfig::PixelFormat::A8B8G8R8_UNORM: + case Service::android::PixelFormat::Rgba8888: internal_format = GL_RGBA8; texture.gl_format = GL_RGBA; texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; break; - case Tegra::FramebufferConfig::PixelFormat::RGB565_UNORM: + case Service::android::PixelFormat::Rgb565: internal_format = GL_RGB565; texture.gl_format = GL_RGB; texture.gl_type = GL_UNSIGNED_SHORT_5_6_5; @@ -467,8 +465,8 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { const auto& texcoords = screen_info.display_texcoords; auto left = texcoords.left; auto right = texcoords.right; - if (framebuffer_transform_flags != Tegra::FramebufferConfig::TransformFlags::Unset) { - if (framebuffer_transform_flags == Tegra::FramebufferConfig::TransformFlags::FlipV) { + if (framebuffer_transform_flags != Service::android::BufferTransformFlags::Unset) { + if (framebuffer_transform_flags == Service::android::BufferTransformFlags::FlipV) { // Flip the framebuffer vertically left = texcoords.right; right = texcoords.left; @@ -480,12 +478,18 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { } } - ASSERT_MSG(framebuffer_crop_rect.top == 0, "Unimplemented"); ASSERT_MSG(framebuffer_crop_rect.left == 0, "Unimplemented"); + f32 left_start{}; + if (framebuffer_crop_rect.Top() > 0) { + left_start = static_cast<f32>(framebuffer_crop_rect.Top()) / + static_cast<f32>(framebuffer_crop_rect.Bottom()); + } + f32 scale_u = static_cast<f32>(framebuffer_width) / static_cast<f32>(screen_info.texture.width); + f32 scale_v = + static_cast<f32>(framebuffer_height) / static_cast<f32>(screen_info.texture.height); // Scale the output by the crop width/height. This is commonly used with 1280x720 rendering // (e.g. handheld mode) on a 1920x1080 framebuffer. - f32 scale_u = 1.f, scale_v = 1.f; if (framebuffer_crop_rect.GetWidth() > 0) { scale_u = static_cast<f32>(framebuffer_crop_rect.GetWidth()) / static_cast<f32>(screen_info.texture.width); @@ -502,10 +506,14 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { const auto& screen = layout.screen; const std::array vertices = { - ScreenRectVertex(screen.left, screen.top, texcoords.top * scale_u, left * scale_v), - ScreenRectVertex(screen.right, screen.top, texcoords.bottom * scale_u, left * scale_v), - ScreenRectVertex(screen.left, screen.bottom, texcoords.top * scale_u, right * scale_v), - ScreenRectVertex(screen.right, screen.bottom, texcoords.bottom * scale_u, right * scale_v), + ScreenRectVertex(screen.left, screen.top, texcoords.top * scale_u, + left_start + left * scale_v), + ScreenRectVertex(screen.right, screen.top, texcoords.bottom * scale_u, + left_start + left * scale_v), + ScreenRectVertex(screen.left, screen.bottom, texcoords.top * scale_u, + left_start + right * scale_v), + ScreenRectVertex(screen.right, screen.bottom, texcoords.bottom * scale_u, + left_start + right * scale_v), }; glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), std::data(vertices)); diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index cda333cad..1a32e739d 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -1,6 +1,5 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: 2014 Citra Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -8,10 +7,12 @@ #include <glad/glad.h> #include "common/common_types.h" #include "common/math_util.h" + #include "video_core/renderer_base.h" #include "video_core/renderer_opengl/gl_device.h" #include "video_core/renderer_opengl/gl_rasterizer.h" #include "video_core/renderer_opengl/gl_resource_manager.h" +#include "video_core/renderer_opengl/gl_shader_manager.h" #include "video_core/renderer_opengl/gl_state_tracker.h" namespace Core { @@ -44,7 +45,7 @@ struct TextureInfo { GLsizei height; GLenum gl_format; GLenum gl_type; - Tegra::FramebufferConfig::PixelFormat pixel_format; + Service::android::PixelFormat pixel_format; }; /// Structure used for storing information about the display target for the Switch screen @@ -133,8 +134,10 @@ private: std::vector<u8> gl_framebuffer_data; /// Used for transforming the framebuffer orientation - Tegra::FramebufferConfig::TransformFlags framebuffer_transform_flags{}; + Service::android::BufferTransformFlags framebuffer_transform_flags{}; Common::Rectangle<int> framebuffer_crop_rect; + u32 framebuffer_width; + u32 framebuffer_height; }; } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/util_shaders.cpp b/src/video_core/renderer_opengl/util_shaders.cpp index 897c380b3..404def62e 100644 --- a/src/video_core/renderer_opengl/util_shaders.cpp +++ b/src/video_core/renderer_opengl/util_shaders.cpp @@ -1,6 +1,5 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include <span> #include <string_view> @@ -13,6 +12,7 @@ #include "video_core/host_shaders/astc_decoder_comp.h" #include "video_core/host_shaders/block_linear_unswizzle_2d_comp.h" #include "video_core/host_shaders/block_linear_unswizzle_3d_comp.h" +#include "video_core/host_shaders/opengl_convert_s8d24_comp.h" #include "video_core/host_shaders/opengl_copy_bc4_comp.h" #include "video_core/host_shaders/pitch_unswizzle_comp.h" #include "video_core/renderer_opengl/gl_shader_manager.h" @@ -50,7 +50,8 @@ UtilShaders::UtilShaders(ProgramManager& program_manager_) block_linear_unswizzle_2d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_2D_COMP)), block_linear_unswizzle_3d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_3D_COMP)), pitch_unswizzle_program(MakeProgram(PITCH_UNSWIZZLE_COMP)), - copy_bc4_program(MakeProgram(OPENGL_COPY_BC4_COMP)) { + copy_bc4_program(MakeProgram(OPENGL_COPY_BC4_COMP)), + convert_s8d24_program(MakeProgram(OPENGL_CONVERT_S8D24_COMP)) { const auto swizzle_table = Tegra::Texture::MakeSwizzleTable(); swizzle_table_buffer.Create(); glNamedBufferStorage(swizzle_table_buffer.handle, sizeof(swizzle_table), &swizzle_table, 0); @@ -248,6 +249,26 @@ void UtilShaders::CopyBC4(Image& dst_image, Image& src_image, std::span<const Im program_manager.RestoreGuestCompute(); } +void UtilShaders::ConvertS8D24(Image& dst_image, std::span<const ImageCopy> copies) { + static constexpr GLuint BINDING_DESTINATION = 0; + static constexpr GLuint LOC_SIZE = 0; + + program_manager.BindComputeProgram(convert_s8d24_program.handle); + for (const ImageCopy& copy : copies) { + ASSERT(copy.src_subresource.base_layer == 0); + ASSERT(copy.src_subresource.num_layers == 1); + ASSERT(copy.dst_subresource.base_layer == 0); + ASSERT(copy.dst_subresource.num_layers == 1); + + glUniform3ui(LOC_SIZE, copy.extent.width, copy.extent.height, copy.extent.depth); + glBindImageTexture(BINDING_DESTINATION, dst_image.StorageHandle(), + copy.dst_subresource.base_level, GL_TRUE, 0, GL_READ_WRITE, GL_RGBA8UI); + glDispatchCompute(Common::DivCeil(copy.extent.width, 16u), + Common::DivCeil(copy.extent.height, 8u), copy.extent.depth); + } + program_manager.RestoreGuestCompute(); +} + GLenum StoreFormat(u32 bytes_per_block) { switch (bytes_per_block) { case 1: @@ -261,7 +282,7 @@ GLenum StoreFormat(u32 bytes_per_block) { case 16: return GL_RGBA32UI; } - UNREACHABLE(); + ASSERT(false); return GL_R8UI; } diff --git a/src/video_core/renderer_opengl/util_shaders.h b/src/video_core/renderer_opengl/util_shaders.h index 5de95ea7a..44efb6ecf 100644 --- a/src/video_core/renderer_opengl/util_shaders.h +++ b/src/video_core/renderer_opengl/util_shaders.h @@ -1,6 +1,5 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -39,6 +38,8 @@ public: void CopyBC4(Image& dst_image, Image& src_image, std::span<const VideoCommon::ImageCopy> copies); + void ConvertS8D24(Image& dst_image, std::span<const VideoCommon::ImageCopy> copies); + private: ProgramManager& program_manager; @@ -49,6 +50,7 @@ private: OGLProgram block_linear_unswizzle_3d_program; OGLProgram pitch_unswizzle_program; OGLProgram copy_bc4_program; + OGLProgram convert_s8d24_program; }; GLenum StoreFormat(u32 bytes_per_block); |
