Skip to content

[OpenGL] Game.GraphicsContext.CommandList.SetScissorRectangle working differently on openGL #2827

@DockFrankenstein

Description

@DockFrankenstein

Release Type: Official Release
Version: 4.2.0.2381
Platform(s): Windows and Linux with OpenGL set as the renderer
Describe the bug
When using Myra, the screen becomes black if there is any ui being rendered. I am still not sure if it's an issue with Myra, but from what I've seen it's calling the same methods when rendering no matter what graphics api is being used. The critical part is in here where the scissor is being set again. The setter for that property calls a method in Stride Game.GraphicsContext.CommandList.SetScissorRectangle which makes the screen completely black. If we remove that single part, the renderer works just fine.

I am not too acquainted with this part of Stride, so I'm not sure what that method does in the first place. If anyone has any idea, I would appreciate if you chimed in.

To Reproduce
Steps to reproduce the behavior:

  1. Follow this guide to create a new project with Myra UI.
  2. Open MyGame.Windows.csproj file and add <StrideGraphicsApi>OpenGL</StrideGraphicsApi> in the same group as <TargetFramework>.
  3. Build the game and see a black screen

If you want to test out rendering without calling the faulty method, you can use this extension script and in MyraRenderer call desktop.RenderLinux instead of desktop.Render. You don't have to use Linux for this to work obviously.

using Myra.Graphics2D.UI;
using Myra.Graphics2D;
using Myra;
using System.Reflection;

namespace LD57.UiSystem
{
    public static partial class MyraExtensions
    {
        static MyraExtensions()
        {
            t_myraContext = typeof(Desktop).GetField("_renderContext", FIND_ANY_FLAGS);
            t_inputContext = typeof(Desktop).GetField("_inputContext", FIND_ANY_FLAGS);
            t_deviceScissor = typeof(RenderContext).GetProperty("DeviceScissor", FIND_ANY_FLAGS);
            t_childrenCopy = typeof(Desktop).GetProperty("ChildrenCopy", FIND_ANY_FLAGS);
            t_widgetProcessInput = typeof(Widget).GetMethod("ProcessInput", FIND_ANY_FLAGS);
            t_iem = typeof(Widget).Assembly.GetTypes().Where(x => x.FullName.Contains("InputEventsManager")).FirstOrDefault();
            t_processEvents = t_iem.GetMethod("ProcessEvents", FIND_ANY_FLAGS);
            t_queue = t_iem.GetMethod("Queue", FIND_ANY_FLAGS);
            t_layoutBounds = typeof(Desktop).GetProperty("LayoutBounds", FIND_ANY_FLAGS);
            t_transform = typeof(Desktop).GetProperty("Transform", FIND_ANY_FLAGS);
        }

        const BindingFlags FIND_ANY_FLAGS = BindingFlags.Instance |
            BindingFlags.Static |
            BindingFlags.NonPublic |
            BindingFlags.Public;

        private static FieldInfo t_myraContext;
        private static FieldInfo t_inputContext;
        private static PropertyInfo t_deviceScissor;
        private static PropertyInfo t_childrenCopy;
        private static MethodInfo t_widgetProcessInput;
        private static Type t_iem;
        private static MethodInfo t_processEvents;
        private static MethodInfo t_queue;
        private static PropertyInfo t_layoutBounds;
        private static PropertyInfo t_transform;

        public static void RenderLinux(this Desktop desktop)
        {
            var inputContext = (InputContext)t_inputContext.GetValue(desktop);

            desktop.UpdateLayout();
            desktop.UpdateInput();
            inputContext.Reset();

            foreach (var item in ((List<Widget>)t_childrenCopy.GetValue(desktop))
                .Reverse<Widget>())
            {
                t_widgetProcessInput.Invoke(item, [inputContext]);
            }

            if (inputContext.MouseWheelWidget != null)
            {
                t_queue.Invoke(null, [inputContext.MouseWheelWidget, 3]);
            }

            t_processEvents.Invoke(null, []);
            desktop.UpdateLayout();
            desktop.RenderVisualLinux();
        }

        public static void RenderVisualLinux(this Desktop desktop)
        {
            var layoutBounds = (Rectangle)t_layoutBounds.GetValue(desktop);
            var myraContext = (RenderContext)t_myraContext.GetValue(desktop);
            var scissors = (Rectangle)t_deviceScissor.GetValue(myraContext);
            myraContext.Begin();
            myraContext.Transform = (Transform)t_transform.GetValue(desktop);

            Rectangle rectangle = myraContext.Transform.Apply(layoutBounds);
            myraContext.Scissor = rectangle;
            myraContext.Opacity = desktop.Opacity;
            if (desktop.Background != null)
            {
                desktop.Background.Draw(myraContext, layoutBounds);
            }

            var widgetsCopy = (List<Widget>)t_childrenCopy.GetValue(desktop);

            foreach (var child in widgetsCopy)
            {
                if (child.Visible)
                {
                    child.InvalidateArrange();
                    child.InvalidateMeasure();
                    child.Arrange(layoutBounds);
                }
            }

            foreach (Widget item in widgetsCopy)
            {
                if (item.Visible)
                {
                    if (MyraEnvironment.EnableModalDarkening && item.IsModal)
                    {
                        myraContext.FillRectangle(rectangle, MyraEnvironment.DarkeningColor);
                    }

                    item.Render(myraContext);
                }
            }

            myraContext.End();
            myraContext.Flush();

            // This breaks on linux / OpenGL
            // t_deviceScissor.SetValue(myraContext, scissors);
        }
    }
}

Expected behavior
The ui and the rest of the game rendering the same as on the default Graphics API for Windows.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions