// Copyright 2018 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include #include #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" #include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/gl_stream_buffer.h" #include "video_core/vulkan_common/vulkan_device.h" #include "video_core/vulkan_common/vulkan_memory_allocator.h" namespace Vulkan { class Device; class MemoryAllocator; } // namespace Vulkan namespace OpenGL { class BufferCacheRuntime; class Buffer : public VideoCommon::BufferBase { public: explicit Buffer(BufferCacheRuntime&, VideoCore::RasterizerInterface& rasterizer, VAddr cpu_addr, u64 size_bytes); explicit Buffer(BufferCacheRuntime&, VideoCommon::NullBufferParams); void ImmediateUpload(size_t offset, std::span data) noexcept; void ImmediateDownload(size_t offset, std::span data) noexcept; void MakeResident(GLenum access) noexcept; [[nodiscard]] GLuint SubBuffer(u32 offset); [[nodiscard]] GLuint64EXT HostGpuAddr() const noexcept { return address; } [[nodiscard]] GLuint Handle() const noexcept { return buffer.handle; } private: void CreateMemoryObjects(BufferCacheRuntime& runtime); GLuint64EXT address = 0; Vulkan::MemoryCommit memory_commit; OGLBuffer buffer; GLenum current_residency_access = GL_NONE; std::vector> subs; }; class BufferCacheRuntime { friend Buffer; public: static constexpr u8 INVALID_BINDING = std::numeric_limits::max(); explicit BufferCacheRuntime(const Device& device_, const Vulkan::Device* vulkan_device_, Vulkan::MemoryAllocator* vulkan_memory_allocator_); void CopyBuffer(Buffer& dst_buffer, Buffer& src_buffer, std::span copies); void BindIndexBuffer(Buffer& buffer, u32 offset, u32 size); void BindVertexBuffer(u32 index, Buffer& buffer, u32 offset, u32 size, u32 stride); void BindUniformBuffer(size_t stage, u32 binding_index, Buffer& buffer, u32 offset, u32 size); void BindComputeUniformBuffer(u32 binding_index, Buffer& buffer, u32 offset, u32 size); void BindStorageBuffer(size_t stage, u32 binding_index, Buffer& buffer, u32 offset, u32 size, bool is_written); void BindComputeStorageBuffer(u32 binding_index, Buffer& buffer, u32 offset, u32 size, bool is_written); void BindTransformFeedbackBuffer(u32 index, Buffer& buffer, u32 offset, u32 size); void BindFastUniformBuffer(size_t stage, u32 binding_index, u32 size) { if (use_assembly_shaders) { const GLuint handle = fast_uniforms[stage][binding_index].handle; const GLsizeiptr gl_size = static_cast(size); glBindBufferRangeNV(PABO_LUT[stage], binding_index, handle, 0, gl_size); } else { const GLuint base_binding = device.GetBaseBindings(stage).uniform_buffer; const GLuint binding = base_binding + binding_index; glBindBufferRange(GL_UNIFORM_BUFFER, binding, fast_uniforms[stage][binding_index].handle, 0, static_cast(size)); } } void PushFastUniformBuffer(size_t stage, u32 binding_index, std::span data) { if (use_assembly_shaders) { glProgramBufferParametersIuivNV( PABO_LUT[stage], binding_index, 0, static_cast(data.size_bytes() / sizeof(GLuint)), reinterpret_cast(data.data())); } else { glNamedBufferSubData(fast_uniforms[stage][binding_index].handle, 0, static_cast(data.size_bytes()), data.data()); } } std::span BindMappedUniformBuffer(size_t stage, u32 binding_index, u32 size) noexcept { const auto [mapped_span, offset] = stream_buffer->Request(static_cast(size)); const GLuint base_binding = device.GetBaseBindings(stage).uniform_buffer; const GLuint binding = base_binding + binding_index; glBindBufferRange(GL_UNIFORM_BUFFER, binding, stream_buffer->Handle(), static_cast(offset), static_cast(size)); return mapped_span; } [[nodiscard]] const GLvoid* IndexOffset() const noexcept { return reinterpret_cast(static_cast(index_buffer_offset)); } [[nodiscard]] bool HasFastBufferSubData() const noexcept { return device.HasFastBufferSubData(); } private: static constexpr std::array PABO_LUT{ GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV, GL_TESS_CONTROL_PROGRAM_PARAMETER_BUFFER_NV, GL_TESS_EVALUATION_PROGRAM_PARAMETER_BUFFER_NV, GL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV, GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV, }; const Device& device; const Vulkan::Device* vulkan_device; Vulkan::MemoryAllocator* vulkan_memory_allocator; std::optional stream_buffer; u32 max_attributes = 0; bool use_assembly_shaders = false; bool has_unified_vertex_buffers = false; std::array, VideoCommon::NUM_STAGES> fast_uniforms; u32 index_buffer_offset = 0; }; struct BufferCacheParams { using Runtime = OpenGL::BufferCacheRuntime; using Buffer = OpenGL::Buffer; static constexpr bool IS_OPENGL = true; static constexpr bool HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS = true; static constexpr bool HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT = true; static constexpr bool NEEDS_BIND_UNIFORM_INDEX = true; static constexpr bool NEEDS_BIND_STORAGE_INDEX = true; static constexpr bool USE_MEMORY_MAPS = false; }; using BufferCache = VideoCommon::BufferCache; } // namespace OpenGL