diff options
Diffstat (limited to 'src/video_core/renderer_opengl')
-rw-r--r-- | src/video_core/renderer_opengl/gl_buffer_cache.cpp | 3 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_buffer_cache.h | 2 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 66 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 3 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 28 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 14 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_manager.cpp | 10 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_manager.h | 9 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_state.cpp | 57 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_state.h | 10 |
10 files changed, 167 insertions, 35 deletions
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp index 075192c3f..46a6c0308 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp @@ -76,7 +76,7 @@ std::tuple<u8*, GLintptr> OGLBufferCache::ReserveMemory(std::size_t size, std::s return std::make_tuple(uploaded_ptr, uploaded_offset); } -void OGLBufferCache::Map(std::size_t max_size) { +bool OGLBufferCache::Map(std::size_t max_size) { bool invalidate; std::tie(buffer_ptr, buffer_offset_base, invalidate) = stream_buffer.Map(static_cast<GLsizeiptr>(max_size), 4); @@ -85,6 +85,7 @@ void OGLBufferCache::Map(std::size_t max_size) { if (invalidate) { InvalidateAll(); } + return invalidate; } void OGLBufferCache::Unmap() { diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h index 91fca3f6c..c11acfb79 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.h +++ b/src/video_core/renderer_opengl/gl_buffer_cache.h @@ -50,7 +50,7 @@ public: /// Reserves memory to be used by host's CPU. Returns mapped address and offset. std::tuple<u8*, GLintptr> ReserveMemory(std::size_t size, std::size_t alignment = 4); - void Map(std::size_t max_size); + bool Map(std::size_t max_size); void Unmap(); GLuint GetHandle() const; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 630a58e49..82b7a0649 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -176,15 +176,25 @@ void RasterizerOpenGL::SetupVertexFormat() { } state.draw.vertex_array = VAO.handle; state.ApplyVertexBufferState(); + + // Rebinding the VAO invalidates the vertex buffer bindings. + gpu.dirty_flags.vertex_array = 0xFFFFFFFF; } void RasterizerOpenGL::SetupVertexBuffer() { - MICROPROFILE_SCOPE(OpenGL_VB); - const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); + auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); const auto& regs = gpu.regs; + if (!gpu.dirty_flags.vertex_array) + return; + + MICROPROFILE_SCOPE(OpenGL_VB); + // Upload all guest vertex arrays sequentially to our buffer for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { + if (~gpu.dirty_flags.vertex_array & (1u << index)) + continue; + const auto& vertex_array = regs.vertex_array[index]; if (!vertex_array.IsEnabled()) continue; @@ -211,6 +221,8 @@ void RasterizerOpenGL::SetupVertexBuffer() { // Implicit set by glBindVertexBuffer. Stupid glstate handling... state.draw.vertex_buffer = buffer_cache.GetHandle(); + + gpu.dirty_flags.vertex_array = 0; } DrawParameters RasterizerOpenGL::SetupDraw() { @@ -600,7 +612,7 @@ void RasterizerOpenGL::DrawArrays() { return; MICROPROFILE_SCOPE(OpenGL_Drawing); - const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); + auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); const auto& regs = gpu.regs; ScopeAcquireGLContext acquire_context{emu_window}; @@ -620,7 +632,7 @@ void RasterizerOpenGL::DrawArrays() { SyncTransformFeedback(); SyncPointState(); CheckAlphaTests(); - + SyncPolygonOffset(); // TODO(bunnei): Sync framebuffer_scale uniform here // TODO(bunnei): Sync scissorbox uniform(s) here @@ -653,7 +665,11 @@ void RasterizerOpenGL::DrawArrays() { // Add space for at least 18 constant buffers buffer_size += Maxwell::MaxConstBuffers * (MaxConstbufferSize + uniform_buffer_alignment); - buffer_cache.Map(buffer_size); + bool invalidate = buffer_cache.Map(buffer_size); + if (invalidate) { + // As all cached buffers are invalidated, we need to recheck their state. + gpu.dirty_flags.vertex_array = 0xFFFFFFFF; + } SetupVertexFormat(); SetupVertexBuffer(); @@ -969,13 +985,25 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; - for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) { - const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()}; + const bool geometry_shaders_enabled = + regs.IsShaderConfigEnabled(static_cast<size_t>(Maxwell::ShaderProgram::Geometry)); + const std::size_t viewport_count = + geometry_shaders_enabled ? Tegra::Engines::Maxwell3D::Regs::NumViewports : 1; + for (std::size_t i = 0; i < viewport_count; i++) { auto& viewport = current_state.viewports[i]; - viewport.x = viewport_rect.left; - viewport.y = viewport_rect.bottom; - viewport.width = viewport_rect.GetWidth(); - viewport.height = viewport_rect.GetHeight(); + const auto& src = regs.viewports[i]; + if (regs.viewport_transform_enabled) { + const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()}; + viewport.x = viewport_rect.left; + viewport.y = viewport_rect.bottom; + viewport.width = viewport_rect.GetWidth(); + viewport.height = viewport_rect.GetHeight(); + } else { + viewport.x = src.x; + viewport.y = src.y; + viewport.width = src.width; + viewport.height = src.height; + } viewport.depth_range_far = regs.viewports[i].depth_range_far; viewport.depth_range_near = regs.viewports[i].depth_range_near; } @@ -1149,7 +1177,11 @@ void RasterizerOpenGL::SyncLogicOpState() { void RasterizerOpenGL::SyncScissorTest(OpenGLState& current_state) { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; - for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) { + const bool geometry_shaders_enabled = + regs.IsShaderConfigEnabled(static_cast<size_t>(Maxwell::ShaderProgram::Geometry)); + const std::size_t viewport_count = + geometry_shaders_enabled ? Tegra::Engines::Maxwell3D::Regs::NumViewports : 1; + for (std::size_t i = 0; i < viewport_count; i++) { const auto& src = regs.scissor_test[i]; auto& dst = current_state.viewports[i].scissor; dst.enabled = (src.enable != 0); @@ -1179,6 +1211,16 @@ void RasterizerOpenGL::SyncPointState() { state.point.size = regs.point_size; } +void RasterizerOpenGL::SyncPolygonOffset() { + const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; + state.polygon_offset.fill_enable = regs.polygon_offset_fill_enable != 0; + state.polygon_offset.line_enable = regs.polygon_offset_line_enable != 0; + state.polygon_offset.point_enable = regs.polygon_offset_point_enable != 0; + state.polygon_offset.units = regs.polygon_offset_units; + state.polygon_offset.factor = regs.polygon_offset_factor; + state.polygon_offset.clamp = regs.polygon_offset_clamp; +} + void RasterizerOpenGL::CheckAlphaTests() { const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index f4354289c..dfb4616f2 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -183,6 +183,9 @@ private: /// Syncs Color Mask void SyncColorMask(); + /// Syncs the polygon offsets + void SyncPolygonOffset(); + /// Check asserts for alpha testing. void CheckAlphaTests(); diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 05fe2d370..0c4524d5c 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -520,7 +520,7 @@ public: switch (attribute) { case Attribute::Index::ClipDistances0123: case Attribute::Index::ClipDistances4567: { - const u64 index = attribute == Attribute::Index::ClipDistances4567 ? 4 : 0 + elem; + const u64 index = (attribute == Attribute::Index::ClipDistances4567 ? 4 : 0) + elem; UNIMPLEMENTED_IF_MSG( ((header.vtg.clip_distances >> index) & 1) == 0, "Shader is setting gl_ClipDistance{} without enabling it in the header", index); @@ -867,7 +867,8 @@ private: // vertex shader, and what's the value of the fourth element when inside a Tess Eval // shader. ASSERT(stage == Maxwell3D::Regs::ShaderStage::Vertex); - return "vec4(0, 0, uintBitsToFloat(instance_id.x), uintBitsToFloat(gl_VertexID))"; + // Config pack's first value is instance_id. + return "vec4(0, 0, uintBitsToFloat(config_pack[0]), uintBitsToFloat(gl_VertexID))"; case Attribute::Index::FrontFacing: // TODO(Subv): Find out what the values are for the other elements. ASSERT(stage == Maxwell3D::Regs::ShaderStage::Fragment); @@ -3400,6 +3401,10 @@ private: regs.SetRegisterToInteger(instr.gpr0, false, 0, predicate + " ? 0xFFFFFFFF : 0", 1, 1); } + if (instr.generates_cc.Value() != 0) { + regs.SetInternalFlag(InternalFlag::ZeroFlag, predicate); + LOG_WARNING(HW_GPU, "FSET Condition Code is incomplete"); + } break; } case OpCode::Type::IntegerSet: { @@ -3653,6 +3658,11 @@ private: regs.SetRegisterToInteger(instr.gpr0, false, 0, "0u", 1, 1); break; } + case Tegra::Shader::SystemVariable::Ydirection: { + // Config pack's third value is Y_NEGATE's state. + regs.SetRegisterToFloat(instr.gpr0, 0, "uintBitsToFloat(config_pack[2])", 1, 1); + break; + } default: { UNIMPLEMENTED_MSG("Unhandled system move: {}", static_cast<u32>(instr.sys20.Value())); @@ -3676,11 +3686,17 @@ private: "BRA with constant buffers are not implemented"); const Tegra::Shader::ConditionCode cc = instr.flow_condition_code; - UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, - "BRA condition code used: {}", static_cast<u32>(cc)); - const u32 target = offset + instr.bra.GetBranchTarget(); - shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }"); + if (cc != Tegra::Shader::ConditionCode::T) { + const std::string condition_code = regs.GetConditionCode(cc); + shader.AddLine("if (" + condition_code + "){"); + shader.scope++; + shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }"); + shader.scope--; + shader.AddLine('}'); + } else { + shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }"); + } break; } case OpCode::Id::IPA: { diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index eea090e52..23ed91e27 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -24,8 +24,7 @@ layout (location = 0) out vec4 position; layout(std140) uniform vs_config { vec4 viewport_flip; - uvec4 instance_id; - uvec4 flip_stage; + uvec4 config_pack; // instance_id, flip_stage, y_direction, padding uvec4 alpha_test; }; )"; @@ -63,7 +62,8 @@ void main() { out += R"( // Check if the flip stage is VertexB - if (flip_stage[0] == 1) { + // Config pack's second value is flip_stage + if (config_pack[1] == 1) { // Viewport can be flipped, which is unsupported by glViewport position.xy *= viewport_flip.xy; } @@ -71,7 +71,7 @@ void main() { // TODO(bunnei): This is likely a hack, position.w should be interpolated as 1.0 // For now, this is here to bring order in lieu of proper emulation - if (flip_stage[0] == 1) { + if (config_pack[1] == 1) { position.w = 1.0; } } @@ -101,8 +101,7 @@ layout (location = 0) out vec4 position; layout (std140) uniform gs_config { vec4 viewport_flip; - uvec4 instance_id; - uvec4 flip_stage; + uvec4 config_pack; // instance_id, flip_stage, y_direction, padding uvec4 alpha_test; }; @@ -139,8 +138,7 @@ layout (location = 0) in vec4 position; layout (std140) uniform fs_config { vec4 viewport_flip; - uvec4 instance_id; - uvec4 flip_stage; + uvec4 config_pack; // instance_id, flip_stage, y_direction, padding uvec4 alpha_test; }; diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp index 8b8869ecb..6a30c28d2 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.cpp +++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp @@ -27,16 +27,18 @@ void MaxwellUniformData::SetFromRegs(const Maxwell3D::State::ShaderStageInfo& sh alpha_test.func = func; alpha_test.ref = regs.alpha_test_ref; - // We only assign the instance to the first component of the vector, the rest is just padding. - instance_id[0] = state.current_instance; + instance_id = state.current_instance; // Assign in which stage the position has to be flipped // (the last stage before the fragment shader). if (gpu.regs.shader_config[static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry)].enable) { - flip_stage[0] = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry); + flip_stage = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry); } else { - flip_stage[0] = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::VertexB); + flip_stage = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::VertexB); } + + // Y_NEGATE controls what value S2R returns for the Y_DIRECTION system value. + y_direction = regs.screen_y_control.y_negate == 0 ? 1.f : -1.f; } } // namespace OpenGL::GLShader diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index 9a5d7e289..b757f5f44 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h @@ -21,8 +21,11 @@ using Tegra::Engines::Maxwell3D; struct MaxwellUniformData { void SetFromRegs(const Maxwell3D::State::ShaderStageInfo& shader_stage); alignas(16) GLvec4 viewport_flip; - alignas(16) GLuvec4 instance_id; - alignas(16) GLuvec4 flip_stage; + struct alignas(16) { + GLuint instance_id; + GLuint flip_stage; + GLfloat y_direction; + }; struct alignas(16) { GLuint enabled; GLuint func; @@ -30,7 +33,7 @@ struct MaxwellUniformData { GLuint padding; } alpha_test; }; -static_assert(sizeof(MaxwellUniformData) == 64, "MaxwellUniformData structure size is incorrect"); +static_assert(sizeof(MaxwellUniformData) == 48, "MaxwellUniformData structure size is incorrect"); static_assert(sizeof(MaxwellUniformData) < 16384, "MaxwellUniformData structure must be less than 16kb as per the OpenGL spec"); diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index 934f4db78..b3bfad6a0 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp @@ -92,6 +92,13 @@ OpenGLState::OpenGLState() { point.size = 1; fragment_color_clamp.enabled = false; + + polygon_offset.fill_enable = false; + polygon_offset.line_enable = false; + polygon_offset.point_enable = false; + polygon_offset.factor = 0.0f; + polygon_offset.units = 0.0f; + polygon_offset.clamp = 0.0f; } void OpenGLState::ApplyDefaultState() { @@ -406,6 +413,55 @@ void OpenGLState::ApplyLogicOp() const { } } +void OpenGLState::ApplyPolygonOffset() const { + + const bool fill_enable_changed = + polygon_offset.fill_enable != cur_state.polygon_offset.fill_enable; + const bool line_enable_changed = + polygon_offset.line_enable != cur_state.polygon_offset.line_enable; + const bool point_enable_changed = + polygon_offset.point_enable != cur_state.polygon_offset.point_enable; + const bool factor_changed = polygon_offset.factor != cur_state.polygon_offset.factor; + const bool units_changed = polygon_offset.units != cur_state.polygon_offset.units; + const bool clamp_changed = polygon_offset.clamp != cur_state.polygon_offset.clamp; + + if (fill_enable_changed) { + if (polygon_offset.fill_enable) { + glEnable(GL_POLYGON_OFFSET_FILL); + } else { + glDisable(GL_POLYGON_OFFSET_FILL); + } + } + + if (line_enable_changed) { + if (polygon_offset.line_enable) { + glEnable(GL_POLYGON_OFFSET_LINE); + } else { + glDisable(GL_POLYGON_OFFSET_LINE); + } + } + + if (point_enable_changed) { + if (polygon_offset.point_enable) { + glEnable(GL_POLYGON_OFFSET_POINT); + } else { + glDisable(GL_POLYGON_OFFSET_POINT); + } + } + + if ((polygon_offset.fill_enable || polygon_offset.line_enable || polygon_offset.point_enable) && + (factor_changed || units_changed || clamp_changed)) { + + if (GLAD_GL_EXT_polygon_offset_clamp && polygon_offset.clamp != 0) { + glPolygonOffsetClamp(polygon_offset.factor, polygon_offset.units, polygon_offset.clamp); + } else { + glPolygonOffset(polygon_offset.factor, polygon_offset.units); + UNIMPLEMENTED_IF_MSG(polygon_offset.clamp != 0, + "Unimplemented Depth polygon offset clamp."); + } + } +} + void OpenGLState::ApplyTextures() const { for (std::size_t i = 0; i < std::size(texture_units); ++i) { const auto& texture_unit = texture_units[i]; @@ -532,6 +588,7 @@ void OpenGLState::Apply() const { ApplyLogicOp(); ApplyTextures(); ApplySamplers(); + ApplyPolygonOffset(); cur_state = *this; } diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 032fc43f0..0bf19ed07 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h @@ -176,6 +176,15 @@ public: float size; // GL_POINT_SIZE } point; + struct { + bool point_enable; + bool line_enable; + bool fill_enable; + GLfloat units; + GLfloat factor; + GLfloat clamp; + } polygon_offset; + std::array<bool, 2> clip_distance; // GL_CLIP_DISTANCE OpenGLState(); @@ -226,6 +235,7 @@ private: void ApplyLogicOp() const; void ApplyTextures() const; void ApplySamplers() const; + void ApplyPolygonOffset() const; }; } // namespace OpenGL |