early-access version 2156
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
#include <algorithm>
|
||||
#include <span>
|
||||
|
||||
#include "shader_recompiler/backend/glasm/emit_glasm.h"
|
||||
#include "video_core/buffer_cache/buffer_cache.h"
|
||||
#include "video_core/renderer_opengl/gl_buffer_cache.h"
|
||||
#include "video_core/renderer_opengl/gl_device.h"
|
||||
@@ -229,8 +230,10 @@ void BufferCacheRuntime::BindStorageBuffer(size_t stage, u32 binding_index, Buff
|
||||
.padding = 0,
|
||||
};
|
||||
buffer.MakeResident(is_written ? GL_READ_WRITE : GL_READ_ONLY);
|
||||
glProgramLocalParametersI4uivNV(PROGRAM_LUT[stage], binding_index, 1,
|
||||
reinterpret_cast<const GLuint*>(&ssbo));
|
||||
glProgramLocalParametersI4uivNV(
|
||||
PROGRAM_LUT[stage],
|
||||
Shader::Backend::GLASM::PROGRAM_LOCAL_PARAMETER_STORAGE_BUFFER_BASE + binding_index, 1,
|
||||
reinterpret_cast<const GLuint*>(&ssbo));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,8 +253,10 @@ void BufferCacheRuntime::BindComputeStorageBuffer(u32 binding_index, Buffer& buf
|
||||
.padding = 0,
|
||||
};
|
||||
buffer.MakeResident(is_written ? GL_READ_WRITE : GL_READ_ONLY);
|
||||
glProgramLocalParametersI4uivNV(GL_COMPUTE_PROGRAM_NV, binding_index, 1,
|
||||
reinterpret_cast<const GLuint*>(&ssbo));
|
||||
glProgramLocalParametersI4uivNV(
|
||||
GL_COMPUTE_PROGRAM_NV,
|
||||
Shader::Backend::GLASM::PROGRAM_LOCAL_PARAMETER_STORAGE_BUFFER_BASE + binding_index, 1,
|
||||
reinterpret_cast<const GLuint*>(&ssbo));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -19,15 +19,6 @@ using VideoCommon::ImageId;
|
||||
constexpr u32 MAX_TEXTURES = 64;
|
||||
constexpr u32 MAX_IMAGES = 16;
|
||||
|
||||
template <typename Range>
|
||||
u32 AccumulateCount(const Range& range) {
|
||||
u32 num{};
|
||||
for (const auto& desc : range) {
|
||||
num += desc.count;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
size_t ComputePipelineKey::Hash() const noexcept {
|
||||
return static_cast<size_t>(
|
||||
Common::CityHash64(reinterpret_cast<const char*>(this), sizeof *this));
|
||||
@@ -58,17 +49,17 @@ ComputePipeline::ComputePipeline(const Device& device, TextureCache& texture_cac
|
||||
std::copy_n(info.constant_buffer_used_sizes.begin(), uniform_buffer_sizes.size(),
|
||||
uniform_buffer_sizes.begin());
|
||||
|
||||
num_texture_buffers = AccumulateCount(info.texture_buffer_descriptors);
|
||||
num_image_buffers = AccumulateCount(info.image_buffer_descriptors);
|
||||
num_texture_buffers = Shader::NumDescriptors(info.texture_buffer_descriptors);
|
||||
num_image_buffers = Shader::NumDescriptors(info.image_buffer_descriptors);
|
||||
|
||||
const u32 num_textures{num_texture_buffers + AccumulateCount(info.texture_descriptors)};
|
||||
const u32 num_textures{num_texture_buffers + Shader::NumDescriptors(info.texture_descriptors)};
|
||||
ASSERT(num_textures <= MAX_TEXTURES);
|
||||
|
||||
const u32 num_images{num_image_buffers + AccumulateCount(info.image_descriptors)};
|
||||
const u32 num_images{num_image_buffers + Shader::NumDescriptors(info.image_descriptors)};
|
||||
ASSERT(num_images <= MAX_IMAGES);
|
||||
|
||||
const bool is_glasm{assembly_program.handle != 0};
|
||||
const u32 num_storage_buffers{AccumulateCount(info.storage_buffers_descriptors)};
|
||||
const u32 num_storage_buffers{Shader::NumDescriptors(info.storage_buffers_descriptors)};
|
||||
use_storage_buffers =
|
||||
!is_glasm || num_storage_buffers < device.GetMaxGLASMStorageBufferBlocks();
|
||||
writes_global_memory = !use_storage_buffers &&
|
||||
@@ -88,8 +79,7 @@ void ComputePipeline::Configure() {
|
||||
}
|
||||
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;
|
||||
boost::container::static_vector<VideoCommon::ImageViewInOut, MAX_TEXTURES + MAX_IMAGES> views;
|
||||
std::array<GLuint, MAX_TEXTURES> samplers;
|
||||
std::array<GLuint, MAX_TEXTURES> textures;
|
||||
std::array<GLuint, MAX_IMAGES> images;
|
||||
@@ -119,33 +109,39 @@ void ComputePipeline::Configure() {
|
||||
}
|
||||
return TexturePair(gpu_memory.Read<u32>(addr), via_header_index);
|
||||
}};
|
||||
const auto add_image{[&](const auto& desc) {
|
||||
const auto add_image{[&](const auto& desc, bool blacklist) {
|
||||
for (u32 index = 0; index < desc.count; ++index) {
|
||||
const auto handle{read_handle(desc, index)};
|
||||
image_view_indices.push_back(handle.first);
|
||||
views.push_back({
|
||||
.index = handle.first,
|
||||
.blacklist = blacklist,
|
||||
.id = {},
|
||||
});
|
||||
}
|
||||
}};
|
||||
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);
|
||||
views.push_back({handle.first});
|
||||
samplers[sampler_binding++] = 0;
|
||||
}
|
||||
}
|
||||
std::ranges::for_each(info.image_buffer_descriptors, add_image);
|
||||
for (const auto& desc : info.image_buffer_descriptors) {
|
||||
add_image(desc, false);
|
||||
}
|
||||
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);
|
||||
views.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);
|
||||
for (const auto& desc : info.image_descriptors) {
|
||||
add_image(desc, desc.is_written);
|
||||
}
|
||||
texture_cache.FillComputeImageViews(std::span(views.data(), views.size()));
|
||||
|
||||
if (assembly_program.handle != 0) {
|
||||
program_manager.BindComputeAssemblyProgram(assembly_program.handle);
|
||||
@@ -161,7 +157,7 @@ void ComputePipeline::Configure() {
|
||||
if constexpr (is_image) {
|
||||
is_written = desc.is_written;
|
||||
}
|
||||
ImageView& image_view{texture_cache.GetImageView(image_view_ids[texbuf_index])};
|
||||
ImageView& image_view{texture_cache.GetImageView(views[texbuf_index].id)};
|
||||
buffer_cache.BindComputeTextureBuffer(texbuf_index, image_view.GpuAddr(),
|
||||
image_view.BufferSize(), image_view.format,
|
||||
is_written, is_image);
|
||||
@@ -177,23 +173,45 @@ void ComputePipeline::Configure() {
|
||||
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};
|
||||
const VideoCommon::ImageViewInOut* views_it{views.data() + num_texture_buffers +
|
||||
num_image_buffers};
|
||||
texture_binding += num_texture_buffers;
|
||||
image_binding += num_image_buffers;
|
||||
|
||||
u32 texture_scaling_mask{};
|
||||
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);
|
||||
ImageView& image_view{texture_cache.GetImageView((views_it++)->id)};
|
||||
textures[texture_binding] = image_view.Handle(desc.type);
|
||||
if (texture_cache.IsRescaling(image_view)) {
|
||||
texture_scaling_mask |= 1u << texture_binding;
|
||||
}
|
||||
++texture_binding;
|
||||
}
|
||||
}
|
||||
u32 image_scaling_mask{};
|
||||
for (const auto& desc : info.image_descriptors) {
|
||||
for (u32 index = 0; index < desc.count; ++index) {
|
||||
ImageView& image_view{texture_cache.GetImageView(*(views_it++))};
|
||||
ImageView& image_view{texture_cache.GetImageView((views_it++)->id)};
|
||||
if (desc.is_written) {
|
||||
texture_cache.MarkModification(image_view.image_id);
|
||||
}
|
||||
images[image_binding++] = image_view.StorageView(desc.type, desc.format);
|
||||
images[image_binding] = image_view.StorageView(desc.type, desc.format);
|
||||
if (texture_cache.IsRescaling(image_view)) {
|
||||
image_scaling_mask |= 1u << image_binding;
|
||||
}
|
||||
++image_binding;
|
||||
}
|
||||
}
|
||||
if (info.uses_rescaling_uniform) {
|
||||
const f32 float_texture_scaling_mask{Common::BitCast<f32>(texture_scaling_mask)};
|
||||
const f32 float_image_scaling_mask{Common::BitCast<f32>(image_scaling_mask)};
|
||||
if (assembly_program.handle != 0) {
|
||||
glProgramLocalParameter4fARB(GL_COMPUTE_PROGRAM_NV, 0, float_texture_scaling_mask,
|
||||
float_image_scaling_mask, 0.0f, 0.0f);
|
||||
} else {
|
||||
glProgramUniform4f(source_program.handle, 0, float_texture_scaling_mask,
|
||||
float_image_scaling_mask, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
if (texture_binding != 0) {
|
||||
|
@@ -15,7 +15,7 @@
|
||||
#include "video_core/renderer_opengl/gl_shader_util.h"
|
||||
#include "video_core/renderer_opengl/gl_state_tracker.h"
|
||||
#include "video_core/shader_notify.h"
|
||||
#include "video_core/texture_cache/texture_cache_base.h"
|
||||
#include "video_core/texture_cache/texture_cache.h"
|
||||
|
||||
#if defined(_MSC_VER) && defined(NDEBUG)
|
||||
#define LAMBDA_FORCEINLINE [[msvc::forceinline]]
|
||||
@@ -27,6 +27,7 @@ namespace OpenGL {
|
||||
namespace {
|
||||
using Shader::ImageBufferDescriptor;
|
||||
using Shader::ImageDescriptor;
|
||||
using Shader::NumDescriptors;
|
||||
using Shader::TextureBufferDescriptor;
|
||||
using Shader::TextureDescriptor;
|
||||
using Tegra::Texture::TexturePair;
|
||||
@@ -35,15 +36,6 @@ using VideoCommon::ImageId;
|
||||
constexpr u32 MAX_TEXTURES = 64;
|
||||
constexpr u32 MAX_IMAGES = 8;
|
||||
|
||||
template <typename Range>
|
||||
u32 AccumulateCount(const Range& range) {
|
||||
u32 num{};
|
||||
for (const auto& desc : range) {
|
||||
num += desc.count;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
GLenum Stage(size_t stage_index) {
|
||||
switch (stage_index) {
|
||||
case 0:
|
||||
@@ -204,23 +196,23 @@ GraphicsPipeline::GraphicsPipeline(
|
||||
base_uniform_bindings[stage + 1] = base_uniform_bindings[stage];
|
||||
base_storage_bindings[stage + 1] = base_storage_bindings[stage];
|
||||
|
||||
base_uniform_bindings[stage + 1] += AccumulateCount(info.constant_buffer_descriptors);
|
||||
base_storage_bindings[stage + 1] += AccumulateCount(info.storage_buffers_descriptors);
|
||||
base_uniform_bindings[stage + 1] += NumDescriptors(info.constant_buffer_descriptors);
|
||||
base_storage_bindings[stage + 1] += NumDescriptors(info.storage_buffers_descriptors);
|
||||
}
|
||||
enabled_uniform_buffer_masks[stage] = info.constant_buffer_mask;
|
||||
std::ranges::copy(info.constant_buffer_used_sizes, uniform_buffer_sizes[stage].begin());
|
||||
|
||||
const u32 num_tex_buffer_bindings{AccumulateCount(info.texture_buffer_descriptors)};
|
||||
const u32 num_tex_buffer_bindings{NumDescriptors(info.texture_buffer_descriptors)};
|
||||
num_texture_buffers[stage] += num_tex_buffer_bindings;
|
||||
num_textures += num_tex_buffer_bindings;
|
||||
|
||||
const u32 num_img_buffers_bindings{AccumulateCount(info.image_buffer_descriptors)};
|
||||
const u32 num_img_buffers_bindings{NumDescriptors(info.image_buffer_descriptors)};
|
||||
num_image_buffers[stage] += num_img_buffers_bindings;
|
||||
num_images += num_img_buffers_bindings;
|
||||
|
||||
num_textures += AccumulateCount(info.texture_descriptors);
|
||||
num_images += AccumulateCount(info.image_descriptors);
|
||||
num_storage_buffers += AccumulateCount(info.storage_buffers_descriptors);
|
||||
num_textures += NumDescriptors(info.texture_descriptors);
|
||||
num_images += NumDescriptors(info.image_descriptors);
|
||||
num_storage_buffers += NumDescriptors(info.storage_buffers_descriptors);
|
||||
|
||||
writes_global_memory |= std::ranges::any_of(
|
||||
info.storage_buffers_descriptors, [](const auto& desc) { return desc.is_written; });
|
||||
@@ -288,10 +280,9 @@ GraphicsPipeline::GraphicsPipeline(
|
||||
|
||||
template <typename Spec>
|
||||
void GraphicsPipeline::ConfigureImpl(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<VideoCommon::ImageViewInOut, MAX_TEXTURES + MAX_IMAGES> views;
|
||||
std::array<GLuint, MAX_TEXTURES> samplers;
|
||||
size_t image_view_index{};
|
||||
size_t views_index{};
|
||||
GLsizei sampler_binding{};
|
||||
|
||||
texture_cache.SynchronizeGraphicsDescriptors();
|
||||
@@ -336,30 +327,34 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||
}
|
||||
return TexturePair(gpu_memory.Read<u32>(addr), via_header_index);
|
||||
}};
|
||||
const auto add_image{[&](const auto& desc) {
|
||||
const auto add_image{[&](const auto& desc, bool blacklist) LAMBDA_FORCEINLINE {
|
||||
for (u32 index = 0; index < desc.count; ++index) {
|
||||
const auto handle{read_handle(desc, index)};
|
||||
image_view_indices[image_view_index++] = handle.first;
|
||||
views[views_index++] = {
|
||||
.index = handle.first,
|
||||
.blacklist = blacklist,
|
||||
.id = {},
|
||||
};
|
||||
}
|
||||
}};
|
||||
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;
|
||||
views[views_index++] = {handle.first};
|
||||
samplers[sampler_binding++] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if constexpr (Spec::has_image_buffers) {
|
||||
for (const auto& desc : info.image_buffer_descriptors) {
|
||||
add_image(desc);
|
||||
add_image(desc, false);
|
||||
}
|
||||
}
|
||||
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;
|
||||
views[views_index++] = {handle.first};
|
||||
|
||||
Sampler* const sampler{texture_cache.GetGraphicsSampler(handle.second)};
|
||||
samplers[sampler_binding++] = sampler->Handle();
|
||||
@@ -367,7 +362,7 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||
}
|
||||
if constexpr (Spec::has_images) {
|
||||
for (const auto& desc : info.image_descriptors) {
|
||||
add_image(desc);
|
||||
add_image(desc, desc.is_written);
|
||||
}
|
||||
}
|
||||
}};
|
||||
@@ -386,13 +381,12 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||
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);
|
||||
texture_cache.FillGraphicsImageViews<Spec::has_images>(std::span(views.data(), views_index));
|
||||
|
||||
texture_cache.UpdateRenderTargets(false);
|
||||
state_tracker.BindFramebuffer(texture_cache.GetFramebuffer()->Handle());
|
||||
|
||||
ImageId* texture_buffer_index{image_view_ids.data()};
|
||||
VideoCommon::ImageViewInOut* texture_buffer_it{views.data()};
|
||||
const auto bind_stage_info{[&](size_t stage) LAMBDA_FORCEINLINE {
|
||||
size_t index{};
|
||||
const auto add_buffer{[&](const auto& desc) {
|
||||
@@ -402,12 +396,12 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||
if constexpr (is_image) {
|
||||
is_written = desc.is_written;
|
||||
}
|
||||
ImageView& image_view{texture_cache.GetImageView(*texture_buffer_index)};
|
||||
ImageView& image_view{texture_cache.GetImageView(texture_buffer_it->id)};
|
||||
buffer_cache.BindGraphicsTextureBuffer(stage, index, image_view.GpuAddr(),
|
||||
image_view.BufferSize(), image_view.format,
|
||||
is_written, is_image);
|
||||
++index;
|
||||
++texture_buffer_index;
|
||||
++texture_buffer_it;
|
||||
}
|
||||
}};
|
||||
const Shader::Info& info{stage_infos[stage]};
|
||||
@@ -423,13 +417,9 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||
add_buffer(desc);
|
||||
}
|
||||
}
|
||||
for (const auto& desc : info.texture_descriptors) {
|
||||
texture_buffer_index += desc.count;
|
||||
}
|
||||
texture_buffer_it += Shader::NumDescriptors(info.texture_descriptors);
|
||||
if constexpr (Spec::has_images) {
|
||||
for (const auto& desc : info.image_descriptors) {
|
||||
texture_buffer_index += desc.count;
|
||||
}
|
||||
texture_buffer_it += Shader::NumDescriptors(info.image_descriptors);
|
||||
}
|
||||
}};
|
||||
if constexpr (Spec::enabled_stages[0]) {
|
||||
@@ -453,12 +443,13 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||
if (!is_built.load(std::memory_order::relaxed)) {
|
||||
WaitForBuild();
|
||||
}
|
||||
if (assembly_programs[0].handle != 0) {
|
||||
const bool use_assembly{assembly_programs[0].handle != 0};
|
||||
if (use_assembly) {
|
||||
program_manager.BindAssemblyPrograms(assembly_programs, enabled_stages_mask);
|
||||
} else {
|
||||
program_manager.BindSourcePrograms(source_programs);
|
||||
}
|
||||
const ImageId* views_it{image_view_ids.data()};
|
||||
const VideoCommon::ImageViewInOut* views_it{views.data()};
|
||||
GLsizei texture_binding = 0;
|
||||
GLsizei image_binding = 0;
|
||||
std::array<GLuint, MAX_TEXTURES> textures;
|
||||
@@ -473,20 +464,49 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||
views_it += num_texture_buffers[stage];
|
||||
views_it += num_image_buffers[stage];
|
||||
|
||||
u32 texture_scaling_mask{};
|
||||
u32 image_scaling_mask{};
|
||||
u32 stage_texture_binding{};
|
||||
u32 stage_image_binding{};
|
||||
|
||||
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);
|
||||
ImageView& image_view{texture_cache.GetImageView((views_it++)->id)};
|
||||
textures[texture_binding] = image_view.Handle(desc.type);
|
||||
if (texture_cache.IsRescaling(image_view)) {
|
||||
texture_scaling_mask |= 1u << stage_texture_binding;
|
||||
}
|
||||
++texture_binding;
|
||||
++stage_texture_binding;
|
||||
}
|
||||
}
|
||||
for (const auto& desc : info.image_descriptors) {
|
||||
for (u32 index = 0; index < desc.count; ++index) {
|
||||
ImageView& image_view{texture_cache.GetImageView(*(views_it++))};
|
||||
ImageView& image_view{texture_cache.GetImageView((views_it++)->id)};
|
||||
if (desc.is_written) {
|
||||
texture_cache.MarkModification(image_view.image_id);
|
||||
}
|
||||
images[image_binding++] = image_view.StorageView(desc.type, desc.format);
|
||||
images[image_binding] = image_view.StorageView(desc.type, desc.format);
|
||||
if (texture_cache.IsRescaling(image_view)) {
|
||||
image_scaling_mask |= 1u << stage_image_binding;
|
||||
}
|
||||
++image_binding;
|
||||
++stage_image_binding;
|
||||
}
|
||||
}
|
||||
if (info.uses_rescaling_uniform) {
|
||||
const f32 float_texture_scaling_mask{Common::BitCast<f32>(texture_scaling_mask)};
|
||||
const f32 float_image_scaling_mask{Common::BitCast<f32>(image_scaling_mask)};
|
||||
const bool is_rescaling{texture_cache.IsRescaling()};
|
||||
const f32 config_down_factor{Settings::values.resolution_info.down_factor};
|
||||
const f32 down_factor{is_rescaling ? config_down_factor : 1.0f};
|
||||
if (use_assembly) {
|
||||
glProgramLocalParameter4fARB(AssemblyStage(stage), 0, float_texture_scaling_mask,
|
||||
float_image_scaling_mask, down_factor, 0.0f);
|
||||
} else {
|
||||
glProgramUniform4f(source_programs[stage].handle, 0, float_texture_scaling_mask,
|
||||
float_image_scaling_mask, down_factor, 0.0f);
|
||||
}
|
||||
}
|
||||
}};
|
||||
|
@@ -186,6 +186,10 @@ void RasterizerOpenGL::Clear() {
|
||||
SyncRasterizeEnable();
|
||||
SyncStencilTestState();
|
||||
|
||||
std::scoped_lock lock{texture_cache.mutex};
|
||||
texture_cache.UpdateRenderTargets(true);
|
||||
state_tracker.BindFramebuffer(texture_cache.GetFramebuffer()->Handle());
|
||||
SyncViewport();
|
||||
if (regs.clear_flags.scissor) {
|
||||
SyncScissorTest();
|
||||
} else {
|
||||
@@ -194,10 +198,6 @@ void RasterizerOpenGL::Clear() {
|
||||
}
|
||||
UNIMPLEMENTED_IF(regs.clear_flags.viewport);
|
||||
|
||||
std::scoped_lock lock{texture_cache.mutex};
|
||||
texture_cache.UpdateRenderTargets(true);
|
||||
state_tracker.BindFramebuffer(texture_cache.GetFramebuffer()->Handle());
|
||||
|
||||
if (use_color) {
|
||||
glClearBufferfv(GL_COLOR, regs.clear_buffers.RT, regs.clear_color);
|
||||
}
|
||||
@@ -216,8 +216,6 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
|
||||
|
||||
query_cache.UpdateCounters();
|
||||
|
||||
SyncState();
|
||||
|
||||
GraphicsPipeline* const pipeline{shader_cache.CurrentGraphicsPipeline()};
|
||||
if (!pipeline) {
|
||||
return;
|
||||
@@ -225,6 +223,8 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
|
||||
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
|
||||
pipeline->Configure(is_indexed);
|
||||
|
||||
SyncState();
|
||||
|
||||
const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(maxwell3d.regs.draw.topology);
|
||||
BeginTransformFeedback(pipeline, primitive_mode);
|
||||
|
||||
@@ -535,7 +535,8 @@ void RasterizerOpenGL::SyncViewport() {
|
||||
auto& flags = maxwell3d.dirty.flags;
|
||||
const auto& regs = maxwell3d.regs;
|
||||
|
||||
const bool dirty_viewport = flags[Dirty::Viewports];
|
||||
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]) {
|
||||
@@ -555,8 +556,7 @@ void RasterizerOpenGL::SyncViewport() {
|
||||
}
|
||||
glFrontFace(mode);
|
||||
}
|
||||
|
||||
if (dirty_viewport || flags[Dirty::ClipControl]) {
|
||||
if (dirty_viewport || dirty_clip_control) {
|
||||
flags[Dirty::ClipControl] = false;
|
||||
|
||||
bool flip_y = false;
|
||||
@@ -572,37 +572,58 @@ void RasterizerOpenGL::SyncViewport() {
|
||||
state_tracker.ClipControl(origin, depth);
|
||||
state_tracker.SetYNegate(regs.screen_y_control.y_negate != 0);
|
||||
}
|
||||
const bool is_rescaling{texture_cache.IsRescaling()};
|
||||
const float scale = is_rescaling ? Settings::values.resolution_info.up_factor : 1.0f;
|
||||
const auto conv = [scale](float value) -> GLfloat {
|
||||
float new_value = value * scale;
|
||||
if (scale < 1.0f) {
|
||||
const bool sign = std::signbit(value);
|
||||
new_value = std::round(std::abs(new_value));
|
||||
new_value = sign ? -new_value : new_value;
|
||||
}
|
||||
return static_cast<GLfloat>(new_value);
|
||||
};
|
||||
|
||||
if (dirty_viewport) {
|
||||
flags[Dirty::Viewports] = false;
|
||||
|
||||
const bool force = flags[Dirty::ViewportTransform];
|
||||
const bool force = flags[Dirty::ViewportTransform] || rescale_viewports;
|
||||
flags[Dirty::ViewportTransform] = false;
|
||||
flags[VideoCommon::Dirty::RescaleViewports] = false;
|
||||
|
||||
for (std::size_t i = 0; i < Maxwell::NumViewports; ++i) {
|
||||
if (!force && !flags[Dirty::Viewport0 + i]) {
|
||||
for (size_t index = 0; index < Maxwell::NumViewports; ++index) {
|
||||
if (!force && !flags[Dirty::Viewport0 + index]) {
|
||||
continue;
|
||||
}
|
||||
flags[Dirty::Viewport0 + i] = false;
|
||||
flags[Dirty::Viewport0 + index] = false;
|
||||
|
||||
const auto& src = regs.viewport_transform[i];
|
||||
const Common::Rectangle<f32> rect{src.GetRect()};
|
||||
glViewportIndexedf(static_cast<GLuint>(i), rect.left, rect.bottom, rect.GetWidth(),
|
||||
rect.GetHeight());
|
||||
const auto& src = regs.viewport_transform[index];
|
||||
GLfloat x = conv(src.translate_x - src.scale_x);
|
||||
GLfloat y = conv(src.translate_y - src.scale_y);
|
||||
GLfloat width = conv(src.scale_x * 2.0f);
|
||||
GLfloat height = conv(src.scale_y * 2.0f);
|
||||
|
||||
if (height < 0) {
|
||||
y += height;
|
||||
height = -height;
|
||||
}
|
||||
glViewportIndexedf(static_cast<GLuint>(index), x, y, width != 0.0f ? width : 1.0f,
|
||||
height != 0.0f ? height : 1.0f);
|
||||
|
||||
const GLdouble reduce_z = regs.depth_mode == Maxwell::DepthMode::MinusOneToOne;
|
||||
const GLdouble near_depth = src.translate_z - src.scale_z * reduce_z;
|
||||
const GLdouble far_depth = src.translate_z + src.scale_z;
|
||||
if (device.HasDepthBufferFloat()) {
|
||||
glDepthRangeIndexeddNV(static_cast<GLuint>(i), near_depth, far_depth);
|
||||
glDepthRangeIndexeddNV(static_cast<GLuint>(index), near_depth, far_depth);
|
||||
} else {
|
||||
glDepthRangeIndexed(static_cast<GLuint>(i), near_depth, far_depth);
|
||||
glDepthRangeIndexed(static_cast<GLuint>(index), near_depth, far_depth);
|
||||
}
|
||||
|
||||
if (!GLAD_GL_NV_viewport_swizzle) {
|
||||
continue;
|
||||
}
|
||||
glViewportSwizzleNV(static_cast<GLuint>(i), MaxwellToGL::ViewportSwizzle(src.swizzle.x),
|
||||
glViewportSwizzleNV(static_cast<GLuint>(index),
|
||||
MaxwellToGL::ViewportSwizzle(src.swizzle.x),
|
||||
MaxwellToGL::ViewportSwizzle(src.swizzle.y),
|
||||
MaxwellToGL::ViewportSwizzle(src.swizzle.z),
|
||||
MaxwellToGL::ViewportSwizzle(src.swizzle.w));
|
||||
@@ -905,14 +926,34 @@ void RasterizerOpenGL::SyncLogicOpState() {
|
||||
|
||||
void RasterizerOpenGL::SyncScissorTest() {
|
||||
auto& flags = maxwell3d.dirty.flags;
|
||||
if (!flags[Dirty::Scissors]) {
|
||||
if (!flags[Dirty::Scissors] && !flags[VideoCommon::Dirty::RescaleScissors]) {
|
||||
return;
|
||||
}
|
||||
flags[Dirty::Scissors] = false;
|
||||
|
||||
const bool force = flags[VideoCommon::Dirty::RescaleScissors];
|
||||
flags[VideoCommon::Dirty::RescaleScissors] = false;
|
||||
|
||||
const auto& regs = maxwell3d.regs;
|
||||
|
||||
const auto& resolution = Settings::values.resolution_info;
|
||||
const bool is_rescaling{texture_cache.IsRescaling()};
|
||||
const u32 up_scale = is_rescaling ? resolution.up_scale : 1U;
|
||||
const u32 down_shift = is_rescaling ? resolution.down_shift : 0U;
|
||||
const auto scale_up = [up_scale, down_shift](u32 value) -> u32 {
|
||||
if (value == 0) {
|
||||
return 0U;
|
||||
}
|
||||
const u32 upset = value * up_scale;
|
||||
u32 acumm{};
|
||||
if ((up_scale >> down_shift) == 0) {
|
||||
acumm = upset % 2;
|
||||
}
|
||||
const u32 converted_value = upset >> down_shift;
|
||||
return std::max<u32>(converted_value + acumm, 1U);
|
||||
};
|
||||
for (std::size_t index = 0; index < Maxwell::NumViewports; ++index) {
|
||||
if (!flags[Dirty::Scissor0 + index]) {
|
||||
if (!force && !flags[Dirty::Scissor0 + index]) {
|
||||
continue;
|
||||
}
|
||||
flags[Dirty::Scissor0 + index] = false;
|
||||
@@ -920,8 +961,8 @@ void RasterizerOpenGL::SyncScissorTest() {
|
||||
const auto& src = regs.scissor_test[index];
|
||||
if (src.enable) {
|
||||
glEnablei(GL_SCISSOR_TEST, static_cast<GLuint>(index));
|
||||
glScissorIndexed(static_cast<GLuint>(index), src.min_x, src.min_y,
|
||||
src.max_x - src.min_x, src.max_y - src.min_y);
|
||||
glScissorIndexed(static_cast<GLuint>(index), scale_up(src.min_x), scale_up(src.min_y),
|
||||
scale_up(src.max_x - src.min_x), scale_up(src.max_y - src.min_y));
|
||||
} else {
|
||||
glDisablei(GL_SCISSOR_TEST, static_cast<GLuint>(index));
|
||||
}
|
||||
|
@@ -166,7 +166,7 @@ void OGLFramebuffer::Create() {
|
||||
return;
|
||||
|
||||
MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
|
||||
glGenFramebuffers(1, &handle);
|
||||
glCreateFramebuffers(1, &handle);
|
||||
}
|
||||
|
||||
void OGLFramebuffer::Release() {
|
||||
|
@@ -426,16 +426,14 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(
|
||||
// Normal path
|
||||
programs[index] = TranslateProgram(pools.inst, pools.block, env, cfg, host_info);
|
||||
|
||||
for (const auto& desc : programs[index].info.storage_buffers_descriptors) {
|
||||
total_storage_buffers += desc.count;
|
||||
}
|
||||
total_storage_buffers +=
|
||||
Shader::NumDescriptors(programs[index].info.storage_buffers_descriptors);
|
||||
} else {
|
||||
// VertexB path when VertexA is present.
|
||||
auto& program_va{programs[0]};
|
||||
auto program_vb{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)};
|
||||
for (const auto& desc : program_vb.info.storage_buffers_descriptors) {
|
||||
total_storage_buffers += desc.count;
|
||||
}
|
||||
total_storage_buffers +=
|
||||
Shader::NumDescriptors(program_vb.info.storage_buffers_descriptors);
|
||||
programs[index] = MergeDualVertexPrograms(program_va, program_vb, env);
|
||||
}
|
||||
}
|
||||
@@ -510,10 +508,7 @@ std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline(
|
||||
Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()};
|
||||
auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)};
|
||||
|
||||
u32 num_storage_buffers{};
|
||||
for (const auto& desc : program.info.storage_buffers_descriptors) {
|
||||
num_storage_buffers += desc.count;
|
||||
}
|
||||
const u32 num_storage_buffers{Shader::NumDescriptors(program.info.storage_buffers_descriptors)};
|
||||
Shader::RuntimeInfo info;
|
||||
info.glasm_use_storage_buffers = num_storage_buffers <= device.GetMaxGLASMStorageBufferBlocks();
|
||||
|
||||
|
@@ -316,6 +316,52 @@ void AttachTexture(GLuint fbo, GLenum attachment, const ImageView* image_view) {
|
||||
}
|
||||
}
|
||||
|
||||
OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_format) {
|
||||
const GLenum target = ImageTarget(info);
|
||||
const GLsizei width = info.size.width;
|
||||
const GLsizei height = info.size.height;
|
||||
const GLsizei depth = info.size.depth;
|
||||
const int max_host_mip_levels = std::bit_width(info.size.width);
|
||||
const GLsizei num_levels = std::min(info.resources.levels, max_host_mip_levels);
|
||||
const GLsizei num_layers = info.resources.layers;
|
||||
const GLsizei num_samples = info.num_samples;
|
||||
|
||||
GLuint handle = 0;
|
||||
OGLTexture texture;
|
||||
if (target != GL_TEXTURE_BUFFER) {
|
||||
texture.Create(target);
|
||||
handle = texture.handle;
|
||||
}
|
||||
switch (target) {
|
||||
case GL_TEXTURE_1D_ARRAY:
|
||||
glTextureStorage2D(handle, num_levels, gl_internal_format, width, num_layers);
|
||||
break;
|
||||
case GL_TEXTURE_2D_ARRAY:
|
||||
glTextureStorage3D(handle, num_levels, gl_internal_format, width, height, num_layers);
|
||||
break;
|
||||
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: {
|
||||
// TODO: Where should 'fixedsamplelocations' come from?
|
||||
const auto [samples_x, samples_y] = SamplesLog2(info.num_samples);
|
||||
glTextureStorage3DMultisample(handle, num_samples, gl_internal_format, width >> samples_x,
|
||||
height >> samples_y, num_layers, GL_FALSE);
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_RECTANGLE:
|
||||
glTextureStorage2D(handle, num_levels, gl_internal_format, width, height);
|
||||
break;
|
||||
case GL_TEXTURE_3D:
|
||||
glTextureStorage3D(handle, num_levels, gl_internal_format, width, height, depth);
|
||||
break;
|
||||
case GL_TEXTURE_BUFFER:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE_MSG("Invalid target=0x{:x}", target);
|
||||
break;
|
||||
}
|
||||
return texture;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool IsPixelFormatBGR(PixelFormat format) {
|
||||
switch (format) {
|
||||
case PixelFormat::B5G6R5_UNORM:
|
||||
@@ -359,7 +405,8 @@ ImageBufferMap::~ImageBufferMap() {
|
||||
|
||||
TextureCacheRuntime::TextureCacheRuntime(const Device& device_, ProgramManager& program_manager,
|
||||
StateTracker& state_tracker_)
|
||||
: device{device_}, state_tracker{state_tracker_}, util_shaders(program_manager) {
|
||||
: device{device_}, state_tracker{state_tracker_},
|
||||
util_shaders(program_manager), 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];
|
||||
@@ -426,6 +473,17 @@ 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);
|
||||
|
||||
if (resolution.active) {
|
||||
for (size_t i = 0; i < rescale_draw_fbos.size(); ++i) {
|
||||
rescale_draw_fbos[i].Create();
|
||||
rescale_read_fbos[i].Create();
|
||||
|
||||
// Make sure the framebuffer is created without DSA
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, rescale_draw_fbos[i].handle);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, rescale_read_fbos[i].handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextureCacheRuntime::~TextureCacheRuntime() = default;
|
||||
@@ -605,13 +663,13 @@ std::optional<size_t> TextureCacheRuntime::StagingBuffers::FindBuffer(size_t req
|
||||
return found;
|
||||
}
|
||||
|
||||
Image::Image(TextureCacheRuntime& runtime, const VideoCommon::ImageInfo& info_, GPUVAddr gpu_addr_,
|
||||
Image::Image(TextureCacheRuntime& runtime_, const VideoCommon::ImageInfo& info_, GPUVAddr gpu_addr_,
|
||||
VAddr cpu_addr_)
|
||||
: VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_) {
|
||||
if (CanBeAccelerated(runtime, info)) {
|
||||
: VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), runtime{&runtime_} {
|
||||
if (CanBeAccelerated(*runtime, info)) {
|
||||
flags |= ImageFlagBits::AcceleratedUpload;
|
||||
}
|
||||
if (IsConverted(runtime.device, info.format, info.type)) {
|
||||
if (IsConverted(runtime->device, info.format, info.type)) {
|
||||
flags |= ImageFlagBits::Converted;
|
||||
gl_internal_format = IsPixelFormatSRGB(info.format) ? GL_SRGB8_ALPHA8 : GL_RGBA8;
|
||||
gl_format = GL_RGBA;
|
||||
@@ -622,58 +680,25 @@ Image::Image(TextureCacheRuntime& runtime, const VideoCommon::ImageInfo& info_,
|
||||
gl_format = tuple.format;
|
||||
gl_type = tuple.type;
|
||||
}
|
||||
const GLenum target = ImageTarget(info);
|
||||
const GLsizei width = info.size.width;
|
||||
const GLsizei height = info.size.height;
|
||||
const GLsizei depth = info.size.depth;
|
||||
const int max_host_mip_levels = std::bit_width(info.size.width);
|
||||
const GLsizei num_levels = std::min(info.resources.levels, max_host_mip_levels);
|
||||
const GLsizei num_layers = info.resources.layers;
|
||||
const GLsizei num_samples = info.num_samples;
|
||||
|
||||
GLuint handle = 0;
|
||||
if (target != GL_TEXTURE_BUFFER) {
|
||||
texture.Create(target);
|
||||
handle = texture.handle;
|
||||
}
|
||||
switch (target) {
|
||||
case GL_TEXTURE_1D_ARRAY:
|
||||
glTextureStorage2D(handle, num_levels, gl_internal_format, width, num_layers);
|
||||
break;
|
||||
case GL_TEXTURE_2D_ARRAY:
|
||||
glTextureStorage3D(handle, num_levels, gl_internal_format, width, height, num_layers);
|
||||
break;
|
||||
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: {
|
||||
// TODO: Where should 'fixedsamplelocations' come from?
|
||||
const auto [samples_x, samples_y] = SamplesLog2(info.num_samples);
|
||||
glTextureStorage3DMultisample(handle, num_samples, gl_internal_format, width >> samples_x,
|
||||
height >> samples_y, num_layers, GL_FALSE);
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_RECTANGLE:
|
||||
glTextureStorage2D(handle, num_levels, gl_internal_format, width, height);
|
||||
break;
|
||||
case GL_TEXTURE_3D:
|
||||
glTextureStorage3D(handle, num_levels, gl_internal_format, width, height, depth);
|
||||
break;
|
||||
case GL_TEXTURE_BUFFER:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE_MSG("Invalid target=0x{:x}", target);
|
||||
break;
|
||||
}
|
||||
if (runtime.device.HasDebuggingToolAttached()) {
|
||||
texture = MakeImage(info, gl_internal_format);
|
||||
current_texture = texture.handle;
|
||||
if (runtime->device.HasDebuggingToolAttached()) {
|
||||
const std::string name = VideoCommon::Name(*this);
|
||||
glObjectLabel(target == GL_TEXTURE_BUFFER ? GL_BUFFER : GL_TEXTURE, handle,
|
||||
static_cast<GLsizei>(name.size()), name.data());
|
||||
glObjectLabel(ImageTarget(info) == GL_TEXTURE_BUFFER ? GL_BUFFER : GL_TEXTURE,
|
||||
texture.handle, static_cast<GLsizei>(name.size()), name.data());
|
||||
}
|
||||
}
|
||||
|
||||
Image::Image(const VideoCommon::NullImageParams& params) : VideoCommon::ImageBase{params} {}
|
||||
|
||||
Image::~Image() = default;
|
||||
|
||||
void Image::UploadMemory(const ImageBufferMap& map,
|
||||
std::span<const VideoCommon::BufferImageCopy> copies) {
|
||||
const bool is_rescaled = True(flags & ImageFlagBits::Rescaled);
|
||||
if (is_rescaled) {
|
||||
ScaleDown(true);
|
||||
}
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, map.buffer);
|
||||
glFlushMappedBufferRange(GL_PIXEL_UNPACK_BUFFER, map.offset, unswizzled_size_bytes);
|
||||
|
||||
@@ -693,12 +718,18 @@ void Image::UploadMemory(const ImageBufferMap& map,
|
||||
}
|
||||
CopyBufferToImage(copy, map.offset);
|
||||
}
|
||||
if (is_rescaled) {
|
||||
ScaleUp();
|
||||
}
|
||||
}
|
||||
|
||||
void Image::DownloadMemory(ImageBufferMap& map,
|
||||
std::span<const VideoCommon::BufferImageCopy> copies) {
|
||||
const bool is_rescaled = True(flags & ImageFlagBits::Rescaled);
|
||||
if (is_rescaled) {
|
||||
ScaleDown();
|
||||
}
|
||||
glMemoryBarrier(GL_PIXEL_BUFFER_BARRIER_BIT); // TODO: Move this to its own API
|
||||
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, map.buffer);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
|
||||
@@ -716,6 +747,9 @@ void Image::DownloadMemory(ImageBufferMap& map,
|
||||
}
|
||||
CopyImageToBuffer(copy, map.offset);
|
||||
}
|
||||
if (is_rescaled) {
|
||||
ScaleUp(true);
|
||||
}
|
||||
}
|
||||
|
||||
GLuint Image::StorageHandle() noexcept {
|
||||
@@ -741,11 +775,11 @@ GLuint Image::StorageHandle() noexcept {
|
||||
return store_view.handle;
|
||||
}
|
||||
store_view.Create();
|
||||
glTextureView(store_view.handle, ImageTarget(info), texture.handle, GL_RGBA8, 0,
|
||||
glTextureView(store_view.handle, ImageTarget(info), current_texture, GL_RGBA8, 0,
|
||||
info.resources.levels, 0, info.resources.layers);
|
||||
return store_view.handle;
|
||||
default:
|
||||
return texture.handle;
|
||||
return current_texture;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -849,6 +883,140 @@ void Image::CopyImageToBuffer(const VideoCommon::BufferImageCopy& copy, size_t b
|
||||
}
|
||||
}
|
||||
|
||||
void Image::Scale(bool up_scale) {
|
||||
const auto format_type = GetFormatType(info.format);
|
||||
const GLenum attachment = [format_type] {
|
||||
switch (format_type) {
|
||||
case SurfaceType::ColorTexture:
|
||||
return GL_COLOR_ATTACHMENT0;
|
||||
case SurfaceType::Depth:
|
||||
return GL_DEPTH_ATTACHMENT;
|
||||
case SurfaceType::DepthStencil:
|
||||
return GL_DEPTH_STENCIL_ATTACHMENT;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return GL_COLOR_ATTACHMENT0;
|
||||
}
|
||||
}();
|
||||
const GLenum mask = [format_type] {
|
||||
switch (format_type) {
|
||||
case SurfaceType::ColorTexture:
|
||||
return GL_COLOR_BUFFER_BIT;
|
||||
case SurfaceType::Depth:
|
||||
return GL_DEPTH_BUFFER_BIT;
|
||||
case SurfaceType::DepthStencil:
|
||||
return GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return GL_COLOR_BUFFER_BIT;
|
||||
}
|
||||
}();
|
||||
const size_t fbo_index = [format_type] {
|
||||
switch (format_type) {
|
||||
case SurfaceType::ColorTexture:
|
||||
return 0;
|
||||
case SurfaceType::Depth:
|
||||
return 1;
|
||||
case SurfaceType::DepthStencil:
|
||||
return 2;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
}();
|
||||
const bool is_2d = info.type == ImageType::e2D;
|
||||
const bool is_color{(mask & GL_COLOR_BUFFER_BIT) != 0};
|
||||
// Integer formats must use NEAREST filter
|
||||
const bool linear_color_format{is_color && !IsPixelFormatInteger(info.format)};
|
||||
const GLenum filter = linear_color_format ? GL_LINEAR : GL_NEAREST;
|
||||
|
||||
const auto& resolution = runtime->resolution;
|
||||
const u32 scaled_width = resolution.ScaleUp(info.size.width);
|
||||
const u32 scaled_height = is_2d ? resolution.ScaleUp(info.size.height) : info.size.height;
|
||||
const u32 original_width = info.size.width;
|
||||
const u32 original_height = info.size.height;
|
||||
|
||||
if (!upscaled_backup.handle) {
|
||||
auto dst_info = info;
|
||||
dst_info.size.width = scaled_width;
|
||||
dst_info.size.height = scaled_height;
|
||||
upscaled_backup = MakeImage(dst_info, gl_internal_format);
|
||||
}
|
||||
const u32 src_width = up_scale ? original_width : scaled_width;
|
||||
const u32 src_height = up_scale ? original_height : scaled_height;
|
||||
const u32 dst_width = up_scale ? scaled_width : original_width;
|
||||
const u32 dst_height = up_scale ? scaled_height : original_height;
|
||||
const auto src_handle = up_scale ? texture.handle : upscaled_backup.handle;
|
||||
const auto dst_handle = up_scale ? upscaled_backup.handle : texture.handle;
|
||||
|
||||
// TODO (ameerj): Investigate other GL states that affect blitting.
|
||||
glDisablei(GL_SCISSOR_TEST, 0);
|
||||
glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(dst_width),
|
||||
static_cast<GLfloat>(dst_height));
|
||||
|
||||
const GLuint read_fbo = runtime->rescale_read_fbos[fbo_index].handle;
|
||||
const GLuint draw_fbo = runtime->rescale_draw_fbos[fbo_index].handle;
|
||||
for (s32 layer = 0; layer < info.resources.layers; ++layer) {
|
||||
for (s32 level = 0; level < info.resources.levels; ++level) {
|
||||
const u32 src_level_width = std::max(1u, src_width >> level);
|
||||
const u32 src_level_height = std::max(1u, src_height >> level);
|
||||
const u32 dst_level_width = std::max(1u, dst_width >> level);
|
||||
const u32 dst_level_height = std::max(1u, dst_height >> level);
|
||||
|
||||
glNamedFramebufferTextureLayer(read_fbo, attachment, src_handle, level, layer);
|
||||
glNamedFramebufferTextureLayer(draw_fbo, attachment, dst_handle, level, layer);
|
||||
|
||||
glBlitNamedFramebuffer(read_fbo, draw_fbo, 0, 0, src_level_width, src_level_height, 0,
|
||||
0, dst_level_width, dst_level_height, mask, filter);
|
||||
}
|
||||
}
|
||||
current_texture = dst_handle;
|
||||
auto& state_tracker = runtime->GetStateTracker();
|
||||
state_tracker.NotifyViewport0();
|
||||
state_tracker.NotifyScissor0();
|
||||
}
|
||||
|
||||
bool Image::ScaleUp(bool ignore) {
|
||||
if (True(flags & ImageFlagBits::Rescaled)) {
|
||||
return false;
|
||||
}
|
||||
if (gl_format == 0 && gl_type == 0) {
|
||||
// compressed textures
|
||||
return false;
|
||||
}
|
||||
if (info.type == ImageType::Linear) {
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
flags |= ImageFlagBits::Rescaled;
|
||||
if (!runtime->resolution.active) {
|
||||
return false;
|
||||
}
|
||||
has_scaled = true;
|
||||
if (ignore) {
|
||||
current_texture = upscaled_backup.handle;
|
||||
return true;
|
||||
}
|
||||
Scale(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Image::ScaleDown(bool ignore) {
|
||||
if (False(flags & ImageFlagBits::Rescaled)) {
|
||||
return false;
|
||||
}
|
||||
flags &= ~ImageFlagBits::Rescaled;
|
||||
if (!runtime->resolution.active) {
|
||||
return false;
|
||||
}
|
||||
if (ignore) {
|
||||
current_texture = texture.handle;
|
||||
return true;
|
||||
}
|
||||
Scale(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info,
|
||||
ImageId image_id_, Image& image)
|
||||
: VideoCommon::ImageViewBase{info, image.info, image_id_}, views{runtime.null_image_views} {
|
||||
@@ -862,7 +1030,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
|
||||
flat_range = info.range;
|
||||
set_object_label = device.HasDebuggingToolAttached();
|
||||
is_render_target = info.IsRenderTarget();
|
||||
original_texture = image.texture.handle;
|
||||
original_texture = image.Handle();
|
||||
num_samples = image.info.num_samples;
|
||||
if (!is_render_target) {
|
||||
swizzle[0] = info.x_source;
|
||||
@@ -950,7 +1118,7 @@ ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info,
|
||||
const VideoCommon::ImageViewInfo& view_info)
|
||||
: VideoCommon::ImageViewBase{info, view_info} {}
|
||||
|
||||
ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::NullImageParams& params)
|
||||
ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::NullImageViewParams& params)
|
||||
: VideoCommon::ImageViewBase{params}, views{runtime.null_image_views} {}
|
||||
|
||||
GLuint ImageView::StorageView(Shader::TextureType texture_type, Shader::ImageFormat image_format) {
|
||||
@@ -1116,25 +1284,24 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM
|
||||
void BGRCopyPass::CopyBGR(Image& dst_image, Image& src_image,
|
||||
std::span<const VideoCommon::ImageCopy> copies) {
|
||||
static constexpr VideoCommon::Offset3D zero_offset{0, 0, 0};
|
||||
const u32 requested_pbo_size =
|
||||
std::max(src_image.unswizzled_size_bytes, dst_image.unswizzled_size_bytes);
|
||||
|
||||
if (bgr_pbo_size < requested_pbo_size) {
|
||||
bgr_pbo.Create();
|
||||
bgr_pbo_size = requested_pbo_size;
|
||||
glNamedBufferData(bgr_pbo.handle, bgr_pbo_size, nullptr, GL_STREAM_COPY);
|
||||
}
|
||||
const u32 img_bpp = BytesPerBlock(src_image.info.format);
|
||||
for (const ImageCopy& copy : copies) {
|
||||
ASSERT(copy.src_offset == zero_offset);
|
||||
ASSERT(copy.dst_offset == zero_offset);
|
||||
|
||||
const u32 num_src_layers = static_cast<u32>(copy.src_subresource.num_layers);
|
||||
const u32 copy_size = copy.extent.width * copy.extent.height * num_src_layers * img_bpp;
|
||||
if (bgr_pbo_size < copy_size) {
|
||||
bgr_pbo.Create();
|
||||
bgr_pbo_size = copy_size;
|
||||
glNamedBufferData(bgr_pbo.handle, bgr_pbo_size, nullptr, GL_STREAM_COPY);
|
||||
}
|
||||
// Copy from source to PBO
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, copy.extent.width);
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, bgr_pbo.handle);
|
||||
glGetTextureSubImage(src_image.Handle(), 0, 0, 0, 0, copy.extent.width, copy.extent.height,
|
||||
copy.src_subresource.num_layers, src_image.GlFormat(),
|
||||
src_image.GlType(), static_cast<GLsizei>(bgr_pbo_size), nullptr);
|
||||
num_src_layers, src_image.GlFormat(), src_image.GlType(),
|
||||
static_cast<GLsizei>(bgr_pbo_size), nullptr);
|
||||
|
||||
// Copy from PBO to destination in desired GL format
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
@@ -15,6 +15,10 @@
|
||||
#include "video_core/texture_cache/image_view_base.h"
|
||||
#include "video_core/texture_cache/texture_cache_base.h"
|
||||
|
||||
namespace Settings {
|
||||
struct ResolutionScalingInfo;
|
||||
}
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
class Device;
|
||||
@@ -80,7 +84,7 @@ public:
|
||||
|
||||
void CopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies);
|
||||
|
||||
void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view) {
|
||||
void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view, bool rescaled) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
@@ -110,6 +114,12 @@ public:
|
||||
|
||||
bool HasNativeASTC() const noexcept;
|
||||
|
||||
void TickFrame() {}
|
||||
|
||||
StateTracker& GetStateTracker() {
|
||||
return state_tracker;
|
||||
}
|
||||
|
||||
private:
|
||||
struct StagingBuffers {
|
||||
explicit StagingBuffers(GLenum storage_flags_, GLenum map_flags_);
|
||||
@@ -149,6 +159,10 @@ private:
|
||||
OGLTextureView null_image_view_cube;
|
||||
|
||||
std::array<GLuint, Shader::NUM_TEXTURE_TYPES> null_image_views{};
|
||||
|
||||
std::array<OGLFramebuffer, 3> rescale_draw_fbos;
|
||||
std::array<OGLFramebuffer, 3> rescale_read_fbos;
|
||||
const Settings::ResolutionScalingInfo& resolution;
|
||||
};
|
||||
|
||||
class Image : public VideoCommon::ImageBase {
|
||||
@@ -157,6 +171,7 @@ class Image : public VideoCommon::ImageBase {
|
||||
public:
|
||||
explicit Image(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, GPUVAddr gpu_addr,
|
||||
VAddr cpu_addr);
|
||||
explicit Image(const VideoCommon::NullImageParams&);
|
||||
|
||||
~Image();
|
||||
|
||||
@@ -174,7 +189,7 @@ public:
|
||||
GLuint StorageHandle() noexcept;
|
||||
|
||||
GLuint Handle() const noexcept {
|
||||
return texture.handle;
|
||||
return current_texture;
|
||||
}
|
||||
|
||||
GLuint GlFormat() const noexcept {
|
||||
@@ -185,16 +200,25 @@ public:
|
||||
return gl_type;
|
||||
}
|
||||
|
||||
bool ScaleUp(bool ignore = false);
|
||||
|
||||
bool ScaleDown(bool ignore = false);
|
||||
|
||||
private:
|
||||
void CopyBufferToImage(const VideoCommon::BufferImageCopy& copy, size_t buffer_offset);
|
||||
|
||||
void CopyImageToBuffer(const VideoCommon::BufferImageCopy& copy, size_t buffer_offset);
|
||||
|
||||
void Scale(bool up_scale);
|
||||
|
||||
OGLTexture texture;
|
||||
OGLTexture upscaled_backup;
|
||||
OGLTextureView store_view;
|
||||
GLenum gl_internal_format = GL_NONE;
|
||||
GLenum gl_format = GL_NONE;
|
||||
GLenum gl_type = GL_NONE;
|
||||
TextureCacheRuntime* runtime{};
|
||||
GLuint current_texture{};
|
||||
};
|
||||
|
||||
class ImageView : public VideoCommon::ImageViewBase {
|
||||
@@ -206,7 +230,7 @@ public:
|
||||
const VideoCommon::ImageViewInfo&, GPUVAddr);
|
||||
explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info,
|
||||
const VideoCommon::ImageViewInfo& view_info);
|
||||
explicit ImageView(TextureCacheRuntime&, const VideoCommon::NullImageParams&);
|
||||
explicit ImageView(TextureCacheRuntime&, const VideoCommon::NullImageViewParams&);
|
||||
|
||||
[[nodiscard]] GLuint StorageView(Shader::TextureType texture_type,
|
||||
Shader::ImageFormat image_format);
|
||||
|
@@ -21,8 +21,13 @@
|
||||
#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"
|
||||
#include "video_core/host_shaders/opengl_present_frag.h"
|
||||
#include "video_core/host_shaders/opengl_present_scaleforce_frag.h"
|
||||
#include "video_core/host_shaders/opengl_present_vert.h"
|
||||
#include "video_core/host_shaders/present_bicubic_frag.h"
|
||||
#include "video_core/host_shaders/present_gaussian_frag.h"
|
||||
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_manager.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_util.h"
|
||||
@@ -208,7 +213,9 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
|
||||
framebuffer_crop_rect = framebuffer.crop_rect;
|
||||
|
||||
const VAddr framebuffer_addr{framebuffer.address + framebuffer.offset};
|
||||
if (rasterizer.AccelerateDisplay(framebuffer, framebuffer_addr, framebuffer.stride)) {
|
||||
screen_info.was_accelerated =
|
||||
rasterizer.AccelerateDisplay(framebuffer, framebuffer_addr, framebuffer.stride);
|
||||
if (screen_info.was_accelerated) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -251,12 +258,25 @@ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color
|
||||
|
||||
void RendererOpenGL::InitOpenGLObjects() {
|
||||
// Create shader programs
|
||||
fxaa_vertex = CreateProgram(HostShaders::FXAA_VERT, GL_VERTEX_SHADER);
|
||||
fxaa_fragment = CreateProgram(HostShaders::FXAA_FRAG, GL_FRAGMENT_SHADER);
|
||||
present_vertex = CreateProgram(HostShaders::OPENGL_PRESENT_VERT, GL_VERTEX_SHADER);
|
||||
present_fragment = CreateProgram(HostShaders::OPENGL_PRESENT_FRAG, GL_FRAGMENT_SHADER);
|
||||
present_bilinear_fragment = CreateProgram(HostShaders::OPENGL_PRESENT_FRAG, GL_FRAGMENT_SHADER);
|
||||
present_bicubic_fragment = CreateProgram(HostShaders::PRESENT_BICUBIC_FRAG, GL_FRAGMENT_SHADER);
|
||||
present_gaussian_fragment =
|
||||
CreateProgram(HostShaders::PRESENT_GAUSSIAN_FRAG, GL_FRAGMENT_SHADER);
|
||||
present_scaleforce_fragment =
|
||||
CreateProgram(fmt::format("#version 460\n{}", HostShaders::OPENGL_PRESENT_SCALEFORCE_FRAG),
|
||||
GL_FRAGMENT_SHADER);
|
||||
|
||||
// Generate presentation sampler
|
||||
present_sampler.Create();
|
||||
glSamplerParameteri(present_sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(present_sampler.handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
present_sampler_nn.Create();
|
||||
glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glSamplerParameteri(present_sampler_nn.handle, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
// Generate VBO handle for drawing
|
||||
vertex_buffer.Create();
|
||||
@@ -274,6 +294,8 @@ void RendererOpenGL::InitOpenGLObjects() {
|
||||
|
||||
// Clear screen to black
|
||||
LoadColorToActiveGLTexture(0, 0, 0, 0, screen_info.texture);
|
||||
|
||||
fxaa_framebuffer.Create();
|
||||
}
|
||||
|
||||
void RendererOpenGL::AddTelemetryFields() {
|
||||
@@ -325,18 +347,130 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
|
||||
texture.resource.Release();
|
||||
texture.resource.Create(GL_TEXTURE_2D);
|
||||
glTextureStorage2D(texture.resource.handle, 1, internal_format, texture.width, texture.height);
|
||||
fxaa_texture.Release();
|
||||
fxaa_texture.Create(GL_TEXTURE_2D);
|
||||
glTextureStorage2D(fxaa_texture.handle, 1, GL_RGBA16F,
|
||||
Settings::values.resolution_info.ScaleUp(screen_info.texture.width),
|
||||
Settings::values.resolution_info.ScaleUp(screen_info.texture.height));
|
||||
glNamedFramebufferTexture(fxaa_framebuffer.handle, GL_COLOR_ATTACHMENT0, fxaa_texture.handle,
|
||||
0);
|
||||
}
|
||||
|
||||
void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
|
||||
// TODO: Signal state tracker about these changes
|
||||
state_tracker.NotifyScreenDrawVertexArray();
|
||||
state_tracker.NotifyPolygonModes();
|
||||
state_tracker.NotifyViewport0();
|
||||
state_tracker.NotifyScissor0();
|
||||
state_tracker.NotifyColorMask(0);
|
||||
state_tracker.NotifyBlend0();
|
||||
state_tracker.NotifyFramebuffer();
|
||||
state_tracker.NotifyFrontFace();
|
||||
state_tracker.NotifyCullTest();
|
||||
state_tracker.NotifyDepthTest();
|
||||
state_tracker.NotifyStencilTest();
|
||||
state_tracker.NotifyPolygonOffset();
|
||||
state_tracker.NotifyRasterizeEnable();
|
||||
state_tracker.NotifyFramebufferSRGB();
|
||||
state_tracker.NotifyLogicOp();
|
||||
state_tracker.NotifyClipControl();
|
||||
state_tracker.NotifyAlphaTest();
|
||||
|
||||
state_tracker.ClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
|
||||
|
||||
// Update background color before drawing
|
||||
glClearColor(Settings::values.bg_red.GetValue() / 255.0f,
|
||||
Settings::values.bg_green.GetValue() / 255.0f,
|
||||
Settings::values.bg_blue.GetValue() / 255.0f, 1.0f);
|
||||
|
||||
glEnable(GL_CULL_FACE);
|
||||
glDisable(GL_COLOR_LOGIC_OP);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
glDisable(GL_RASTERIZER_DISCARD);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glDisablei(GL_BLEND, 0);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
glCullFace(GL_BACK);
|
||||
glFrontFace(GL_CW);
|
||||
glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
|
||||
glBindTextureUnit(0, screen_info.display_texture);
|
||||
|
||||
if (Settings::values.anti_aliasing.GetValue() == Settings::AntiAliasing::Fxaa) {
|
||||
program_manager.BindPresentPrograms(fxaa_vertex.handle, fxaa_fragment.handle);
|
||||
|
||||
glEnablei(GL_SCISSOR_TEST, 0);
|
||||
auto viewport_width = screen_info.texture.width;
|
||||
auto scissor_width = framebuffer_crop_rect.GetWidth();
|
||||
if (scissor_width <= 0) {
|
||||
scissor_width = viewport_width;
|
||||
}
|
||||
auto viewport_height = screen_info.texture.height;
|
||||
auto scissor_height = framebuffer_crop_rect.GetHeight();
|
||||
if (scissor_height <= 0) {
|
||||
scissor_height = viewport_height;
|
||||
}
|
||||
if (screen_info.was_accelerated) {
|
||||
viewport_width = Settings::values.resolution_info.ScaleUp(viewport_width);
|
||||
scissor_width = Settings::values.resolution_info.ScaleUp(scissor_width);
|
||||
viewport_height = Settings::values.resolution_info.ScaleUp(viewport_height);
|
||||
scissor_height = Settings::values.resolution_info.ScaleUp(scissor_height);
|
||||
}
|
||||
glScissorIndexed(0, 0, 0, scissor_width, scissor_height);
|
||||
glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(viewport_width),
|
||||
static_cast<GLfloat>(viewport_height));
|
||||
glDepthRangeIndexed(0, 0.0, 0.0);
|
||||
|
||||
glBindSampler(0, present_sampler.handle);
|
||||
GLint old_read_fb;
|
||||
GLint old_draw_fb;
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb);
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fxaa_framebuffer.handle);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb);
|
||||
|
||||
glBindTextureUnit(0, fxaa_texture.handle);
|
||||
}
|
||||
|
||||
// Set projection matrix
|
||||
const std::array ortho_matrix =
|
||||
MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height));
|
||||
program_manager.BindPresentPrograms(present_vertex.handle, present_fragment.handle);
|
||||
|
||||
GLuint fragment_handle;
|
||||
const auto filter = Settings::values.scaling_filter.GetValue();
|
||||
switch (filter) {
|
||||
case Settings::ScalingFilter::NearestNeighbor:
|
||||
fragment_handle = present_bilinear_fragment.handle;
|
||||
break;
|
||||
case Settings::ScalingFilter::Bilinear:
|
||||
fragment_handle = present_bilinear_fragment.handle;
|
||||
break;
|
||||
case Settings::ScalingFilter::Bicubic:
|
||||
fragment_handle = present_bicubic_fragment.handle;
|
||||
break;
|
||||
case Settings::ScalingFilter::Gaussian:
|
||||
fragment_handle = present_gaussian_fragment.handle;
|
||||
break;
|
||||
case Settings::ScalingFilter::ScaleForce:
|
||||
fragment_handle = present_scaleforce_fragment.handle;
|
||||
break;
|
||||
case Settings::ScalingFilter::Fsr:
|
||||
LOG_WARNING(
|
||||
Render_OpenGL,
|
||||
"FidelityFX FSR Super Sampling is not supported in OpenGL, changing to ScaleForce");
|
||||
fragment_handle = present_scaleforce_fragment.handle;
|
||||
break;
|
||||
default:
|
||||
fragment_handle = present_bilinear_fragment.handle;
|
||||
break;
|
||||
}
|
||||
program_manager.BindPresentPrograms(present_vertex.handle, fragment_handle);
|
||||
glProgramUniformMatrix3x2fv(present_vertex.handle, ModelViewMatrixLocation, 1, GL_FALSE,
|
||||
ortho_matrix.data());
|
||||
|
||||
@@ -370,6 +504,11 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
|
||||
scale_v = static_cast<f32>(framebuffer_crop_rect.GetHeight()) /
|
||||
static_cast<f32>(screen_info.texture.height);
|
||||
}
|
||||
if (Settings::values.anti_aliasing.GetValue() == Settings::AntiAliasing::Fxaa &&
|
||||
!screen_info.was_accelerated) {
|
||||
scale_u /= Settings::values.resolution_info.up_factor;
|
||||
scale_v /= Settings::values.resolution_info.up_factor;
|
||||
}
|
||||
|
||||
const auto& screen = layout.screen;
|
||||
const std::array vertices = {
|
||||
@@ -380,47 +519,14 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
|
||||
};
|
||||
glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), std::data(vertices));
|
||||
|
||||
// TODO: Signal state tracker about these changes
|
||||
state_tracker.NotifyScreenDrawVertexArray();
|
||||
state_tracker.NotifyPolygonModes();
|
||||
state_tracker.NotifyViewport0();
|
||||
state_tracker.NotifyScissor0();
|
||||
state_tracker.NotifyColorMask(0);
|
||||
state_tracker.NotifyBlend0();
|
||||
state_tracker.NotifyFramebuffer();
|
||||
state_tracker.NotifyFrontFace();
|
||||
state_tracker.NotifyCullTest();
|
||||
state_tracker.NotifyDepthTest();
|
||||
state_tracker.NotifyStencilTest();
|
||||
state_tracker.NotifyPolygonOffset();
|
||||
state_tracker.NotifyRasterizeEnable();
|
||||
state_tracker.NotifyFramebufferSRGB();
|
||||
state_tracker.NotifyLogicOp();
|
||||
state_tracker.NotifyClipControl();
|
||||
state_tracker.NotifyAlphaTest();
|
||||
|
||||
state_tracker.ClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
|
||||
glEnable(GL_CULL_FACE);
|
||||
if (screen_info.display_srgb) {
|
||||
glEnable(GL_FRAMEBUFFER_SRGB);
|
||||
} else {
|
||||
glDisable(GL_FRAMEBUFFER_SRGB);
|
||||
}
|
||||
glDisable(GL_COLOR_LOGIC_OP);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
glDisable(GL_RASTERIZER_DISCARD);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glDisablei(GL_BLEND, 0);
|
||||
glDisablei(GL_SCISSOR_TEST, 0);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
glCullFace(GL_BACK);
|
||||
glFrontFace(GL_CW);
|
||||
glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(layout.width),
|
||||
static_cast<GLfloat>(layout.height));
|
||||
glDepthRangeIndexed(0, 0.0, 0.0);
|
||||
|
||||
glEnableVertexAttribArray(PositionLocation);
|
||||
glEnableVertexAttribArray(TexCoordLocation);
|
||||
@@ -440,8 +546,11 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
|
||||
glBindVertexBuffer(0, vertex_buffer.handle, 0, sizeof(ScreenRectVertex));
|
||||
}
|
||||
|
||||
glBindTextureUnit(0, screen_info.display_texture);
|
||||
glBindSampler(0, present_sampler.handle);
|
||||
if (Settings::values.scaling_filter.GetValue() != Settings::ScalingFilter::NearestNeighbor) {
|
||||
glBindSampler(0, present_sampler.handle);
|
||||
} else {
|
||||
glBindSampler(0, present_sampler_nn.handle);
|
||||
}
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
@@ -50,6 +50,7 @@ struct TextureInfo {
|
||||
/// Structure used for storing information about the display target for the Switch screen
|
||||
struct ScreenInfo {
|
||||
GLuint display_texture{};
|
||||
bool was_accelerated = false;
|
||||
bool display_srgb{};
|
||||
const Common::Rectangle<float> display_texcoords{0.0f, 0.0f, 1.0f, 1.0f};
|
||||
TextureInfo texture;
|
||||
@@ -109,9 +110,15 @@ private:
|
||||
|
||||
// OpenGL object IDs
|
||||
OGLSampler present_sampler;
|
||||
OGLSampler present_sampler_nn;
|
||||
OGLBuffer vertex_buffer;
|
||||
OGLProgram fxaa_vertex;
|
||||
OGLProgram fxaa_fragment;
|
||||
OGLProgram present_vertex;
|
||||
OGLProgram present_fragment;
|
||||
OGLProgram present_bilinear_fragment;
|
||||
OGLProgram present_bicubic_fragment;
|
||||
OGLProgram present_gaussian_fragment;
|
||||
OGLProgram present_scaleforce_fragment;
|
||||
OGLFramebuffer screenshot_framebuffer;
|
||||
|
||||
// GPU address of the vertex buffer
|
||||
@@ -119,6 +126,8 @@ private:
|
||||
|
||||
/// Display information for Switch screen
|
||||
ScreenInfo screen_info;
|
||||
OGLTexture fxaa_texture;
|
||||
OGLFramebuffer fxaa_framebuffer;
|
||||
|
||||
/// OpenGL framebuffer data
|
||||
std::vector<u8> gl_framebuffer_data;
|
||||
|
Reference in New Issue
Block a user