diff options
Diffstat (limited to 'src/video_core')
25 files changed, 350 insertions, 206 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 0b1cc1290..a780215c1 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -21,6 +21,7 @@ add_library(video_core STATIC macro_interpreter.h memory_manager.cpp memory_manager.h + rasterizer_cache.cpp rasterizer_cache.h rasterizer_interface.h renderer_base.cpp diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 2cd595f26..6de07ea56 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -53,6 +53,19 @@ void Maxwell3D::InitializeRegisterDefaults() { regs.independent_blend[blend_index].factor_source_a = Regs::Blend::Factor::One; regs.independent_blend[blend_index].factor_dest_a = Regs::Blend::Factor::Zero; } + regs.stencil_front_op_fail = Regs::StencilOp::Keep; + regs.stencil_front_op_zfail = Regs::StencilOp::Keep; + regs.stencil_front_op_zpass = Regs::StencilOp::Keep; + regs.stencil_front_func_func = Regs::ComparisonOp::Always; + regs.stencil_front_func_mask = 0xFFFFFFFF; + regs.stencil_front_mask = 0xFFFFFFFF; + regs.stencil_two_side_enable = 1; + regs.stencil_back_op_fail = Regs::StencilOp::Keep; + regs.stencil_back_op_zfail = Regs::StencilOp::Keep; + regs.stencil_back_op_zpass = Regs::StencilOp::Keep; + regs.stencil_back_func_func = Regs::ComparisonOp::Always; + regs.stencil_back_func_mask = 0xFFFFFFFF; + regs.stencil_back_mask = 0xFFFFFFFF; } void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) { @@ -108,7 +121,13 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) { debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandLoaded, nullptr); } - regs.reg_array[method] = value; + if (regs.reg_array[method] != value) { + regs.reg_array[method] = value; + if (method >= MAXWELL3D_REG_INDEX(vertex_attrib_format) && + method < MAXWELL3D_REG_INDEX(vertex_attrib_format) + regs.vertex_attrib_format.size()) { + dirty_flags.vertex_attrib_format = true; + } + } switch (method) { case MAXWELL3D_REG_INDEX(macros.data): { diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 0509ba3a2..91ca57883 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -345,6 +345,14 @@ public: Invert = 6, IncrWrap = 7, DecrWrap = 8, + KeepOGL = 0x1E00, + ZeroOGL = 0, + ReplaceOGL = 0x1E01, + IncrOGL = 0x1E02, + DecrOGL = 0x1E03, + InvertOGL = 0x150A, + IncrWrapOGL = 0x8507, + DecrWrapOGL = 0x8508, }; enum class MemoryLayout : u32 { @@ -1004,6 +1012,12 @@ public: State state{}; MemoryManager& memory_manager; + struct DirtyFlags { + bool vertex_attrib_format = true; + }; + + DirtyFlags dirty_flags; + /// Reads a register value located at the input method address u32 GetRegisterValue(u32 method) const; diff --git a/src/video_core/rasterizer_cache.cpp b/src/video_core/rasterizer_cache.cpp new file mode 100644 index 000000000..093b2cdf4 --- /dev/null +++ b/src/video_core/rasterizer_cache.cpp @@ -0,0 +1,7 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "video_core/rasterizer_cache.h" + +RasterizerCacheObject::~RasterizerCacheObject() = default; diff --git a/src/video_core/rasterizer_cache.h b/src/video_core/rasterizer_cache.h index 0a3b3951e..6d41321fa 100644 --- a/src/video_core/rasterizer_cache.h +++ b/src/video_core/rasterizer_cache.h @@ -10,13 +10,13 @@ #include <boost/range/iterator_range_core.hpp> #include "common/common_types.h" -#include "core/core.h" #include "core/settings.h" #include "video_core/rasterizer_interface.h" -#include "video_core/renderer_base.h" class RasterizerCacheObject { public: + virtual ~RasterizerCacheObject(); + /// Gets the address of the shader in guest memory, required for cache management virtual VAddr GetAddr() const = 0; @@ -64,6 +64,8 @@ class RasterizerCache : NonCopyable { friend class RasterizerCacheObject; public: + explicit RasterizerCache(VideoCore::RasterizerInterface& rasterizer) : rasterizer{rasterizer} {} + /// Write any cached resources overlapping the specified region back to memory void FlushRegion(Tegra::GPUVAddr addr, size_t size) { const auto& objects{GetSortedObjectsFromRegion(addr, size)}; @@ -109,14 +111,12 @@ protected: void Register(const T& object) { object->SetIsRegistered(true); object_cache.add({GetInterval(object), ObjectSet{object}}); - auto& rasterizer = Core::System::GetInstance().Renderer().Rasterizer(); rasterizer.UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), 1); } /// Unregisters an object from the cache void Unregister(const T& object) { object->SetIsRegistered(false); - auto& rasterizer = Core::System::GetInstance().Renderer().Rasterizer(); rasterizer.UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), -1); // Only flush if use_accurate_gpu_emulation is enabled, as it incurs a performance hit @@ -177,4 +177,5 @@ private: ObjectCache object_cache; ///< Cache of objects u64 modified_ticks{}; ///< Counter of cache state ticks, used for in-order flushing + VideoCore::RasterizerInterface& rasterizer; }; diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp index 0df3725c2..1482cdb40 100644 --- a/src/video_core/renderer_base.cpp +++ b/src/video_core/renderer_base.cpp @@ -5,7 +5,6 @@ #include "core/frontend/emu_window.h" #include "core/settings.h" #include "video_core/renderer_base.h" -#include "video_core/renderer_opengl/gl_rasterizer.h" namespace VideoCore { diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp index 41a54b3e7..075192c3f 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp @@ -9,10 +9,12 @@ #include "core/core.h" #include "core/memory.h" #include "video_core/renderer_opengl/gl_buffer_cache.h" +#include "video_core/renderer_opengl/gl_rasterizer.h" namespace OpenGL { -OGLBufferCache::OGLBufferCache(std::size_t size) : stream_buffer(GL_ARRAY_BUFFER, size) {} +OGLBufferCache::OGLBufferCache(RasterizerOpenGL& rasterizer, std::size_t size) + : RasterizerCache{rasterizer}, stream_buffer(GL_ARRAY_BUFFER, size) {} GLintptr OGLBufferCache::UploadMemory(Tegra::GPUVAddr gpu_addr, std::size_t size, std::size_t alignment, bool cache) { diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h index be29dc8be..91fca3f6c 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.h +++ b/src/video_core/renderer_opengl/gl_buffer_cache.h @@ -15,6 +15,8 @@ namespace OpenGL { +class RasterizerOpenGL; + struct CachedBufferEntry final : public RasterizerCacheObject { VAddr GetAddr() const override { return addr; @@ -35,7 +37,7 @@ struct CachedBufferEntry final : public RasterizerCacheObject { class OGLBufferCache final : public RasterizerCache<std::shared_ptr<CachedBufferEntry>> { public: - explicit OGLBufferCache(std::size_t size); + explicit OGLBufferCache(RasterizerOpenGL& rasterizer, std::size_t size); /// Uploads data from a guest GPU address. Returns host's buffer offset where it's been /// allocated. diff --git a/src/video_core/renderer_opengl/gl_primitive_assembler.cpp b/src/video_core/renderer_opengl/gl_primitive_assembler.cpp index 741f14bc3..d9ed08437 100644 --- a/src/video_core/renderer_opengl/gl_primitive_assembler.cpp +++ b/src/video_core/renderer_opengl/gl_primitive_assembler.cpp @@ -6,6 +6,7 @@ #include <array> #include "common/assert.h" #include "common/common_types.h" +#include "core/core.h" #include "core/memory.h" #include "video_core/renderer_opengl/gl_buffer_cache.h" #include "video_core/renderer_opengl/gl_primitive_assembler.h" diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index bb263b6aa..54cc47a9b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -33,7 +33,8 @@ using Maxwell = Tegra::Engines::Maxwell3D::Regs; using PixelFormat = VideoCore::Surface::PixelFormat; using SurfaceType = VideoCore::Surface::SurfaceType; -MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Array Setup", MP_RGB(128, 128, 192)); +MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Format Setup", MP_RGB(128, 128, 192)); +MICROPROFILE_DEFINE(OpenGL_VB, "OpenGL", "Vertex Buffer Setup", MP_RGB(128, 128, 192)); MICROPROFILE_DEFINE(OpenGL_Shader, "OpenGL", "Shader Setup", MP_RGB(128, 128, 192)); MICROPROFILE_DEFINE(OpenGL_UBO, "OpenGL", "Const Buffer Setup", MP_RGB(128, 128, 192)); MICROPROFILE_DEFINE(OpenGL_Index, "OpenGL", "Index Buffer Setup", MP_RGB(128, 128, 192)); @@ -79,7 +80,8 @@ struct DrawParameters { }; RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo& info) - : emu_window{window}, screen_info{info}, buffer_cache(STREAM_BUFFER_SIZE) { + : res_cache{*this}, shader_cache{*this}, emu_window{window}, screen_info{info}, + buffer_cache(*this, STREAM_BUFFER_SIZE) { // Create sampler objects for (std::size_t i = 0; i < texture_samplers.size(); ++i) { texture_samplers[i].Create(); @@ -122,18 +124,23 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo RasterizerOpenGL::~RasterizerOpenGL() {} -void RasterizerOpenGL::SetupVertexArrays() { - MICROPROFILE_SCOPE(OpenGL_VAO); - const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); +void RasterizerOpenGL::SetupVertexFormat() { + auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); const auto& regs = gpu.regs; + if (!gpu.dirty_flags.vertex_attrib_format) + return; + gpu.dirty_flags.vertex_attrib_format = false; + + MICROPROFILE_SCOPE(OpenGL_VAO); + auto [iter, is_cache_miss] = vertex_array_cache.try_emplace(regs.vertex_attrib_format); auto& VAO = iter->second; if (is_cache_miss) { VAO.Create(); state.draw.vertex_array = VAO.handle; - state.Apply(); + state.ApplyVertexBufferState(); // The index buffer binding is stored within the VAO. Stupid OpenGL, but easy to work // around. @@ -175,8 +182,13 @@ void RasterizerOpenGL::SetupVertexArrays() { } } state.draw.vertex_array = VAO.handle; - state.draw.vertex_buffer = buffer_cache.GetHandle(); - state.Apply(); + state.ApplyVertexBufferState(); +} + +void RasterizerOpenGL::SetupVertexBuffer() { + MICROPROFILE_SCOPE(OpenGL_VB); + const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); + const auto& regs = gpu.regs; // Upload all guest vertex arrays sequentially to our buffer for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { @@ -203,6 +215,9 @@ void RasterizerOpenGL::SetupVertexArrays() { glVertexBindingDivisor(index, 0); } } + + // Implicit set by glBindVertexBuffer. Stupid glstate handling... + state.draw.vertex_buffer = buffer_cache.GetHandle(); } DrawParameters RasterizerOpenGL::SetupDraw() { @@ -327,8 +342,6 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { index++; } } - - state.Apply(); } std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const { @@ -397,8 +410,8 @@ void RasterizerOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { cached_pages.add({pages_interval, delta}); } -void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_depth_fb, - bool preserve_contents, +void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool using_color_fb, + bool using_depth_fb, bool preserve_contents, std::optional<std::size_t> single_color_target) { MICROPROFILE_SCOPE(OpenGL_Framebuffer); const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; @@ -414,9 +427,9 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_dep ASSERT_MSG(regs.rt_separate_frag_data == 0, "Unimplemented"); // Bind the framebuffer surfaces - state.draw.draw_framebuffer = framebuffer.handle; - state.Apply(); - state.framebuffer_srgb.enabled = regs.framebuffer_srgb != 0; + current_state.draw.draw_framebuffer = framebuffer.handle; + current_state.ApplyFramebufferState(); + current_state.framebuffer_srgb.enabled = regs.framebuffer_srgb != 0; if (using_color_fb) { if (single_color_target) { @@ -494,10 +507,7 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_dep glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); } - - SyncViewport(); - - state.Apply(); + SyncViewport(current_state); } void RasterizerOpenGL::Clear() { @@ -510,22 +520,23 @@ void RasterizerOpenGL::Clear() { bool use_stencil{}; OpenGLState clear_state; - clear_state.draw.draw_framebuffer = framebuffer.handle; - clear_state.color_mask[0].red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE; - clear_state.color_mask[0].green_enabled = regs.clear_buffers.G ? GL_TRUE : GL_FALSE; - clear_state.color_mask[0].blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE; - clear_state.color_mask[0].alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE; - if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B || regs.clear_buffers.A) { use_color = true; } + if (use_color) { + clear_state.color_mask[0].red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE; + clear_state.color_mask[0].green_enabled = regs.clear_buffers.G ? GL_TRUE : GL_FALSE; + clear_state.color_mask[0].blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE; + clear_state.color_mask[0].alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE; + } if (regs.clear_buffers.Z) { ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear Z but buffer is not enabled!"); use_depth = true; // Always enable the depth write when clearing the depth buffer. The depth write mask is - // ignored when clearing the buffer in the Switch, but OpenGL obeys it so we set it to true. + // ignored when clearing the buffer in the Switch, but OpenGL obeys it so we set it to + // true. clear_state.depth.test_enabled = true; clear_state.depth.test_func = GL_ALWAYS; } @@ -542,11 +553,8 @@ void RasterizerOpenGL::Clear() { ScopeAcquireGLContext acquire_context{emu_window}; - ConfigureFramebuffers(use_color, use_depth || use_stencil, false, + ConfigureFramebuffers(clear_state, use_color, use_depth || use_stencil, false, regs.clear_buffers.RT.Value()); - // Copy the sRGB setting to the clear state to avoid problem with - // specific driver implementations - clear_state.framebuffer_srgb.enabled = state.framebuffer_srgb.enabled; clear_state.Apply(); if (use_color) { @@ -572,7 +580,7 @@ void RasterizerOpenGL::DrawArrays() { ScopeAcquireGLContext acquire_context{emu_window}; - ConfigureFramebuffers(); + ConfigureFramebuffers(state); SyncColorMask(); SyncDepthTestState(); SyncStencilTestState(); @@ -593,7 +601,7 @@ void RasterizerOpenGL::DrawArrays() { const bool is_indexed = accelerate_draw == AccelDraw::Indexed; state.draw.vertex_buffer = buffer_cache.GetHandle(); - state.Apply(); + state.ApplyVertexBufferState(); std::size_t buffer_size = CalculateVertexArraysSize(); @@ -620,7 +628,8 @@ void RasterizerOpenGL::DrawArrays() { buffer_cache.Map(buffer_size); - SetupVertexArrays(); + SetupVertexFormat(); + SetupVertexBuffer(); DrawParameters params = SetupDraw(); SetupShaders(params.primitive_mode); @@ -724,9 +733,9 @@ void RasterizerOpenGL::SamplerInfo::Create() { glSamplerParameteri(sampler.handle, GL_TEXTURE_COMPARE_FUNC, GL_NEVER); } -void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntry& config) { +void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::FullTextureInfo& info) { const GLuint s = sampler.handle; - + const Tegra::Texture::TSCEntry& config = info.tsc; if (mag_filter != config.mag_filter) { mag_filter = config.mag_filter; glSamplerParameteri( @@ -777,6 +786,22 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr glSamplerParameterfv(s, GL_TEXTURE_BORDER_COLOR, border_color.data()); } } + if (info.tic.use_header_opt_control == 0) { + if (GLAD_GL_ARB_texture_filter_anisotropic) { + glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY, + static_cast<float>(1 << info.tic.max_anisotropy.Value())); + } else if (GLAD_GL_EXT_texture_filter_anisotropic) { + glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY_EXT, + static_cast<float>(1 << info.tic.max_anisotropy.Value())); + } + glSamplerParameterf(s, GL_TEXTURE_MIN_LOD, + static_cast<float>(info.tic.res_min_mip_level.Value())); + glSamplerParameterf(s, GL_TEXTURE_MAX_LOD, + static_cast<float>(info.tic.res_max_mip_level.Value() == 0 + ? 16 + : info.tic.res_max_mip_level.Value())); + glSamplerParameterf(s, GL_TEXTURE_LOD_BIAS, info.tic.mip_lod_bias.Value() / 256.f); + } } u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shader, @@ -874,7 +899,7 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, continue; } - texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); + texture_samplers[current_bindpoint].SyncWithConfig(texture); Surface surface = res_cache.GetTextureSurface(texture, entry); if (surface != nullptr) { state.texture_units[current_bindpoint].texture = surface->Texture().handle; @@ -896,15 +921,15 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, return current_unit + static_cast<u32>(entries.size()); } -void RasterizerOpenGL::SyncViewport() { +void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()}; - auto& viewport = state.viewports[i]; + auto& viewport = current_state.viewports[i]; viewport.x = viewport_rect.left; viewport.y = viewport_rect.bottom; - viewport.width = static_cast<GLsizei>(viewport_rect.GetWidth()); - viewport.height = static_cast<GLsizei>(viewport_rect.GetHeight()); + viewport.width = static_cast<GLfloat>(viewport_rect.GetWidth()); + viewport.height = static_cast<GLfloat>(viewport_rect.GetHeight()); viewport.depth_range_far = regs.viewport[i].depth_range_far; viewport.depth_range_near = regs.viewport[i].depth_range_near; } @@ -969,9 +994,6 @@ void RasterizerOpenGL::SyncStencilTestState() { return; } - // TODO(bunnei): Verify behavior when this is not set - ASSERT(regs.stencil_two_side_enable); - state.stencil.front.test_func = MaxwellToGL::ComparisonOp(regs.stencil_front_func_func); state.stencil.front.test_ref = regs.stencil_front_func_ref; state.stencil.front.test_mask = regs.stencil_front_func_mask; @@ -979,14 +1001,23 @@ void RasterizerOpenGL::SyncStencilTestState() { state.stencil.front.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_front_op_zfail); state.stencil.front.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_front_op_zpass); state.stencil.front.write_mask = regs.stencil_front_mask; - - state.stencil.back.test_func = MaxwellToGL::ComparisonOp(regs.stencil_back_func_func); - state.stencil.back.test_ref = regs.stencil_back_func_ref; - state.stencil.back.test_mask = regs.stencil_back_func_mask; - state.stencil.back.action_stencil_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_fail); - state.stencil.back.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_zfail); - state.stencil.back.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_back_op_zpass); - state.stencil.back.write_mask = regs.stencil_back_mask; + if (regs.stencil_two_side_enable) { + state.stencil.back.test_func = MaxwellToGL::ComparisonOp(regs.stencil_back_func_func); + state.stencil.back.test_ref = regs.stencil_back_func_ref; + state.stencil.back.test_mask = regs.stencil_back_func_mask; + state.stencil.back.action_stencil_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_fail); + state.stencil.back.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_zfail); + state.stencil.back.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_back_op_zpass); + state.stencil.back.write_mask = regs.stencil_back_mask; + } else { + state.stencil.back.test_func = GL_ALWAYS; + state.stencil.back.test_ref = 0; + state.stencil.back.test_mask = 0xFFFFFFFF; + state.stencil.back.write_mask = 0xFFFFFFFF; + state.stencil.back.action_stencil_fail = GL_KEEP; + state.stencil.back.action_depth_fail = GL_KEEP; + state.stencil.back.action_depth_pass = GL_KEEP; + } } void RasterizerOpenGL::SyncColorMask() { @@ -1098,9 +1129,8 @@ void RasterizerOpenGL::CheckAlphaTests() { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; if (regs.alpha_test_enabled != 0 && regs.rt_control.count > 1) { - LOG_CRITICAL( - Render_OpenGL, - "Alpha Testing is enabled with Multiple Render Targets, this behavior is undefined."); + LOG_CRITICAL(Render_OpenGL, "Alpha Testing is enabled with Multiple Render Targets, " + "this behavior is undefined."); UNREACHABLE(); } } diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 60e783803..8ef0f6c12 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -88,7 +88,7 @@ private: /// SamplerInfo struct. void Create(); /// Syncs the sampler object with the config, updating any necessary state. - void SyncWithConfig(const Tegra::Texture::TSCEntry& config); + void SyncWithConfig(const Tegra::Texture::FullTextureInfo& info); private: Tegra::Texture::TextureFilter mag_filter; @@ -109,8 +109,8 @@ private: * @param preserve_contents If true, tries to preserve data from a previously used framebuffer. * @param single_color_target Specifies if a single color buffer target should be used. */ - void ConfigureFramebuffers(bool use_color_fb = true, bool using_depth_fb = true, - bool preserve_contents = true, + void ConfigureFramebuffers(OpenGLState& current_state, bool use_color_fb = true, + bool using_depth_fb = true, bool preserve_contents = true, std::optional<std::size_t> single_color_target = {}); /* @@ -134,7 +134,7 @@ private: GLenum primitive_mode, u32 current_unit); /// Syncs the viewport and depth range to match the guest state - void SyncViewport(); + void SyncViewport(OpenGLState& current_state); /// Syncs the clip enabled status to match the guest state void SyncClipEnabled(); @@ -207,7 +207,8 @@ private: std::size_t CalculateIndexBufferSize() const; - void SetupVertexArrays(); + void SetupVertexFormat(); + void SetupVertexBuffer(); DrawParameters SetupDraw(); diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index ada2e3859..26711e6f7 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -15,6 +15,7 @@ #include "core/memory.h" #include "core/settings.h" #include "video_core/engines/maxwell_3d.h" +#include "video_core/renderer_opengl/gl_rasterizer.h" #include "video_core/renderer_opengl/gl_rasterizer_cache.h" #include "video_core/renderer_opengl/gl_state.h" #include "video_core/renderer_opengl/utils.h" @@ -313,6 +314,8 @@ static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4_SRGB {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X5 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X5_SRGB + {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_10X8 + {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_10X8_SRGB // Depth formats {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F @@ -455,6 +458,8 @@ static constexpr GLConversionArray morton_to_gl_fns = { MortonCopy<true, PixelFormat::ASTC_2D_5X4_SRGB>, MortonCopy<true, PixelFormat::ASTC_2D_5X5>, MortonCopy<true, PixelFormat::ASTC_2D_5X5_SRGB>, + MortonCopy<true, PixelFormat::ASTC_2D_10X8>, + MortonCopy<true, PixelFormat::ASTC_2D_10X8_SRGB>, MortonCopy<true, PixelFormat::Z32F>, MortonCopy<true, PixelFormat::Z16>, MortonCopy<true, PixelFormat::Z24S8>, @@ -525,6 +530,8 @@ static constexpr GLConversionArray gl_to_morton_fns = { nullptr, nullptr, nullptr, + nullptr, + nullptr, MortonCopy<false, PixelFormat::Z32F>, MortonCopy<false, PixelFormat::Z16>, MortonCopy<false, PixelFormat::Z24S8>, @@ -579,7 +586,7 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface, state.draw.draw_framebuffer = draw_fb_handle; // Set sRGB enabled if the destination surfaces need it state.framebuffer_srgb.enabled = dst_params.srgb_conversion; - state.Apply(); + state.ApplyFramebufferState(); u32 buffers{}; @@ -928,7 +935,9 @@ static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelForma case PixelFormat::ASTC_2D_8X8_SRGB: case PixelFormat::ASTC_2D_8X5_SRGB: case PixelFormat::ASTC_2D_5X4_SRGB: - case PixelFormat::ASTC_2D_5X5_SRGB: { + case PixelFormat::ASTC_2D_5X5_SRGB: + case PixelFormat::ASTC_2D_10X8: + case PixelFormat::ASTC_2D_10X8_SRGB: { // Convert ASTC pixel formats to RGBA8, as most desktop GPUs do not support ASTC. u32 block_width{}; u32 block_height{}; @@ -963,7 +972,11 @@ static void ConvertFormatAsNeeded_FlushGLBuffer(std::vector<u8>& data, PixelForm case PixelFormat::ASTC_2D_4X4: case PixelFormat::ASTC_2D_8X8: case PixelFormat::ASTC_2D_4X4_SRGB: - case PixelFormat::ASTC_2D_8X8_SRGB: { + case PixelFormat::ASTC_2D_8X8_SRGB: + case PixelFormat::ASTC_2D_5X5: + case PixelFormat::ASTC_2D_5X5_SRGB: + case PixelFormat::ASTC_2D_10X8: + case PixelFormat::ASTC_2D_10X8_SRGB: { LOG_CRITICAL(HW_GPU, "Conversion of format {} after texture flushing is not implemented", static_cast<u32>(pixel_format)); UNREACHABLE(); @@ -1169,7 +1182,8 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle UploadGLMipmapTexture(i, read_fb_handle, draw_fb_handle); } -RasterizerCacheOpenGL::RasterizerCacheOpenGL() { +RasterizerCacheOpenGL::RasterizerCacheOpenGL(RasterizerOpenGL& rasterizer) + : RasterizerCache{rasterizer} { read_framebuffer.Create(); draw_framebuffer.Create(); copy_pbo.Create(); @@ -1331,6 +1345,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface, break; case SurfaceTarget::TextureCubemap: case SurfaceTarget::Texture3D: + case SurfaceTarget::Texture2DArray: case SurfaceTarget::TextureCubeArray: AccurateCopySurface(old_surface, new_surface); break; diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index c0b6bc4e6..494f6b903 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -264,6 +264,8 @@ struct hash<SurfaceReserveKey> { namespace OpenGL { +class RasterizerOpenGL; + class CachedSurface final : public RasterizerCacheObject { public: CachedSurface(const SurfaceParams& params); @@ -311,7 +313,7 @@ private: class RasterizerCacheOpenGL final : public RasterizerCache<Surface> { public: - RasterizerCacheOpenGL(); + explicit RasterizerCacheOpenGL(RasterizerOpenGL& rasterizer); /// Get a surface based on the texture configuration Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config, diff --git a/src/video_core/renderer_opengl/gl_resource_manager.cpp b/src/video_core/renderer_opengl/gl_resource_manager.cpp index 161318c5f..c17d5ac00 100644 --- a/src/video_core/renderer_opengl/gl_resource_manager.cpp +++ b/src/video_core/renderer_opengl/gl_resource_manager.cpp @@ -10,10 +10,8 @@ #include "video_core/renderer_opengl/gl_shader_util.h" #include "video_core/renderer_opengl/gl_state.h" -MICROPROFILE_DEFINE(OpenGL_ResourceCreation, "OpenGL", "Resource Creation", - MP_RGB(128, 128, 192)); -MICROPROFILE_DEFINE(OpenGL_ResourceDeletion, "OpenGL", "Resource Deletion", - MP_RGB(128, 128, 192)); +MICROPROFILE_DEFINE(OpenGL_ResourceCreation, "OpenGL", "Resource Creation", MP_RGB(128, 128, 192)); +MICROPROFILE_DEFINE(OpenGL_ResourceDeletion, "OpenGL", "Resource Deletion", MP_RGB(128, 128, 192)); namespace OpenGL { diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 9522fd344..a85a7c0c5 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -6,10 +6,10 @@ #include "core/core.h" #include "core/memory.h" #include "video_core/engines/maxwell_3d.h" +#include "video_core/renderer_opengl/gl_rasterizer.h" #include "video_core/renderer_opengl/gl_shader_cache.h" #include "video_core/renderer_opengl/gl_shader_manager.h" #include "video_core/renderer_opengl/utils.h" -#include "video_core/utils.h" namespace OpenGL { @@ -121,12 +121,16 @@ GLint CachedShader::GetUniformLocation(const GLShader::SamplerEntry& sampler) { } GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program, - const std::string& glsl_topology, + const std::string& glsl_topology, u32 max_vertices, const std::string& debug_name) { if (target_program.handle != 0) { return target_program.handle; } - const std::string source{geometry_programs.code + "layout (" + glsl_topology + ") in;\n"}; + std::string source = "#version 430 core\n"; + source += "layout (" + glsl_topology + ") in;\n"; + source += "#define MAX_VERTEX_INPUT " + std::to_string(max_vertices) + '\n'; + source += geometry_programs.code; + OGLShader shader; shader.Create(source.c_str(), GL_GEOMETRY_SHADER); target_program.Create(true, shader.handle); @@ -135,6 +139,8 @@ GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program, return target_program.handle; }; +ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer) : RasterizerCache{rasterizer} {} + Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) { const VAddr program_addr{GetShaderAddress(program)}; diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h index a210f1731..ffbf21831 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_cache.h @@ -16,6 +16,8 @@ namespace OpenGL { class CachedShader; +class RasterizerOpenGL; + using Shader = std::shared_ptr<CachedShader>; using Maxwell = Tegra::Engines::Maxwell3D::Regs; @@ -46,22 +48,23 @@ public: } switch (primitive_mode) { case GL_POINTS: - return LazyGeometryProgram(geometry_programs.points, "points", "ShaderPoints"); + return LazyGeometryProgram(geometry_programs.points, "points", 1, "ShaderPoints"); case GL_LINES: case GL_LINE_STRIP: - return LazyGeometryProgram(geometry_programs.lines, "lines", "ShaderLines"); + return LazyGeometryProgram(geometry_programs.lines, "lines", 2, "ShaderLines"); case GL_LINES_ADJACENCY: case GL_LINE_STRIP_ADJACENCY: - return LazyGeometryProgram(geometry_programs.lines_adjacency, "lines_adjacency", + return LazyGeometryProgram(geometry_programs.lines_adjacency, "lines_adjacency", 4, "ShaderLinesAdjacency"); case GL_TRIANGLES: case GL_TRIANGLE_STRIP: case GL_TRIANGLE_FAN: - return LazyGeometryProgram(geometry_programs.triangles, "triangles", "ShaderTriangles"); + return LazyGeometryProgram(geometry_programs.triangles, "triangles", 3, + "ShaderTriangles"); case GL_TRIANGLES_ADJACENCY: case GL_TRIANGLE_STRIP_ADJACENCY: return LazyGeometryProgram(geometry_programs.triangles_adjacency, "triangles_adjacency", - "ShaderLines"); + 6, "ShaderTrianglesAdjacency"); default: UNREACHABLE_MSG("Unknown primitive mode."); } @@ -76,7 +79,7 @@ public: private: /// Generates a geometry shader or returns one that already exists. GLuint LazyGeometryProgram(OGLProgram& target_program, const std::string& glsl_topology, - const std::string& debug_name); + u32 max_vertices, const std::string& debug_name); VAddr addr; Maxwell::ShaderProgram program_type; @@ -104,6 +107,8 @@ private: class ShaderCacheOpenGL final : public RasterizerCache<Shader> { public: + explicit ShaderCacheOpenGL(RasterizerOpenGL& rasterizer); + /// Gets the current specified shader stage program Shader GetStageProgram(Maxwell::ShaderProgram program); }; diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 09b003c59..5fde22ad4 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -494,10 +494,10 @@ public: // instruction for now. if (stage == Maxwell3D::Regs::ShaderStage::Geometry) { // TODO(Rodrigo): nouveau sets some attributes after setting emitting a geometry - // shader. These instructions use a dirty register as buffer index. To avoid some - // drivers from complaining for the out of boundary writes, guard them. - const std::string buf_index{"min(" + GetRegisterAsInteger(buf_reg) + ", " + - std::to_string(MAX_GEOMETRY_BUFFERS - 1) + ')'}; + // shader. These instructions use a dirty register as buffer index, to avoid some + // drivers from complaining about out of boundary writes, guard them. + const std::string buf_index{"((" + GetRegisterAsInteger(buf_reg) + ") % " + + std::to_string(MAX_GEOMETRY_BUFFERS) + ')'}; shader.AddLine("amem[" + buf_index + "][" + std::to_string(static_cast<u32>(attribute)) + ']' + GetSwizzle(elem) + " = " + src + ';'); @@ -811,7 +811,11 @@ private: std::optional<Register> vertex = {}) { auto GeometryPass = [&](const std::string& name) { if (stage == Maxwell3D::Regs::ShaderStage::Geometry && vertex) { - return "gs_" + name + '[' + GetRegisterAsInteger(*vertex, 0, false) + ']'; + // TODO(Rodrigo): Guard geometry inputs against out of bound reads. Some games set + // an 0x80000000 index for those and the shader fails to build. Find out why this + // happens and what's its intent. + return "gs_" + name + '[' + GetRegisterAsInteger(*vertex, 0, false) + + " % MAX_VERTEX_INPUT]"; } return name; }; @@ -2742,12 +2746,12 @@ private: } case 3: { if (is_array) { - UNIMPLEMENTED_MSG("3-coordinate arrays not fully implemented"); - const std::string x = regs.GetRegisterAsFloat(instr.gpr8); - const std::string y = regs.GetRegisterAsFloat(instr.gpr20); - coord = "vec2 coords = vec2(" + x + ", " + y + ");"; - texture_type = Tegra::Shader::TextureType::Texture2D; - is_array = false; + const std::string index = regs.GetRegisterAsInteger(instr.gpr8); + const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); + const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2); + const std::string z = regs.GetRegisterAsFloat(instr.gpr20); + coord = + "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + index + ");"; } else { const std::string x = regs.GetRegisterAsFloat(instr.gpr8); const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); @@ -2777,7 +2781,11 @@ private: break; } case Tegra::Shader::TextureProcessMode::LZ: { - texture = "textureLod(" + sampler + ", coords, 0.0)"; + if (depth_compare && is_array) { + texture = "texture(" + sampler + ", coords)"; + } else { + texture = "textureLod(" + sampler + ", coords, 0.0)"; + } break; } case Tegra::Shader::TextureProcessMode::LL: { diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 9d17edd63..eea090e52 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -82,8 +82,8 @@ void main() { } ProgramResult GenerateGeometryShader(const ShaderSetup& setup) { - std::string out = "#version 430 core\n"; - out += "#extension GL_ARB_separate_shader_objects : enable\n\n"; + // Version is intentionally skipped in shader generation, it's added by the lazy compilation. + std::string out = "#extension GL_ARB_separate_shader_objects : enable\n\n"; out += Decompiler::GetCommonDeclarations(); out += "bool exec_geometry();\n"; diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index 9517285e5..2635f2b0c 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp @@ -427,7 +427,7 @@ void OpenGLState::ApplySamplers() const { } } -void OpenGLState::Apply() const { +void OpenGLState::ApplyFramebufferState() const { // Framebuffer if (draw.read_framebuffer != cur_state.draw.read_framebuffer) { glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer); @@ -435,7 +435,9 @@ void OpenGLState::Apply() const { if (draw.draw_framebuffer != cur_state.draw.draw_framebuffer) { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, draw.draw_framebuffer); } +} +void OpenGLState::ApplyVertexBufferState() const { // Vertex array if (draw.vertex_array != cur_state.draw.vertex_array) { glBindVertexArray(draw.vertex_array); @@ -445,7 +447,11 @@ void OpenGLState::Apply() const { if (draw.vertex_buffer != cur_state.draw.vertex_buffer) { glBindBuffer(GL_ARRAY_BUFFER, draw.vertex_buffer); } +} +void OpenGLState::Apply() const { + ApplyFramebufferState(); + ApplyVertexBufferState(); // Uniform buffer if (draw.uniform_buffer != cur_state.draw.uniform_buffer) { glBindBuffer(GL_UNIFORM_BUFFER, draw.uniform_buffer); diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index b8cf1f637..eacca0b9c 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h @@ -181,6 +181,10 @@ public: } /// Apply this state as the current OpenGL state void Apply() const; + /// Apply only the state afecting the framebuffer + void ApplyFramebufferState() const; + /// Apply only the state afecting the vertex buffer + void ApplyVertexBufferState() const; /// Set the initial OpenGL state static void ApplyDefaultState(); /// Resets any references to the given resource diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index 87d511c38..3ce2cc6d2 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h @@ -159,10 +159,8 @@ inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode, } } } - LOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode={}", - static_cast<u32>(filter_mode)); - UNREACHABLE(); - return {}; + LOG_ERROR(Render_OpenGL, "Unimplemented texture filter mode={}", static_cast<u32>(filter_mode)); + return GL_LINEAR; } inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) { @@ -183,9 +181,8 @@ inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) { case Tegra::Texture::WrapMode::MirrorOnceClampToEdge: return GL_MIRROR_CLAMP_TO_EDGE; } - LOG_CRITICAL(Render_OpenGL, "Unimplemented texture wrap mode={}", static_cast<u32>(wrap_mode)); - UNREACHABLE(); - return {}; + LOG_ERROR(Render_OpenGL, "Unimplemented texture wrap mode={}", static_cast<u32>(wrap_mode)); + return GL_REPEAT; } inline GLenum DepthCompareFunc(Tegra::Texture::DepthCompareFunc func) { @@ -207,10 +204,9 @@ inline GLenum DepthCompareFunc(Tegra::Texture::DepthCompareFunc func) { case Tegra::Texture::DepthCompareFunc::Always: return GL_ALWAYS; } - LOG_CRITICAL(Render_OpenGL, "Unimplemented texture depth compare function ={}", - static_cast<u32>(func)); - UNREACHABLE(); - return {}; + LOG_ERROR(Render_OpenGL, "Unimplemented texture depth compare function ={}", + static_cast<u32>(func)); + return GL_GREATER; } inline GLenum BlendEquation(Maxwell::Blend::Equation equation) { @@ -226,9 +222,8 @@ inline GLenum BlendEquation(Maxwell::Blend::Equation equation) { case Maxwell::Blend::Equation::Max: return GL_MAX; } - LOG_CRITICAL(Render_OpenGL, "Unimplemented blend equation={}", static_cast<u32>(equation)); - UNREACHABLE(); - return {}; + LOG_ERROR(Render_OpenGL, "Unimplemented blend equation={}", static_cast<u32>(equation)); + return GL_FUNC_ADD; } inline GLenum BlendFunc(Maxwell::Blend::Factor factor) { @@ -291,9 +286,8 @@ inline GLenum BlendFunc(Maxwell::Blend::Factor factor) { case Maxwell::Blend::Factor::OneMinusConstantAlphaGL: return GL_ONE_MINUS_CONSTANT_ALPHA; } - LOG_CRITICAL(Render_OpenGL, "Unimplemented blend factor={}", static_cast<u32>(factor)); - UNREACHABLE(); - return {}; + LOG_ERROR(Render_OpenGL, "Unimplemented blend factor={}", static_cast<u32>(factor)); + return GL_ZERO; } inline GLenum SwizzleSource(Tegra::Texture::SwizzleSource source) { @@ -312,9 +306,8 @@ inline GLenum SwizzleSource(Tegra::Texture::SwizzleSource source) { case Tegra::Texture::SwizzleSource::OneFloat: return GL_ONE; } - LOG_CRITICAL(Render_OpenGL, "Unimplemented swizzle source={}", static_cast<u32>(source)); - UNREACHABLE(); - return {}; + LOG_ERROR(Render_OpenGL, "Unimplemented swizzle source={}", static_cast<u32>(source)); + return GL_ZERO; } inline GLenum ComparisonOp(Maxwell::ComparisonOp comparison) { @@ -344,33 +337,39 @@ inline GLenum ComparisonOp(Maxwell::ComparisonOp comparison) { case Maxwell::ComparisonOp::AlwaysOld: return GL_ALWAYS; } - LOG_CRITICAL(Render_OpenGL, "Unimplemented comparison op={}", static_cast<u32>(comparison)); - UNREACHABLE(); - return {}; + LOG_ERROR(Render_OpenGL, "Unimplemented comparison op={}", static_cast<u32>(comparison)); + return GL_ALWAYS; } inline GLenum StencilOp(Maxwell::StencilOp stencil) { switch (stencil) { case Maxwell::StencilOp::Keep: + case Maxwell::StencilOp::KeepOGL: return GL_KEEP; case Maxwell::StencilOp::Zero: + case Maxwell::StencilOp::ZeroOGL: return GL_ZERO; case Maxwell::StencilOp::Replace: + case Maxwell::StencilOp::ReplaceOGL: return GL_REPLACE; case Maxwell::StencilOp::Incr: + case Maxwell::StencilOp::IncrOGL: return GL_INCR; case Maxwell::StencilOp::Decr: + case Maxwell::StencilOp::DecrOGL: return GL_DECR; case Maxwell::StencilOp::Invert: + case Maxwell::StencilOp::InvertOGL: return GL_INVERT; case Maxwell::StencilOp::IncrWrap: + case Maxwell::StencilOp::IncrWrapOGL: return GL_INCR_WRAP; case Maxwell::StencilOp::DecrWrap: + case Maxwell::StencilOp::DecrWrapOGL: return GL_DECR_WRAP; } - LOG_CRITICAL(Render_OpenGL, "Unimplemented stencil op={}", static_cast<u32>(stencil)); - UNREACHABLE(); - return {}; + LOG_ERROR(Render_OpenGL, "Unimplemented stencil op={}", static_cast<u32>(stencil)); + return GL_KEEP; } inline GLenum FrontFace(Maxwell::Cull::FrontFace front_face) { @@ -380,9 +379,8 @@ inline GLenum FrontFace(Maxwell::Cull::FrontFace front_face) { case Maxwell::Cull::FrontFace::CounterClockWise: return GL_CCW; } - LOG_CRITICAL(Render_OpenGL, "Unimplemented front face cull={}", static_cast<u32>(front_face)); - UNREACHABLE(); - return {}; + LOG_ERROR(Render_OpenGL, "Unimplemented front face cull={}", static_cast<u32>(front_face)); + return GL_CCW; } inline GLenum CullFace(Maxwell::Cull::CullFace cull_face) { @@ -394,9 +392,8 @@ inline GLenum CullFace(Maxwell::Cull::CullFace cull_face) { case Maxwell::Cull::CullFace::FrontAndBack: return GL_FRONT_AND_BACK; } - LOG_CRITICAL(Render_OpenGL, "Unimplemented cull face={}", static_cast<u32>(cull_face)); - UNREACHABLE(); - return {}; + LOG_ERROR(Render_OpenGL, "Unimplemented cull face={}", static_cast<u32>(cull_face)); + return GL_BACK; } inline GLenum LogicOp(Maxwell::LogicOperation operation) { @@ -434,9 +431,8 @@ inline GLenum LogicOp(Maxwell::LogicOperation operation) { case Maxwell::LogicOperation::Set: return GL_SET; } - LOG_CRITICAL(Render_OpenGL, "Unimplemented logic operation={}", static_cast<u32>(operation)); - UNREACHABLE(); - return {}; + LOG_ERROR(Render_OpenGL, "Unimplemented logic operation={}", static_cast<u32>(operation)); + return GL_COPY; } } // namespace MaxwellToGL diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp index 051ad3964..9582dd2ca 100644 --- a/src/video_core/surface.cpp +++ b/src/video_core/surface.cpp @@ -306,6 +306,8 @@ PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format, return is_srgb ? PixelFormat::ASTC_2D_8X8_SRGB : PixelFormat::ASTC_2D_8X8; case Tegra::Texture::TextureFormat::ASTC_2D_8X5: return is_srgb ? PixelFormat::ASTC_2D_8X5_SRGB : PixelFormat::ASTC_2D_8X5; + case Tegra::Texture::TextureFormat::ASTC_2D_10X8: + return is_srgb ? PixelFormat::ASTC_2D_10X8_SRGB : PixelFormat::ASTC_2D_10X8; case Tegra::Texture::TextureFormat::R16_G16: switch (component_type) { case Tegra::Texture::ComponentType::FLOAT: @@ -453,6 +455,8 @@ bool IsPixelFormatASTC(PixelFormat format) { case PixelFormat::ASTC_2D_5X5_SRGB: case PixelFormat::ASTC_2D_8X8_SRGB: case PixelFormat::ASTC_2D_8X5_SRGB: + case PixelFormat::ASTC_2D_10X8: + case PixelFormat::ASTC_2D_10X8_SRGB: return true; default: return false; diff --git a/src/video_core/surface.h b/src/video_core/surface.h index dfdb8d122..0dd3eb2e4 100644 --- a/src/video_core/surface.h +++ b/src/video_core/surface.h @@ -74,19 +74,21 @@ enum class PixelFormat { ASTC_2D_5X4_SRGB = 56, ASTC_2D_5X5 = 57, ASTC_2D_5X5_SRGB = 58, + ASTC_2D_10X8 = 59, + ASTC_2D_10X8_SRGB = 60, MaxColorFormat, // Depth formats - Z32F = 59, - Z16 = 60, + Z32F = 61, + Z16 = 62, MaxDepthFormat, // DepthStencil formats - Z24S8 = 61, - S8Z24 = 62, - Z32FS8 = 63, + Z24S8 = 63, + S8Z24 = 64, + Z32FS8 = 65, MaxDepthStencilFormat, @@ -193,6 +195,8 @@ static constexpr u32 GetCompressionFactor(PixelFormat format) { 4, // ASTC_2D_5X4_SRGB 4, // ASTC_2D_5X5 4, // ASTC_2D_5X5_SRGB + 4, // ASTC_2D_10X8 + 4, // ASTC_2D_10X8_SRGB 1, // Z32F 1, // Z16 1, // Z24S8 @@ -208,70 +212,72 @@ static constexpr u32 GetDefaultBlockWidth(PixelFormat format) { if (format == PixelFormat::Invalid) return 0; constexpr std::array<u32, MaxPixelFormat> block_width_table = {{ - 1, // ABGR8U - 1, // ABGR8S - 1, // ABGR8UI - 1, // B5G6R5U - 1, // A2B10G10R10U - 1, // A1B5G5R5U - 1, // R8U - 1, // R8UI - 1, // RGBA16F - 1, // RGBA16U - 1, // RGBA16UI - 1, // R11FG11FB10F - 1, // RGBA32UI - 4, // DXT1 - 4, // DXT23 - 4, // DXT45 - 4, // DXN1 - 4, // DXN2UNORM - 4, // DXN2SNORM - 4, // BC7U - 4, // BC6H_UF16 - 4, // BC6H_SF16 - 4, // ASTC_2D_4X4 - 1, // G8R8U - 1, // G8R8S - 1, // BGRA8 - 1, // RGBA32F - 1, // RG32F - 1, // R32F - 1, // R16F - 1, // R16U - 1, // R16S - 1, // R16UI - 1, // R16I - 1, // RG16 - 1, // RG16F - 1, // RG16UI - 1, // RG16I - 1, // RG16S - 1, // RGB32F - 1, // RGBA8_SRGB - 1, // RG8U - 1, // RG8S - 1, // RG32UI - 1, // R32UI - 8, // ASTC_2D_8X8 - 8, // ASTC_2D_8X5 - 5, // ASTC_2D_5X4 - 1, // BGRA8_SRGB - 4, // DXT1_SRGB - 4, // DXT23_SRGB - 4, // DXT45_SRGB - 4, // BC7U_SRGB - 4, // ASTC_2D_4X4_SRGB - 8, // ASTC_2D_8X8_SRGB - 8, // ASTC_2D_8X5_SRGB - 5, // ASTC_2D_5X4_SRGB - 5, // ASTC_2D_5X5 - 5, // ASTC_2D_5X5_SRGB - 1, // Z32F - 1, // Z16 - 1, // Z24S8 - 1, // S8Z24 - 1, // Z32FS8 + 1, // ABGR8U + 1, // ABGR8S + 1, // ABGR8UI + 1, // B5G6R5U + 1, // A2B10G10R10U + 1, // A1B5G5R5U + 1, // R8U + 1, // R8UI + 1, // RGBA16F + 1, // RGBA16U + 1, // RGBA16UI + 1, // R11FG11FB10F + 1, // RGBA32UI + 4, // DXT1 + 4, // DXT23 + 4, // DXT45 + 4, // DXN1 + 4, // DXN2UNORM + 4, // DXN2SNORM + 4, // BC7U + 4, // BC6H_UF16 + 4, // BC6H_SF16 + 4, // ASTC_2D_4X4 + 1, // G8R8U + 1, // G8R8S + 1, // BGRA8 + 1, // RGBA32F + 1, // RG32F + 1, // R32F + 1, // R16F + 1, // R16U + 1, // R16S + 1, // R16UI + 1, // R16I + 1, // RG16 + 1, // RG16F + 1, // RG16UI + 1, // RG16I + 1, // RG16S + 1, // RGB32F + 1, // RGBA8_SRGB + 1, // RG8U + 1, // RG8S + 1, // RG32UI + 1, // R32UI + 8, // ASTC_2D_8X8 + 8, // ASTC_2D_8X5 + 5, // ASTC_2D_5X4 + 1, // BGRA8_SRGB + 4, // DXT1_SRGB + 4, // DXT23_SRGB + 4, // DXT45_SRGB + 4, // BC7U_SRGB + 4, // ASTC_2D_4X4_SRGB + 8, // ASTC_2D_8X8_SRGB + 8, // ASTC_2D_8X5_SRGB + 5, // ASTC_2D_5X4_SRGB + 5, // ASTC_2D_5X5 + 5, // ASTC_2D_5X5_SRGB + 10, // ASTC_2D_10X8 + 10, // ASTC_2D_10X8_SRGB + 1, // Z32F + 1, // Z16 + 1, // Z24S8 + 1, // S8Z24 + 1, // Z32FS8 }}; ASSERT(static_cast<std::size_t>(format) < block_width_table.size()); return block_width_table[static_cast<std::size_t>(format)]; @@ -341,6 +347,8 @@ static constexpr u32 GetDefaultBlockHeight(PixelFormat format) { 4, // ASTC_2D_5X4_SRGB 5, // ASTC_2D_5X5 5, // ASTC_2D_5X5_SRGB + 8, // ASTC_2D_10X8 + 8, // ASTC_2D_10X8_SRGB 1, // Z32F 1, // Z16 1, // Z24S8 @@ -416,6 +424,8 @@ static constexpr u32 GetFormatBpp(PixelFormat format) { 128, // ASTC_2D_5X4_SRGB 128, // ASTC_2D_5X5 128, // ASTC_2D_5X5_SRGB + 128, // ASTC_2D_10X8 + 128, // ASTC_2D_10X8_SRGB 32, // Z32F 16, // Z16 32, // Z24S8 diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index 3066abf61..a9d134d14 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp @@ -202,6 +202,8 @@ u32 BytesPerPixel(TextureFormat format) { case TextureFormat::ASTC_2D_5X4: case TextureFormat::ASTC_2D_8X8: case TextureFormat::ASTC_2D_8X5: + case TextureFormat::ASTC_2D_10X8: + case TextureFormat::ASTC_2D_5X5: case TextureFormat::A8R8G8B8: case TextureFormat::A2B10G10R10: case TextureFormat::BF10GF11RF11: @@ -294,6 +296,8 @@ std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat case TextureFormat::BC6H_SF16: case TextureFormat::ASTC_2D_4X4: case TextureFormat::ASTC_2D_8X8: + case TextureFormat::ASTC_2D_5X5: + case TextureFormat::ASTC_2D_10X8: case TextureFormat::A8R8G8B8: case TextureFormat::A2B10G10R10: case TextureFormat::A1B5G5R5: diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h index d12d2ecb8..e199d019a 100644 --- a/src/video_core/textures/texture.h +++ b/src/video_core/textures/texture.h @@ -168,20 +168,29 @@ struct TICEntry { // High 16 bits of the pitch value BitField<0, 16, u32> pitch_high; - + BitField<26, 1, u32> use_header_opt_control; + BitField<27, 1, u32> depth_texture; BitField<28, 4, u32> max_mip_level; }; union { BitField<0, 16, u32> width_minus_1; BitField<22, 1, u32> srgb_conversion; BitField<23, 4, TextureType> texture_type; + BitField<29, 3, u32> border_size; }; union { BitField<0, 16, u32> height_minus_1; BitField<16, 15, u32> depth_minus_1; }; + union { + BitField<6, 13, u32> mip_lod_bias; + BitField<27, 3, u32> max_anisotropy; + }; - INSERT_PADDING_BYTES(8); + union { + BitField<0, 4, u32> res_min_mip_level; + BitField<4, 4, u32> res_max_mip_level; + }; GPUVAddr Address() const { return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | address_low); |