committed by
ameerj
38 changed files with 1427 additions and 705 deletions
-
4src/shader_recompiler/frontend/ir/ir_emitter.cpp
-
1src/shader_recompiler/frontend/ir/ir_emitter.h
-
7src/shader_recompiler/frontend/maxwell/translate/impl/move_special_register.cpp
-
4src/video_core/CMakeLists.txt
-
53src/video_core/buffer_cache/buffer_cache.h
-
37src/video_core/renderer_opengl/gl_buffer_cache.cpp
-
40src/video_core/renderer_opengl/gl_buffer_cache.h
-
178src/video_core/renderer_opengl/gl_compute_program.cpp
-
83src/video_core/renderer_opengl/gl_compute_program.h
-
89src/video_core/renderer_opengl/gl_device.cpp
-
16src/video_core/renderer_opengl/gl_device.h
-
296src/video_core/renderer_opengl/gl_graphics_program.cpp
-
105src/video_core/renderer_opengl/gl_graphics_program.h
-
23src/video_core/renderer_opengl/gl_rasterizer.cpp
-
275src/video_core/renderer_opengl/gl_shader_cache.cpp
-
98src/video_core/renderer_opengl/gl_shader_cache.h
-
146src/video_core/renderer_opengl/gl_shader_manager.cpp
-
73src/video_core/renderer_opengl/gl_shader_manager.h
-
257src/video_core/renderer_opengl/gl_texture_cache.cpp
-
29src/video_core/renderer_opengl/gl_texture_cache.h
-
108src/video_core/renderer_opengl/maxwell_to_gl.h
-
17src/video_core/renderer_opengl/renderer_opengl.cpp
-
5src/video_core/renderer_opengl/renderer_opengl.h
-
13src/video_core/renderer_opengl/util_shaders.cpp
-
17src/video_core/renderer_vulkan/pipeline_helper.h
-
2src/video_core/renderer_vulkan/vk_buffer_cache.h
-
22src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
-
22src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
-
23src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
-
11src/video_core/renderer_vulkan/vk_rasterizer.cpp
-
17src/video_core/shader_cache.cpp
-
23src/video_core/shader_cache.h
-
4src/video_core/shader_environment.cpp
-
16src/video_core/shader_environment.h
-
4src/video_core/texture_cache/formatter.cpp
-
3src/video_core/texture_cache/formatter.h
-
9src/video_core/textures/texture.h
-
2src/video_core/vulkan_common/vulkan_device.cpp
@ -0,0 +1,178 @@ |
|||
// Copyright 2021 yuzu Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include <cstring>
|
|||
|
|||
#include "common/cityhash.h"
|
|||
#include "video_core/renderer_opengl/gl_compute_program.h"
|
|||
#include "video_core/renderer_opengl/gl_shader_manager.h"
|
|||
|
|||
namespace OpenGL { |
|||
|
|||
using Shader::ImageBufferDescriptor; |
|||
using Tegra::Texture::TexturePair; |
|||
using VideoCommon::ImageId; |
|||
|
|||
constexpr u32 MAX_TEXTURES = 64; |
|||
constexpr u32 MAX_IMAGES = 16; |
|||
|
|||
size_t ComputeProgramKey::Hash() const noexcept { |
|||
return static_cast<size_t>( |
|||
Common::CityHash64(reinterpret_cast<const char*>(this), sizeof *this)); |
|||
} |
|||
|
|||
bool ComputeProgramKey::operator==(const ComputeProgramKey& rhs) const noexcept { |
|||
return std::memcmp(this, &rhs, sizeof *this) == 0; |
|||
} |
|||
|
|||
ComputeProgram::ComputeProgram(TextureCache& texture_cache_, BufferCache& buffer_cache_, |
|||
Tegra::MemoryManager& gpu_memory_, |
|||
Tegra::Engines::KeplerCompute& kepler_compute_, |
|||
ProgramManager& program_manager_, OGLProgram program_, |
|||
const Shader::Info& info_) |
|||
: texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, gpu_memory{gpu_memory_}, |
|||
kepler_compute{kepler_compute_}, |
|||
program_manager{program_manager_}, program{std::move(program_)}, info{info_} { |
|||
for (const auto& desc : info.texture_buffer_descriptors) { |
|||
num_texture_buffers += desc.count; |
|||
} |
|||
for (const auto& desc : info.image_buffer_descriptors) { |
|||
num_image_buffers += desc.count; |
|||
} |
|||
u32 num_textures = num_texture_buffers; |
|||
for (const auto& desc : info.texture_descriptors) { |
|||
num_textures += desc.count; |
|||
} |
|||
ASSERT(num_textures <= MAX_TEXTURES); |
|||
|
|||
u32 num_images = num_image_buffers; |
|||
for (const auto& desc : info.image_descriptors) { |
|||
num_images += desc.count; |
|||
} |
|||
ASSERT(num_images <= MAX_IMAGES); |
|||
} |
|||
|
|||
void ComputeProgram::Configure() { |
|||
buffer_cache.SetEnabledComputeUniformBuffers(info.constant_buffer_mask); |
|||
buffer_cache.UnbindComputeStorageBuffers(); |
|||
size_t ssbo_index{}; |
|||
for (const auto& desc : info.storage_buffers_descriptors) { |
|||
ASSERT(desc.count == 1); |
|||
buffer_cache.BindComputeStorageBuffer(ssbo_index, desc.cbuf_index, desc.cbuf_offset, |
|||
desc.is_written); |
|||
++ssbo_index; |
|||
} |
|||
texture_cache.SynchronizeComputeDescriptors(); |
|||
|
|||
std::array<ImageViewId, MAX_TEXTURES + MAX_IMAGES> image_view_ids; |
|||
boost::container::static_vector<u32, MAX_TEXTURES + MAX_IMAGES> image_view_indices; |
|||
std::array<GLuint, MAX_TEXTURES> samplers; |
|||
std::array<GLuint, MAX_TEXTURES> textures; |
|||
std::array<GLuint, MAX_IMAGES> images; |
|||
GLsizei sampler_binding{}; |
|||
GLsizei texture_binding{}; |
|||
GLsizei image_binding{}; |
|||
|
|||
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) { |
|||
ASSERT(((qmd.const_buffer_enable_mask >> desc.cbuf_index) & 1) != 0); |
|||
const u32 index_offset{index << desc.size_shift}; |
|||
const u32 offset{desc.cbuf_offset + index_offset}; |
|||
const GPUVAddr addr{cbufs[desc.cbuf_index].Address() + offset}; |
|||
if constexpr (std::is_same_v<decltype(desc), const Shader::TextureDescriptor&> || |
|||
std::is_same_v<decltype(desc), const Shader::TextureBufferDescriptor&>) { |
|||
if (desc.has_secondary) { |
|||
ASSERT(((qmd.const_buffer_enable_mask >> desc.secondary_cbuf_index) & 1) != 0); |
|||
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)}; |
|||
return TexturePair(lhs_raw | rhs_raw, via_header_index); |
|||
} |
|||
} |
|||
return TexturePair(gpu_memory.Read<u32>(addr), via_header_index); |
|||
}}; |
|||
const auto add_image{[&](const auto& desc) { |
|||
for (u32 index = 0; index < desc.count; ++index) { |
|||
const auto handle{read_handle(desc, index)}; |
|||
image_view_indices.push_back(handle.first); |
|||
} |
|||
}}; |
|||
for (const auto& desc : info.texture_buffer_descriptors) { |
|||
for (u32 index = 0; index < desc.count; ++index) { |
|||
const auto handle{read_handle(desc, index)}; |
|||
image_view_indices.push_back(handle.first); |
|||
samplers[sampler_binding++] = 0; |
|||
} |
|||
} |
|||
std::ranges::for_each(info.image_buffer_descriptors, add_image); |
|||
for (const auto& desc : info.texture_descriptors) { |
|||
for (u32 index = 0; index < desc.count; ++index) { |
|||
const auto handle{read_handle(desc, index)}; |
|||
image_view_indices.push_back(handle.first); |
|||
|
|||
Sampler* const sampler = texture_cache.GetComputeSampler(handle.second); |
|||
samplers[sampler_binding++] = sampler->Handle(); |
|||
} |
|||
} |
|||
std::ranges::for_each(info.image_descriptors, add_image); |
|||
|
|||
const std::span indices_span(image_view_indices.data(), image_view_indices.size()); |
|||
texture_cache.FillComputeImageViews(indices_span, image_view_ids); |
|||
|
|||
buffer_cache.UnbindComputeTextureBuffers(); |
|||
size_t texbuf_index{}; |
|||
const auto add_buffer{[&](const auto& desc) { |
|||
constexpr bool is_image = std::is_same_v<decltype(desc), const ImageBufferDescriptor&>; |
|||
for (u32 i = 0; i < desc.count; ++i) { |
|||
bool is_written{false}; |
|||
if constexpr (is_image) { |
|||
is_written = desc.is_written; |
|||
} |
|||
ImageView& image_view{texture_cache.GetImageView(image_view_ids[texbuf_index])}; |
|||
buffer_cache.BindComputeTextureBuffer(texbuf_index, image_view.GpuAddr(), |
|||
image_view.BufferSize(), image_view.format, |
|||
is_written, is_image); |
|||
++texbuf_index; |
|||
} |
|||
}}; |
|||
std::ranges::for_each(info.texture_buffer_descriptors, add_buffer); |
|||
std::ranges::for_each(info.image_buffer_descriptors, add_buffer); |
|||
|
|||
buffer_cache.UpdateComputeBuffers(); |
|||
|
|||
buffer_cache.runtime.SetImagePointers(textures.data(), images.data()); |
|||
buffer_cache.BindHostComputeBuffers(); |
|||
|
|||
const ImageId* views_it{image_view_ids.data() + num_texture_buffers + num_image_buffers}; |
|||
texture_binding += num_texture_buffers; |
|||
image_binding += num_image_buffers; |
|||
|
|||
for (const auto& desc : info.texture_descriptors) { |
|||
for (u32 index = 0; index < desc.count; ++index) { |
|||
ImageView& image_view{texture_cache.GetImageView(*(views_it++))}; |
|||
textures[texture_binding++] = image_view.Handle(desc.type); |
|||
} |
|||
} |
|||
for (const auto& desc : info.image_descriptors) { |
|||
for (u32 index = 0; index < desc.count; ++index) { |
|||
ImageView& image_view{texture_cache.GetImageView(*(views_it++))}; |
|||
images[image_binding++] = image_view.Handle(desc.type); |
|||
} |
|||
} |
|||
if (texture_binding != 0) { |
|||
ASSERT(texture_binding == sampler_binding); |
|||
glBindTextures(0, texture_binding, textures.data()); |
|||
glBindSamplers(0, sampler_binding, samplers.data()); |
|||
} |
|||
if (image_binding != 0) { |
|||
glBindImageTextures(0, image_binding, images.data()); |
|||
} |
|||
program_manager.BindProgram(program.handle); |
|||
} |
|||
|
|||
} // namespace OpenGL
|
|||
@ -0,0 +1,83 @@ |
|||
// Copyright 2021 yuzu Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include <array> |
|||
#include <type_traits> |
|||
#include <utility> |
|||
|
|||
#include "common/common_types.h" |
|||
#include "shader_recompiler/shader_info.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" |
|||
|
|||
namespace Tegra { |
|||
class MemoryManager; |
|||
} |
|||
|
|||
namespace Tegra::Engines { |
|||
class KeplerCompute; |
|||
} |
|||
|
|||
namespace Shader { |
|||
struct Info; |
|||
} |
|||
|
|||
namespace OpenGL { |
|||
|
|||
class ProgramManager; |
|||
|
|||
struct ComputeProgramKey { |
|||
u64 unique_hash; |
|||
u32 shared_memory_size; |
|||
std::array<u32, 3> workgroup_size; |
|||
|
|||
size_t Hash() const noexcept; |
|||
|
|||
bool operator==(const ComputeProgramKey&) const noexcept; |
|||
|
|||
bool operator!=(const ComputeProgramKey& rhs) const noexcept { |
|||
return !operator==(rhs); |
|||
} |
|||
}; |
|||
static_assert(std::has_unique_object_representations_v<ComputeProgramKey>); |
|||
static_assert(std::is_trivially_copyable_v<ComputeProgramKey>); |
|||
static_assert(std::is_trivially_constructible_v<ComputeProgramKey>); |
|||
|
|||
class ComputeProgram { |
|||
public: |
|||
explicit ComputeProgram(TextureCache& texture_cache_, BufferCache& buffer_cache_, |
|||
Tegra::MemoryManager& gpu_memory_, |
|||
Tegra::Engines::KeplerCompute& kepler_compute_, |
|||
ProgramManager& program_manager_, OGLProgram program_, |
|||
const Shader::Info& info_); |
|||
|
|||
void Configure(); |
|||
|
|||
private: |
|||
TextureCache& texture_cache; |
|||
BufferCache& buffer_cache; |
|||
Tegra::MemoryManager& gpu_memory; |
|||
Tegra::Engines::KeplerCompute& kepler_compute; |
|||
ProgramManager& program_manager; |
|||
|
|||
OGLProgram program; |
|||
Shader::Info info; |
|||
|
|||
u32 num_texture_buffers{}; |
|||
u32 num_image_buffers{}; |
|||
}; |
|||
|
|||
} // namespace OpenGL |
|||
|
|||
namespace std { |
|||
template <> |
|||
struct hash<OpenGL::ComputeProgramKey> { |
|||
size_t operator()(const OpenGL::ComputeProgramKey& k) const noexcept { |
|||
return k.Hash(); |
|||
} |
|||
}; |
|||
} // namespace std |
|||
@ -0,0 +1,296 @@ |
|||
// Copyright 2021 yuzu Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include <cstring>
|
|||
|
|||
#include "common/cityhash.h"
|
|||
#include "shader_recompiler/shader_info.h"
|
|||
#include "video_core/renderer_opengl/gl_graphics_program.h"
|
|||
#include "video_core/renderer_opengl/gl_shader_manager.h"
|
|||
#include "video_core/renderer_opengl/gl_state_tracker.h"
|
|||
#include "video_core/texture_cache/texture_cache.h"
|
|||
|
|||
namespace OpenGL { |
|||
|
|||
using Shader::ImageBufferDescriptor; |
|||
using Tegra::Texture::TexturePair; |
|||
using VideoCommon::ImageId; |
|||
|
|||
constexpr u32 MAX_TEXTURES = 64; |
|||
constexpr u32 MAX_IMAGES = 8; |
|||
|
|||
size_t GraphicsProgramKey::Hash() const noexcept { |
|||
return static_cast<size_t>(Common::CityHash64(reinterpret_cast<const char*>(this), Size())); |
|||
} |
|||
|
|||
bool GraphicsProgramKey::operator==(const GraphicsProgramKey& rhs) const noexcept { |
|||
return std::memcmp(this, &rhs, Size()) == 0; |
|||
} |
|||
|
|||
GraphicsProgram::GraphicsProgram(TextureCache& texture_cache_, BufferCache& buffer_cache_, |
|||
Tegra::MemoryManager& gpu_memory_, |
|||
Tegra::Engines::Maxwell3D& maxwell3d_, |
|||
ProgramManager& program_manager_, StateTracker& state_tracker_, |
|||
OGLProgram program_, |
|||
const std::array<const Shader::Info*, 5>& infos) |
|||
: texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, |
|||
gpu_memory{gpu_memory_}, maxwell3d{maxwell3d_}, program_manager{program_manager_}, |
|||
state_tracker{state_tracker_}, program{std::move(program_)} { |
|||
std::ranges::transform(infos, stage_infos.begin(), |
|||
[](const Shader::Info* info) { return info ? *info : Shader::Info{}; }); |
|||
|
|||
u32 num_textures{}; |
|||
u32 num_images{}; |
|||
for (size_t stage = 0; stage < base_uniform_bindings.size() - 1; ++stage) { |
|||
const auto& info{stage_infos[stage]}; |
|||
base_uniform_bindings[stage + 1] = base_uniform_bindings[stage]; |
|||
base_storage_bindings[stage + 1] = base_storage_bindings[stage]; |
|||
for (const auto& desc : info.constant_buffer_descriptors) { |
|||
base_uniform_bindings[stage + 1] += desc.count; |
|||
} |
|||
for (const auto& desc : info.storage_buffers_descriptors) { |
|||
base_storage_bindings[stage + 1] += desc.count; |
|||
} |
|||
for (const auto& desc : info.texture_buffer_descriptors) { |
|||
num_texture_buffers[stage] += desc.count; |
|||
num_textures += desc.count; |
|||
} |
|||
for (const auto& desc : info.image_buffer_descriptors) { |
|||
num_image_buffers[stage] += desc.count; |
|||
num_images += desc.count; |
|||
} |
|||
for (const auto& desc : info.texture_descriptors) { |
|||
num_textures += desc.count; |
|||
} |
|||
for (const auto& desc : info.image_descriptors) { |
|||
num_images += desc.count; |
|||
} |
|||
} |
|||
ASSERT(num_textures <= MAX_TEXTURES); |
|||
ASSERT(num_images <= MAX_IMAGES); |
|||
} |
|||
|
|||
struct Spec { |
|||
static constexpr std::array<bool, 5> enabled_stages{true, true, true, true, true}; |
|||
static constexpr bool has_storage_buffers = true; |
|||
static constexpr bool has_texture_buffers = true; |
|||
static constexpr bool has_image_buffers = true; |
|||
static constexpr bool has_images = true; |
|||
}; |
|||
|
|||
void GraphicsProgram::Configure(bool is_indexed) { |
|||
std::array<ImageId, MAX_TEXTURES + MAX_IMAGES> image_view_ids; |
|||
std::array<u32, MAX_TEXTURES + MAX_IMAGES> image_view_indices; |
|||
std::array<GLuint, MAX_TEXTURES> samplers; |
|||
size_t image_view_index{}; |
|||
GLsizei sampler_binding{}; |
|||
|
|||
texture_cache.SynchronizeGraphicsDescriptors(); |
|||
|
|||
buffer_cache.runtime.SetBaseUniformBindings(base_uniform_bindings); |
|||
buffer_cache.runtime.SetBaseStorageBindings(base_storage_bindings); |
|||
|
|||
const auto& regs{maxwell3d.regs}; |
|||
const bool via_header_index{regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex}; |
|||
const auto config_stage{[&](size_t stage) { |
|||
const Shader::Info& info{stage_infos[stage]}; |
|||
buffer_cache.SetEnabledUniformBuffers(stage, info.constant_buffer_mask); |
|||
buffer_cache.UnbindGraphicsStorageBuffers(stage); |
|||
if constexpr (Spec::has_storage_buffers) { |
|||
size_t ssbo_index{}; |
|||
for (const auto& desc : info.storage_buffers_descriptors) { |
|||
ASSERT(desc.count == 1); |
|||
buffer_cache.BindGraphicsStorageBuffer(stage, ssbo_index, desc.cbuf_index, |
|||
desc.cbuf_offset, desc.is_written); |
|||
++ssbo_index; |
|||
} |
|||
} |
|||
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}; |
|||
const u32 offset{desc.cbuf_offset + index_offset}; |
|||
const GPUVAddr addr{cbufs[desc.cbuf_index].address + offset}; |
|||
if constexpr (std::is_same_v<decltype(desc), const Shader::TextureDescriptor&> || |
|||
std::is_same_v<decltype(desc), const Shader::TextureBufferDescriptor&>) { |
|||
if (desc.has_secondary) { |
|||
ASSERT(cbufs[desc.secondary_cbuf_index].enabled); |
|||
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 raw{lhs_raw | rhs_raw}; |
|||
return TexturePair(raw, via_header_index); |
|||
} |
|||
} |
|||
return TexturePair(gpu_memory.Read<u32>(addr), via_header_index); |
|||
}}; |
|||
const auto add_image{[&](const auto& desc) { |
|||
for (u32 index = 0; index < desc.count; ++index) { |
|||
const auto handle{read_handle(desc, index)}; |
|||
image_view_indices[image_view_index++] = handle.first; |
|||
} |
|||
}}; |
|||
if constexpr (Spec::has_texture_buffers) { |
|||
for (const auto& desc : info.texture_buffer_descriptors) { |
|||
for (u32 index = 0; index < desc.count; ++index) { |
|||
const auto handle{read_handle(desc, index)}; |
|||
image_view_indices[image_view_index++] = handle.first; |
|||
samplers[sampler_binding++] = 0; |
|||
} |
|||
} |
|||
} |
|||
if constexpr (Spec::has_image_buffers) { |
|||
for (const auto& desc : info.image_buffer_descriptors) { |
|||
add_image(desc); |
|||
} |
|||
} |
|||
for (const auto& desc : info.texture_descriptors) { |
|||
for (u32 index = 0; index < desc.count; ++index) { |
|||
const auto handle{read_handle(desc, index)}; |
|||
image_view_indices[image_view_index++] = handle.first; |
|||
|
|||
Sampler* const sampler{texture_cache.GetGraphicsSampler(handle.second)}; |
|||
samplers[sampler_binding++] = sampler->Handle(); |
|||
} |
|||
} |
|||
if constexpr (Spec::has_images) { |
|||
for (const auto& desc : info.image_descriptors) { |
|||
add_image(desc); |
|||
} |
|||
} |
|||
}}; |
|||
if constexpr (Spec::enabled_stages[0]) { |
|||
config_stage(0); |
|||
} |
|||
if constexpr (Spec::enabled_stages[1]) { |
|||
config_stage(1); |
|||
} |
|||
if constexpr (Spec::enabled_stages[2]) { |
|||
config_stage(2); |
|||
} |
|||
if constexpr (Spec::enabled_stages[3]) { |
|||
config_stage(3); |
|||
} |
|||
if constexpr (Spec::enabled_stages[4]) { |
|||
config_stage(4); |
|||
} |
|||
const std::span indices_span(image_view_indices.data(), image_view_index); |
|||
texture_cache.FillGraphicsImageViews(indices_span, image_view_ids); |
|||
|
|||
ImageId* texture_buffer_index{image_view_ids.data()}; |
|||
const auto bind_stage_info{[&](size_t stage) { |
|||
size_t index{}; |
|||
const auto add_buffer{[&](const auto& desc) { |
|||
constexpr bool is_image = std::is_same_v<decltype(desc), const ImageBufferDescriptor&>; |
|||
for (u32 i = 0; i < desc.count; ++i) { |
|||
bool is_written{false}; |
|||
if constexpr (is_image) { |
|||
is_written = desc.is_written; |
|||
} |
|||
ImageView& image_view{texture_cache.GetImageView(*texture_buffer_index)}; |
|||
buffer_cache.BindGraphicsTextureBuffer(stage, index, image_view.GpuAddr(), |
|||
image_view.BufferSize(), image_view.format, |
|||
is_written, is_image); |
|||
++index; |
|||
++texture_buffer_index; |
|||
} |
|||
}}; |
|||
const Shader::Info& info{stage_infos[stage]}; |
|||
buffer_cache.UnbindGraphicsTextureBuffers(stage); |
|||
|
|||
if constexpr (Spec::has_texture_buffers) { |
|||
for (const auto& desc : info.texture_buffer_descriptors) { |
|||
add_buffer(desc); |
|||
} |
|||
} |
|||
if constexpr (Spec::has_image_buffers) { |
|||
for (const auto& desc : info.image_buffer_descriptors) { |
|||
add_buffer(desc); |
|||
} |
|||
} |
|||
for (const auto& desc : info.texture_descriptors) { |
|||
texture_buffer_index += desc.count; |
|||
} |
|||
if constexpr (Spec::has_images) { |
|||
for (const auto& desc : info.image_descriptors) { |
|||
texture_buffer_index += desc.count; |
|||
} |
|||
} |
|||
}}; |
|||
if constexpr (Spec::enabled_stages[0]) { |
|||
bind_stage_info(0); |
|||
} |
|||
if constexpr (Spec::enabled_stages[1]) { |
|||
bind_stage_info(1); |
|||
} |
|||
if constexpr (Spec::enabled_stages[2]) { |
|||
bind_stage_info(2); |
|||
} |
|||
if constexpr (Spec::enabled_stages[3]) { |
|||
bind_stage_info(3); |
|||
} |
|||
if constexpr (Spec::enabled_stages[4]) { |
|||
bind_stage_info(4); |
|||
} |
|||
buffer_cache.UpdateGraphicsBuffers(is_indexed); |
|||
buffer_cache.BindHostGeometryBuffers(is_indexed); |
|||
|
|||
const ImageId* views_it{image_view_ids.data()}; |
|||
GLsizei texture_binding = 0; |
|||
GLsizei image_binding = 0; |
|||
std::array<GLuint, MAX_TEXTURES> textures; |
|||
std::array<GLuint, MAX_IMAGES> images; |
|||
const auto prepare_stage{[&](size_t stage) { |
|||
buffer_cache.runtime.SetImagePointers(&textures[texture_binding], &images[image_binding]); |
|||
buffer_cache.BindHostStageBuffers(stage); |
|||
|
|||
texture_binding += num_texture_buffers[stage]; |
|||
image_binding += num_image_buffers[stage]; |
|||
|
|||
const auto& info{stage_infos[stage]}; |
|||
for (const auto& desc : info.texture_descriptors) { |
|||
for (u32 index = 0; index < desc.count; ++index) { |
|||
ImageView& image_view{texture_cache.GetImageView(*(views_it++))}; |
|||
textures[texture_binding++] = image_view.Handle(desc.type); |
|||
} |
|||
} |
|||
for (const auto& desc : info.image_descriptors) { |
|||
for (u32 index = 0; index < desc.count; ++index) { |
|||
ImageView& image_view{texture_cache.GetImageView(*(views_it++))}; |
|||
images[image_binding++] = image_view.Handle(desc.type); |
|||
} |
|||
} |
|||
}}; |
|||
if constexpr (Spec::enabled_stages[0]) { |
|||
prepare_stage(0); |
|||
} |
|||
if constexpr (Spec::enabled_stages[1]) { |
|||
prepare_stage(1); |
|||
} |
|||
if constexpr (Spec::enabled_stages[2]) { |
|||
prepare_stage(2); |
|||
} |
|||
if constexpr (Spec::enabled_stages[3]) { |
|||
prepare_stage(3); |
|||
} |
|||
if constexpr (Spec::enabled_stages[4]) { |
|||
prepare_stage(4); |
|||
} |
|||
if (texture_binding != 0) { |
|||
ASSERT(texture_binding == sampler_binding); |
|||
glBindTextures(0, texture_binding, textures.data()); |
|||
glBindSamplers(0, sampler_binding, samplers.data()); |
|||
} |
|||
if (image_binding != 0) { |
|||
glBindImageTextures(0, image_binding, images.data()); |
|||
} |
|||
texture_cache.UpdateRenderTargets(false); |
|||
|
|||
state_tracker.BindFramebuffer(texture_cache.GetFramebuffer()->Handle()); |
|||
program_manager.BindProgram(program.handle); |
|||
} |
|||
|
|||
} // namespace OpenGL
|
|||
@ -0,0 +1,105 @@ |
|||
// Copyright 2021 yuzu Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include <array> |
|||
#include <type_traits> |
|||
#include <utility> |
|||
|
|||
#include "common/bit_field.h" |
|||
#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" |
|||
|
|||
namespace OpenGL { |
|||
|
|||
class ProgramManager; |
|||
|
|||
using Maxwell = Tegra::Engines::Maxwell3D::Regs; |
|||
|
|||
struct GraphicsProgramKey { |
|||
struct TransformFeedbackState { |
|||
struct Layout { |
|||
u32 stream; |
|||
u32 varying_count; |
|||
u32 stride; |
|||
}; |
|||
std::array<Layout, Maxwell::NumTransformFeedbackBuffers> layouts; |
|||
std::array<std::array<u8, 128>, Maxwell::NumTransformFeedbackBuffers> varyings; |
|||
}; |
|||
|
|||
std::array<u64, 6> unique_hashes; |
|||
union { |
|||
u32 raw; |
|||
BitField<0, 1, u32> xfb_enabled; |
|||
BitField<1, 1, u32> early_z; |
|||
BitField<2, 4, Maxwell::PrimitiveTopology> gs_input_topology; |
|||
BitField<6, 2, Maxwell::TessellationPrimitive> tessellation_primitive; |
|||
BitField<8, 2, Maxwell::TessellationSpacing> tessellation_spacing; |
|||
BitField<10, 1, u32> tessellation_clockwise; |
|||
}; |
|||
std::array<u32, 3> padding; |
|||
TransformFeedbackState xfb_state; |
|||
|
|||
size_t Hash() const noexcept; |
|||
|
|||
bool operator==(const GraphicsProgramKey&) const noexcept; |
|||
|
|||
bool operator!=(const GraphicsProgramKey& rhs) const noexcept { |
|||
return !operator==(rhs); |
|||
} |
|||
|
|||
[[nodiscard]] size_t Size() const noexcept { |
|||
if (xfb_enabled != 0) { |
|||
return sizeof(GraphicsProgramKey); |
|||
} else { |
|||
return offsetof(GraphicsProgramKey, padding); |
|||
} |
|||
} |
|||
}; |
|||
static_assert(std::has_unique_object_representations_v<GraphicsProgramKey>); |
|||
static_assert(std::is_trivially_copyable_v<GraphicsProgramKey>); |
|||
static_assert(std::is_trivially_constructible_v<GraphicsProgramKey>); |
|||
|
|||
class GraphicsProgram { |
|||
public: |
|||
explicit GraphicsProgram(TextureCache& texture_cache_, BufferCache& buffer_cache_, |
|||
Tegra::MemoryManager& gpu_memory_, |
|||
Tegra::Engines::Maxwell3D& maxwell3d_, |
|||
ProgramManager& program_manager_, StateTracker& state_tracker_, |
|||
OGLProgram program_, const std::array<const Shader::Info*, 5>& infos); |
|||
|
|||
void Configure(bool is_indexed); |
|||
|
|||
private: |
|||
TextureCache& texture_cache; |
|||
BufferCache& buffer_cache; |
|||
Tegra::MemoryManager& gpu_memory; |
|||
Tegra::Engines::Maxwell3D& maxwell3d; |
|||
ProgramManager& program_manager; |
|||
StateTracker& state_tracker; |
|||
|
|||
OGLProgram program; |
|||
std::array<Shader::Info, 5> stage_infos{}; |
|||
std::array<u32, 5> base_uniform_bindings{}; |
|||
std::array<u32, 5> base_storage_bindings{}; |
|||
std::array<u32, 5> num_texture_buffers{}; |
|||
std::array<u32, 5> num_image_buffers{}; |
|||
}; |
|||
|
|||
} // namespace OpenGL |
|||
|
|||
namespace std { |
|||
template <> |
|||
struct hash<OpenGL::GraphicsProgramKey> { |
|||
size_t operator()(const OpenGL::GraphicsProgramKey& k) const noexcept { |
|||
return k.Hash(); |
|||
} |
|||
}; |
|||
} // namespace std |
|||
@ -1,149 +1,3 @@ |
|||
// Copyright 2018 yuzu Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include <glad/glad.h>
|
|||
|
|||
#include "common/common_types.h"
|
|||
#include "video_core/engines/maxwell_3d.h"
|
|||
#include "video_core/renderer_opengl/gl_device.h"
|
|||
#include "video_core/renderer_opengl/gl_shader_manager.h"
|
|||
|
|||
namespace OpenGL { |
|||
|
|||
namespace { |
|||
|
|||
void BindProgram(GLenum stage, GLuint current, GLuint old, bool& enabled) { |
|||
if (current == old) { |
|||
return; |
|||
} |
|||
if (current == 0) { |
|||
if (enabled) { |
|||
enabled = false; |
|||
glDisable(stage); |
|||
} |
|||
return; |
|||
} |
|||
if (!enabled) { |
|||
enabled = true; |
|||
glEnable(stage); |
|||
} |
|||
glBindProgramARB(stage, current); |
|||
} |
|||
|
|||
} // Anonymous namespace
|
|||
|
|||
ProgramManager::ProgramManager(const Device& device) |
|||
: use_assembly_programs{device.UseAssemblyShaders()} { |
|||
if (use_assembly_programs) { |
|||
glEnable(GL_COMPUTE_PROGRAM_NV); |
|||
} else { |
|||
graphics_pipeline.Create(); |
|||
glBindProgramPipeline(graphics_pipeline.handle); |
|||
} |
|||
} |
|||
|
|||
ProgramManager::~ProgramManager() = default; |
|||
|
|||
void ProgramManager::BindCompute(GLuint program) { |
|||
if (use_assembly_programs) { |
|||
glBindProgramARB(GL_COMPUTE_PROGRAM_NV, program); |
|||
} else { |
|||
is_graphics_bound = false; |
|||
glUseProgram(program); |
|||
} |
|||
} |
|||
|
|||
void ProgramManager::BindGraphicsPipeline() { |
|||
if (!use_assembly_programs) { |
|||
UpdateSourcePrograms(); |
|||
} |
|||
} |
|||
|
|||
void ProgramManager::BindHostPipeline(GLuint pipeline) { |
|||
if (use_assembly_programs) { |
|||
if (geometry_enabled) { |
|||
geometry_enabled = false; |
|||
old_state.geometry = 0; |
|||
glDisable(GL_GEOMETRY_PROGRAM_NV); |
|||
} |
|||
} else { |
|||
if (!is_graphics_bound) { |
|||
glUseProgram(0); |
|||
} |
|||
} |
|||
glBindProgramPipeline(pipeline); |
|||
} |
|||
|
|||
void ProgramManager::RestoreGuestPipeline() { |
|||
if (use_assembly_programs) { |
|||
glBindProgramPipeline(0); |
|||
} else { |
|||
glBindProgramPipeline(graphics_pipeline.handle); |
|||
} |
|||
} |
|||
|
|||
void ProgramManager::BindHostCompute(GLuint program) { |
|||
if (use_assembly_programs) { |
|||
glDisable(GL_COMPUTE_PROGRAM_NV); |
|||
} |
|||
glUseProgram(program); |
|||
is_graphics_bound = false; |
|||
} |
|||
|
|||
void ProgramManager::RestoreGuestCompute() { |
|||
if (use_assembly_programs) { |
|||
glEnable(GL_COMPUTE_PROGRAM_NV); |
|||
glUseProgram(0); |
|||
} |
|||
} |
|||
|
|||
void ProgramManager::UseVertexShader(GLuint program) { |
|||
if (use_assembly_programs) { |
|||
BindProgram(GL_VERTEX_PROGRAM_NV, program, current_state.vertex, vertex_enabled); |
|||
} |
|||
current_state.vertex = program; |
|||
} |
|||
|
|||
void ProgramManager::UseGeometryShader(GLuint program) { |
|||
if (use_assembly_programs) { |
|||
BindProgram(GL_GEOMETRY_PROGRAM_NV, program, current_state.vertex, geometry_enabled); |
|||
} |
|||
current_state.geometry = program; |
|||
} |
|||
|
|||
void ProgramManager::UseFragmentShader(GLuint program) { |
|||
if (use_assembly_programs) { |
|||
BindProgram(GL_FRAGMENT_PROGRAM_NV, program, current_state.vertex, fragment_enabled); |
|||
} |
|||
current_state.fragment = program; |
|||
} |
|||
|
|||
void ProgramManager::UpdateSourcePrograms() { |
|||
if (!is_graphics_bound) { |
|||
is_graphics_bound = true; |
|||
glUseProgram(0); |
|||
} |
|||
|
|||
const GLuint handle = graphics_pipeline.handle; |
|||
const auto update_state = [handle](GLenum stage, GLuint current, GLuint old) { |
|||
if (current == old) { |
|||
return; |
|||
} |
|||
glUseProgramStages(handle, stage, current); |
|||
}; |
|||
update_state(GL_VERTEX_SHADER_BIT, current_state.vertex, old_state.vertex); |
|||
update_state(GL_GEOMETRY_SHADER_BIT, current_state.geometry, old_state.geometry); |
|||
update_state(GL_FRAGMENT_SHADER_BIT, current_state.fragment, old_state.fragment); |
|||
|
|||
old_state = current_state; |
|||
} |
|||
|
|||
void MaxwellUniformData::SetFromRegs(const Tegra::Engines::Maxwell3D& maxwell) { |
|||
const auto& regs = maxwell.regs; |
|||
|
|||
// Y_NEGATE controls what value S2R returns for the Y_DIRECTION system value.
|
|||
y_direction = regs.screen_y_control.y_negate == 0 ? 1.0f : -1.0f; |
|||
} |
|||
|
|||
} // namespace OpenGL
|
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue