Просмотр исходного кода

Merge branch 'master' into shader-purge

Rodrigo Locatti 6 лет назад
Родитель
Сommit
244fe13219

+ 1 - 0
externals/microprofile/microprofile.h

@@ -243,6 +243,7 @@ typedef uint32_t ThreadIdType;
 #define MICROPROFILE_DEFINE_GPU(var, name, color) MicroProfileToken g_mp_##var = MicroProfileGetToken("GPU", name, color, MicroProfileTokenTypeGpu)
 #define MICROPROFILE_TOKEN_PASTE0(a, b) a ## b
 #define MICROPROFILE_TOKEN_PASTE(a, b)  MICROPROFILE_TOKEN_PASTE0(a,b)
+#define MICROPROFILE_TOKEN(var) g_mp_##var
 #define MICROPROFILE_SCOPE(var) MicroProfileScopeHandler MICROPROFILE_TOKEN_PASTE(foo, __LINE__)(g_mp_##var)
 #define MICROPROFILE_SCOPE_TOKEN(token) MicroProfileScopeHandler MICROPROFILE_TOKEN_PASTE(foo, __LINE__)(token)
 #define MICROPROFILE_SCOPEI(group, name, color) static MicroProfileToken MICROPROFILE_TOKEN_PASTE(g_mp,__LINE__) = MicroProfileGetToken(group, name, color, MicroProfileTokenTypeCpu); MicroProfileScopeHandler MICROPROFILE_TOKEN_PASTE(foo,__LINE__)( MICROPROFILE_TOKEN_PASTE(g_mp,__LINE__))

+ 17 - 3
src/audio_core/cubeb_sink.cpp

@@ -8,6 +8,7 @@
 #include "audio_core/cubeb_sink.h"
 #include "audio_core/stream.h"
 #include "audio_core/time_stretch.h"
+#include "common/assert.h"
 #include "common/logging/log.h"
 #include "common/ring_buffer.h"
 #include "core/settings.h"
@@ -65,12 +66,25 @@ public:
     void EnqueueSamples(u32 source_num_channels, const std::vector<s16>& samples) override {
         if (source_num_channels > num_channels) {
             // Downsample 6 channels to 2
+            ASSERT_MSG(source_num_channels == 6, "Channel count must be 6");
+
             std::vector<s16> buf;
             buf.reserve(samples.size() * num_channels / source_num_channels);
             for (std::size_t i = 0; i < samples.size(); i += source_num_channels) {
-                for (std::size_t ch = 0; ch < num_channels; ch++) {
-                    buf.push_back(samples[i + ch]);
-                }
+                // Downmixing implementation taken from the ATSC standard
+                const s16 left{samples[i + 0]};
+                const s16 right{samples[i + 1]};
+                const s16 center{samples[i + 2]};
+                const s16 surround_left{samples[i + 4]};
+                const s16 surround_right{samples[i + 5]};
+                // Not used in the ATSC reference implementation
+                [[maybe_unused]] const s16 low_frequency_effects { samples[i + 3] };
+
+                constexpr s32 clev{707}; // center mixing level coefficient
+                constexpr s32 slev{707}; // surround mixing level coefficient
+
+                buf.push_back(left + (clev * center / 1000) + (slev * surround_left / 1000));
+                buf.push_back(right + (clev * center / 1000) + (slev * surround_right / 1000));
             }
             queue.Push(buf);
             return;

+ 2 - 2
src/core/frontend/framebuffer_layout.cpp

@@ -48,8 +48,8 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) {
     u32 width, height;
 
     if (Settings::values.use_docked_mode) {
-        width = ScreenDocked::WidthDocked * res_scale;
-        height = ScreenDocked::HeightDocked * res_scale;
+        width = ScreenDocked::Width * res_scale;
+        height = ScreenDocked::Height * res_scale;
     } else {
         width = ScreenUndocked::Width * res_scale;
         height = ScreenUndocked::Height * res_scale;

+ 8 - 8
src/core/frontend/framebuffer_layout.h

@@ -8,15 +8,15 @@
 
 namespace Layout {
 
-enum ScreenUndocked : u32 {
-    Width = 1280,
-    Height = 720,
-};
+namespace ScreenUndocked {
+constexpr u32 Width = 1280;
+constexpr u32 Height = 720;
+} // namespace ScreenUndocked
 
-enum ScreenDocked : u32 {
-    WidthDocked = 1920,
-    HeightDocked = 1080,
-};
+namespace ScreenDocked {
+constexpr u32 Width = 1920;
+constexpr u32 Height = 1080;
+} // namespace ScreenDocked
 
 enum class AspectRatio {
     Default,

+ 2 - 2
src/core/hle/service/nvflinger/nvflinger.cpp

@@ -191,8 +191,6 @@ void NVFlinger::Compose() {
         // Search for a queued buffer and acquire it
         auto buffer = buffer_queue.AcquireBuffer();
 
-        MicroProfileFlip();
-
         if (!buffer) {
             continue;
         }
@@ -206,6 +204,8 @@ void NVFlinger::Compose() {
             gpu.WaitFence(fence.id, fence.value);
         }
 
+        MicroProfileFlip();
+
         // Now send the buffer to the GPU for drawing.
         // TODO(Subv): Support more than just disp0. The display device selection is probably based
         // on which display we're drawing (Default, Internal, External, etc)

+ 20 - 2
src/video_core/engines/maxwell_3d.h

@@ -525,6 +525,12 @@ public:
             FractionalEven = 2,
         };
 
+        enum class PolygonMode : u32 {
+            Point = 0x1b00,
+            Line = 0x1b01,
+            Fill = 0x1b02,
+        };
+
         struct RenderTargetConfig {
             u32 address_high;
             u32 address_low;
@@ -728,7 +734,12 @@ public:
 
                 s32 clear_stencil;
 
-                INSERT_UNION_PADDING_WORDS(0x7);
+                INSERT_UNION_PADDING_WORDS(0x2);
+
+                PolygonMode polygon_mode_front;
+                PolygonMode polygon_mode_back;
+
+                INSERT_UNION_PADDING_WORDS(0x3);
 
                 u32 polygon_offset_point_enable;
                 u32 polygon_offset_line_enable;
@@ -787,7 +798,11 @@ public:
                     BitField<12, 4, u32> viewport;
                 } clear_flags;
 
-                INSERT_UNION_PADDING_WORDS(0x19);
+                INSERT_UNION_PADDING_WORDS(0x10);
+
+                u32 fill_rectangle;
+
+                INSERT_UNION_PADDING_WORDS(0x8);
 
                 std::array<VertexAttribute, NumVertexAttributes> vertex_attrib_format;
 
@@ -1451,6 +1466,8 @@ ASSERT_REG_POSITION(depth_mode, 0x35F);
 ASSERT_REG_POSITION(clear_color[0], 0x360);
 ASSERT_REG_POSITION(clear_depth, 0x364);
 ASSERT_REG_POSITION(clear_stencil, 0x368);
+ASSERT_REG_POSITION(polygon_mode_front, 0x36B);
+ASSERT_REG_POSITION(polygon_mode_back, 0x36C);
 ASSERT_REG_POSITION(polygon_offset_point_enable, 0x370);
 ASSERT_REG_POSITION(polygon_offset_line_enable, 0x371);
 ASSERT_REG_POSITION(polygon_offset_fill_enable, 0x372);
@@ -1464,6 +1481,7 @@ ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB);
 ASSERT_REG_POSITION(depth_bounds, 0x3E7);
 ASSERT_REG_POSITION(zeta, 0x3F8);
 ASSERT_REG_POSITION(clear_flags, 0x43E);
+ASSERT_REG_POSITION(fill_rectangle, 0x44F);
 ASSERT_REG_POSITION(vertex_attrib_format, 0x458);
 ASSERT_REG_POSITION(rt_control, 0x487);
 ASSERT_REG_POSITION(zeta_width, 0x48a);

+ 42 - 2
src/video_core/renderer_opengl/gl_rasterizer.cpp

@@ -484,6 +484,7 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
 
     SyncViewport();
     SyncRasterizeEnable();
+    SyncPolygonModes();
     SyncColorMask();
     SyncFragmentColorClampState();
     SyncMultiSampleState();
@@ -562,7 +563,7 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
     bind_ubo_pushbuffer.Bind();
     bind_ssbo_pushbuffer.Bind();
 
-    program_manager.Update();
+    program_manager.BindGraphicsPipeline();
 
     if (texture_cache.TextureBarrier()) {
         glTextureBarrier();
@@ -619,7 +620,7 @@ void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) {
     auto kernel = shader_cache.GetComputeKernel(code_addr);
     SetupComputeTextures(kernel);
     SetupComputeImages(kernel);
-    glUseProgramStages(program_manager.GetHandle(), GL_COMPUTE_SHADER_BIT, kernel->GetHandle());
+    program_manager.BindComputeShader(kernel->GetHandle());
 
     const std::size_t buffer_size =
         Tegra::Engines::KeplerCompute::NumConstBuffers *
@@ -1089,6 +1090,45 @@ void RasterizerOpenGL::SyncRasterizeEnable() {
     oglEnable(GL_RASTERIZER_DISCARD, gpu.regs.rasterize_enable == 0);
 }
 
+void RasterizerOpenGL::SyncPolygonModes() {
+    auto& gpu = system.GPU().Maxwell3D();
+    auto& flags = gpu.dirty.flags;
+    if (!flags[Dirty::PolygonModes]) {
+        return;
+    }
+    flags[Dirty::PolygonModes] = false;
+
+    if (gpu.regs.fill_rectangle) {
+        if (!GLAD_GL_NV_fill_rectangle) {
+            LOG_ERROR(Render_OpenGL, "GL_NV_fill_rectangle used and not supported");
+            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+            return;
+        }
+
+        flags[Dirty::PolygonModeFront] = true;
+        flags[Dirty::PolygonModeBack] = true;
+        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL_RECTANGLE_NV);
+        return;
+    }
+
+    if (gpu.regs.polygon_mode_front == gpu.regs.polygon_mode_back) {
+        flags[Dirty::PolygonModeFront] = false;
+        flags[Dirty::PolygonModeBack] = false;
+        glPolygonMode(GL_FRONT_AND_BACK, MaxwellToGL::PolygonMode(gpu.regs.polygon_mode_front));
+        return;
+    }
+
+    if (flags[Dirty::PolygonModeFront]) {
+        flags[Dirty::PolygonModeFront] = false;
+        glPolygonMode(GL_FRONT, MaxwellToGL::PolygonMode(gpu.regs.polygon_mode_front));
+    }
+
+    if (flags[Dirty::PolygonModeBack]) {
+        flags[Dirty::PolygonModeBack] = false;
+        glPolygonMode(GL_BACK, MaxwellToGL::PolygonMode(gpu.regs.polygon_mode_back));
+    }
+}
+
 void RasterizerOpenGL::SyncColorMask() {
     auto& gpu = system.GPU().Maxwell3D();
     auto& flags = gpu.dirty.flags;

+ 3 - 0
src/video_core/renderer_opengl/gl_rasterizer.h

@@ -177,6 +177,9 @@ private:
     /// Syncs the rasterizer enable state to match the guest state
     void SyncRasterizeEnable();
 
+    /// Syncs polygon modes to match the guest state
+    void SyncPolygonModes();
+
     /// Syncs Color Mask
     void SyncColorMask();
 

+ 22 - 9
src/video_core/renderer_opengl/gl_shader_manager.cpp

@@ -2,21 +2,29 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include <glad/glad.h>
+
 #include "common/common_types.h"
 #include "video_core/engines/maxwell_3d.h"
 #include "video_core/renderer_opengl/gl_shader_manager.h"
 
 namespace OpenGL::GLShader {
 
-using Tegra::Engines::Maxwell3D;
+ProgramManager::ProgramManager() = default;
 
 ProgramManager::~ProgramManager() = default;
 
 void ProgramManager::Create() {
-    pipeline.Create();
+    graphics_pipeline.Create();
+    glBindProgramPipeline(graphics_pipeline.handle);
 }
 
-void ProgramManager::Update() {
+void ProgramManager::BindGraphicsPipeline() {
+    if (!is_graphics_bound) {
+        is_graphics_bound = true;
+        glUseProgram(0);
+    }
+
     // Avoid updating the pipeline when values have no changed
     if (old_state == current_state) {
         return;
@@ -25,16 +33,21 @@ void ProgramManager::Update() {
     // Workaround for AMD bug
     static constexpr GLenum all_used_stages{GL_VERTEX_SHADER_BIT | GL_GEOMETRY_SHADER_BIT |
                                             GL_FRAGMENT_SHADER_BIT};
-    glUseProgramStages(pipeline.handle, all_used_stages, 0);
-
-    glUseProgramStages(pipeline.handle, GL_VERTEX_SHADER_BIT, current_state.vertex_shader);
-    glUseProgramStages(pipeline.handle, GL_GEOMETRY_SHADER_BIT, current_state.geometry_shader);
-    glUseProgramStages(pipeline.handle, GL_FRAGMENT_SHADER_BIT, current_state.fragment_shader);
+    const GLuint handle = graphics_pipeline.handle;
+    glUseProgramStages(handle, all_used_stages, 0);
+    glUseProgramStages(handle, GL_VERTEX_SHADER_BIT, current_state.vertex_shader);
+    glUseProgramStages(handle, GL_GEOMETRY_SHADER_BIT, current_state.geometry_shader);
+    glUseProgramStages(handle, GL_FRAGMENT_SHADER_BIT, current_state.fragment_shader);
 
     old_state = current_state;
 }
 
-void MaxwellUniformData::SetFromRegs(const Maxwell3D& maxwell) {
+void ProgramManager::BindComputeShader(GLuint program) {
+    is_graphics_bound = false;
+    glUseProgram(program);
+}
+
+void MaxwellUniformData::SetFromRegs(const Tegra::Engines::Maxwell3D& maxwell) {
     const auto& regs = maxwell.regs;
 
     // Y_NEGATE controls what value S2R returns for the Y_DIRECTION system value.

+ 14 - 15
src/video_core/renderer_opengl/gl_shader_manager.h

@@ -28,11 +28,16 @@ static_assert(sizeof(MaxwellUniformData) < 16384,
 
 class ProgramManager {
 public:
+    explicit ProgramManager();
     ~ProgramManager();
 
     void Create();
 
-    void Update();
+    /// Updates the graphics pipeline and binds it.
+    void BindGraphicsPipeline();
+
+    /// Binds a compute shader.
+    void BindComputeShader(GLuint program);
 
     void UseVertexShader(GLuint program) {
         current_state.vertex_shader = program;
@@ -46,33 +51,27 @@ public:
         current_state.fragment_shader = program;
     }
 
-    GLuint GetHandle() const {
-        return pipeline.handle;
-    }
-
-    void UseTrivialFragmentShader() {
-        current_state.fragment_shader = 0;
-    }
-
 private:
     struct PipelineState {
-        bool operator==(const PipelineState& rhs) const {
+        bool operator==(const PipelineState& rhs) const noexcept {
             return vertex_shader == rhs.vertex_shader && fragment_shader == rhs.fragment_shader &&
                    geometry_shader == rhs.geometry_shader;
         }
 
-        bool operator!=(const PipelineState& rhs) const {
+        bool operator!=(const PipelineState& rhs) const noexcept {
             return !operator==(rhs);
         }
 
-        GLuint vertex_shader{};
-        GLuint fragment_shader{};
-        GLuint geometry_shader{};
+        GLuint vertex_shader = 0;
+        GLuint fragment_shader = 0;
+        GLuint geometry_shader = 0;
     };
 
-    OGLPipeline pipeline;
+    OGLPipeline graphics_pipeline;
+    OGLPipeline compute_pipeline;
     PipelineState current_state;
     PipelineState old_state;
+    bool is_graphics_bound = true;
 };
 
 } // namespace OpenGL::GLShader

+ 10 - 0
src/video_core/renderer_opengl/gl_state_tracker.cpp

@@ -94,6 +94,15 @@ void SetupDirtyShaders(Tables& tables) {
               Shaders);
 }
 
+void SetupDirtyPolygonModes(Tables& tables) {
+    tables[0][OFF(polygon_mode_front)] = PolygonModeFront;
+    tables[0][OFF(polygon_mode_back)] = PolygonModeBack;
+
+    tables[1][OFF(polygon_mode_front)] = PolygonModes;
+    tables[1][OFF(polygon_mode_back)] = PolygonModes;
+    tables[0][OFF(fill_rectangle)] = PolygonModes;
+}
+
 void SetupDirtyDepthTest(Tables& tables) {
     auto& table = tables[0];
     table[OFF(depth_test_enable)] = DepthTest;
@@ -211,6 +220,7 @@ void StateTracker::Initialize() {
     SetupDirtyVertexArrays(tables);
     SetupDirtyVertexFormat(tables);
     SetupDirtyShaders(tables);
+    SetupDirtyPolygonModes(tables);
     SetupDirtyDepthTest(tables);
     SetupDirtyStencilTest(tables);
     SetupDirtyAlphaTest(tables);

+ 11 - 0
src/video_core/renderer_opengl/gl_state_tracker.h

@@ -59,6 +59,10 @@ enum : u8 {
     Shaders,
     ClipDistances,
 
+    PolygonModes,
+    PolygonModeFront,
+    PolygonModeBack,
+
     ColorMask,
     FrontFace,
     CullTest,
@@ -111,6 +115,13 @@ public:
         flags[OpenGL::Dirty::VertexInstance0 + 1] = true;
     }
 
+    void NotifyPolygonModes() {
+        auto& flags = system.GPU().Maxwell3D().dirty.flags;
+        flags[OpenGL::Dirty::PolygonModes] = true;
+        flags[OpenGL::Dirty::PolygonModeFront] = true;
+        flags[OpenGL::Dirty::PolygonModeBack] = true;
+    }
+
     void NotifyViewport0() {
         auto& flags = system.GPU().Maxwell3D().dirty.flags;
         flags[OpenGL::Dirty::Viewports] = true;

+ 13 - 0
src/video_core/renderer_opengl/maxwell_to_gl.h

@@ -488,5 +488,18 @@ inline GLenum LogicOp(Maxwell::LogicOperation operation) {
     return GL_COPY;
 }
 
+inline GLenum PolygonMode(Maxwell::PolygonMode polygon_mode) {
+    switch (polygon_mode) {
+    case Maxwell::PolygonMode::Point:
+        return GL_POINT;
+    case Maxwell::PolygonMode::Line:
+        return GL_LINE;
+    case Maxwell::PolygonMode::Fill:
+        return GL_FILL;
+    }
+    UNREACHABLE_MSG("Invalid polygon mode={}", static_cast<int>(polygon_mode));
+    return GL_FILL;
+}
+
 } // namespace MaxwellToGL
 } // namespace OpenGL

+ 3 - 2
src/video_core/renderer_opengl/renderer_opengl.cpp

@@ -443,7 +443,6 @@ void RendererOpenGL::InitOpenGLObjects() {
 
     // Create program pipeline
     program_manager.Create();
-    glBindProgramPipeline(program_manager.GetHandle());
 
     // Generate VBO handle for drawing
     vertex_buffer.Create();
@@ -577,6 +576,7 @@ 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.NotifyColorMask0();
@@ -596,7 +596,7 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
     program_manager.UseVertexShader(vertex_program.handle);
     program_manager.UseGeometryShader(0);
     program_manager.UseFragmentShader(fragment_program.handle);
-    program_manager.Update();
+    program_manager.BindGraphicsPipeline();
 
     glEnable(GL_CULL_FACE);
     if (screen_info.display_srgb) {
@@ -612,6 +612,7 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
     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);

+ 8 - 1
src/video_core/renderer_vulkan/vk_rasterizer.cpp

@@ -854,7 +854,7 @@ void RasterizerVulkan::SetupGraphicsTextures(const ShaderEntries& entries, std::
 
 void RasterizerVulkan::SetupGraphicsImages(const ShaderEntries& entries, std::size_t stage) {
     MICROPROFILE_SCOPE(Vulkan_Images);
-    const auto& gpu = system.GPU().KeplerCompute();
+    const auto& gpu = system.GPU().Maxwell3D();
     for (const auto& entry : entries.images) {
         const auto tic = GetTextureInfo(gpu, entry, stage).tic;
         SetupImage(tic, entry);
@@ -915,6 +915,13 @@ void RasterizerVulkan::SetupComputeImages(const ShaderEntries& entries) {
 
 void RasterizerVulkan::SetupConstBuffer(const ConstBufferEntry& entry,
                                         const Tegra::Engines::ConstBufferInfo& buffer) {
+    if (!buffer.enabled) {
+        // Set values to zero to unbind buffers
+        update_descriptor_queue.AddBuffer(buffer_cache.GetEmptyBuffer(sizeof(float)), 0,
+                                          sizeof(float));
+        return;
+    }
+
     // Align the size to avoid bad std140 interactions
     const std::size_t size =
         Common::AlignUp(CalculateConstBufferSize(entry, buffer), 4 * sizeof(float));

+ 2 - 1
src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp

@@ -73,7 +73,8 @@ VKBuffer* VKStagingBufferPool::TryGetReservedBuffer(std::size_t size, bool host_
 VKBuffer& VKStagingBufferPool::CreateStagingBuffer(std::size_t size, bool host_visible) {
     const auto usage =
         vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst |
-        vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eIndexBuffer;
+        vk::BufferUsageFlagBits::eUniformBuffer | vk::BufferUsageFlagBits::eStorageBuffer |
+        vk::BufferUsageFlagBits::eIndexBuffer;
     const u32 log2 = Common::Log2Ceil64(size);
     const vk::BufferCreateInfo buffer_ci({}, 1ULL << log2, usage, vk::SharingMode::eExclusive, 0,
                                          nullptr);