void INativeRenderTarget.GetData <T>(T[] buffer, ColorDataLayout dataLayout, ColorDataElementType dataElementType, int targetIndex, int x, int y, int width, int height)
        {
            DefaultOpenTKBackendPlugin.GuardSingleThreadState();

            NativeRenderTarget lastRt = BoundRT;

            Bind(this);
            {
                GL.ReadBuffer((ReadBufferMode)((int)ReadBufferMode.ColorAttachment0 + targetIndex));
                GL.ReadPixels(x, y, width, height, dataLayout.ToOpenTK(), dataElementType.ToOpenTK(), buffer);
                GL.ReadBuffer(ReadBufferMode.Back);
            }
            Bind(lastRt);
        }
        void IGraphicsBackend.GetOutputPixelData(IntPtr buffer, ColorDataLayout dataLayout, ColorDataElementType dataElementType, int x, int y, int width, int height)
        {
            DefaultOpenTKBackendPlugin.GuardSingleThreadState();

            NativeRenderTarget lastRt = NativeRenderTarget.BoundRT;

            NativeRenderTarget.Bind(null);
            {
                // Use a temporary local buffer, since the image will be upside-down because
                // of OpenGL's coordinate system and we'll need to flip it before returning.
                byte[] byteData = new byte[width * height * 4];

                // Retrieve pixel data
                GL.ReadPixels(x, y, width, height, dataLayout.ToOpenTK(), dataElementType.ToOpenTK(), byteData);

                // Flip the retrieved image vertically
                int    bytesPerLine = width * 4;
                byte[] switchLine   = new byte[width * 4];
                for (int flipY = 0; flipY < height / 2; flipY++)
                {
                    int lineIndex  = flipY * width * 4;
                    int lineIndex2 = (height - 1 - flipY) * width * 4;

                    // Copy the current line to the switch buffer
                    for (int lineX = 0; lineX < bytesPerLine; lineX++)
                    {
                        switchLine[lineX] = byteData[lineIndex + lineX];
                    }

                    // Copy the opposite line to the current line
                    for (int lineX = 0; lineX < bytesPerLine; lineX++)
                    {
                        byteData[lineIndex + lineX] = byteData[lineIndex2 + lineX];
                    }

                    // Copy the switch buffer to the opposite line
                    for (int lineX = 0; lineX < bytesPerLine; lineX++)
                    {
                        byteData[lineIndex2 + lineX] = switchLine[lineX];
                    }
                }

                // Copy the flipped data to the output buffer
                Marshal.Copy(byteData, 0, buffer, width * height * 4);
            }
            NativeRenderTarget.Bind(lastRt);
        }
Exemple #3
0
        private void CheckContextCaps()
        {
            if (this.contextCapsRetrieved)
            {
                return;
            }
            this.contextCapsRetrieved = true;

            Log.Core.Write("Determining OpenGL context capabilities...");
            Log.Core.PushIndent();

            // Make sure we're not on a render target, which may override
            // some settings that we'd like to get from the main contexts
            // backbuffer.
            NativeRenderTarget oldTarget = NativeRenderTarget.BoundRT;

            NativeRenderTarget.Bind(null);

            int targetSamples = this.defaultGraphicsMode.Samples;
            int actualSamples;

            // Retrieve how many MSAA samples are actually available, despite what
            // was offered and requested vis graphics mode.
            CheckOpenGLErrors(true);
            actualSamples = GL.GetInteger(GetPName.Samples);
            if (CheckOpenGLErrors())
            {
                actualSamples = targetSamples;
            }

            // If the sample count differs, mention it in the logs. If it is
            // actually zero, assume MSAA is driver-disabled.
            if (targetSamples != actualSamples)
            {
                Log.Core.Write("Requested {0} MSAA samples, but got {1} samples instead.", targetSamples, actualSamples);
                if (actualSamples == 0)
                {
                    this.msaaIsDriverDisabled = true;
                    Log.Core.Write("Assuming MSAA is unavailable. Duality will not use Alpha-to-Coverage masking techniques.");
                }
            }

            NativeRenderTarget.Bind(oldTarget);

            Log.Core.PopIndent();
        }
Exemple #4
0
 private static void ApplyGLBind(NativeRenderTarget target)
 {
     if (target == null)
     {
         GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, 0);
         GL.ReadBuffer(ReadBufferMode.Back);
         GL.DrawBuffer(DrawBufferMode.Back);
     }
     else
     {
         GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, target.samples > 0 ? target.handleMsaaFBO : target.handleMainFBO);
         DrawBuffersEnum[] buffers = new DrawBuffersEnum[target.targetInfos.Count];
         for (int i = 0; i < buffers.Length; i++)
         {
             buffers[i] = (DrawBuffersEnum)((int)DrawBuffersEnum.ColorAttachment0 + i);
         }
         GL.DrawBuffers(target.targetInfos.Count, buffers);
     }
 }
Exemple #5
0
        void IGraphicsBackend.GetOutputPixelData <T>(T[] buffer, ColorDataLayout dataLayout, ColorDataElementType dataElementType, int x, int y, int width, int height)
        {
            DefaultOpenTKBackendPlugin.GuardSingleThreadState();

            NativeRenderTarget lastRt = NativeRenderTarget.BoundRT;

            NativeRenderTarget.Bind(null);
            {
                GL.ReadPixels(x, y, width, height, dataLayout.ToOpenTK(), dataElementType.ToOpenTK(), buffer);

                // The image will be upside-down because of OpenGL's coordinate system. Flip it.
                int structSize = System.Runtime.InteropServices.Marshal.SizeOf(typeof(T));
                T[] switchLine = new T[width * 4 / structSize];
                for (int flipY = 0; flipY < height / 2; flipY++)
                {
                    int lineIndex  = flipY * width * 4 / structSize;
                    int lineIndex2 = (height - 1 - flipY) * width * 4 / structSize;

                    // Copy the current line to the switch buffer
                    for (int lineX = 0; lineX < width; lineX++)
                    {
                        switchLine[lineX] = buffer[lineIndex + lineX];
                    }

                    // Copy the opposite line to the current line
                    for (int lineX = 0; lineX < width; lineX++)
                    {
                        buffer[lineIndex + lineX] = buffer[lineIndex2 + lineX];
                    }

                    // Copy the switch buffer to the opposite line
                    for (int lineX = 0; lineX < width; lineX++)
                    {
                        buffer[lineIndex2 + lineX] = switchLine[lineX];
                    }
                }
            }
            NativeRenderTarget.Bind(lastRt);
        }
Exemple #6
0
        public static void Bind(NativeRenderTarget nextBound)
        {
            if (curBound == nextBound)
            {
                return;
            }

            // When binding a different target, execute pending post-render steps for the previous one
            if (curBound != null && curBound != nextBound)
            {
                curBound.ApplyPostRender();
            }

            // Bind new RenderTarget
            ApplyGLBind(nextBound);

            // Update binding info
            curBound = nextBound;
            if (curBound != null)
            {
                curBound.pendingPostRender = true;
            }
        }
Exemple #7
0
        void IGraphicsBackend.BeginRendering(IDrawDevice device, RenderOptions options, RenderStats stats)
        {
            DebugCheckOpenGLErrors();
            this.CheckContextCaps();

            this.currentDevice = device;
            this.renderStats   = stats;

            // Prepare the target surface for rendering
            NativeRenderTarget.Bind(options.Target as NativeRenderTarget);

            // Determine whether masked blending should use alpha-to-coverage mode
            if (this.msaaIsDriverDisabled)
            {
                this.useAlphaToCoverageBlend = false;
            }
            else if (NativeRenderTarget.BoundRT != null)
            {
                this.useAlphaToCoverageBlend = NativeRenderTarget.BoundRT.Samples > 0;
            }
            else if (this.activeWindow != null)
            {
                this.useAlphaToCoverageBlend = this.activeWindow.IsMultisampled;
            }
            else
            {
                this.useAlphaToCoverageBlend = this.defaultGraphicsMode.Samples > 0;
            }

            if (this.primaryVBO == 0)
            {
                GL.GenBuffers(1, out this.primaryVBO);
            }
            GL.BindBuffer(BufferTarget.ArrayBuffer, this.primaryVBO);

            // Setup viewport
            Rect viewportRect = options.Viewport;

            GL.Viewport((int)viewportRect.X, (int)viewportRect.Y, (int)viewportRect.W, (int)viewportRect.H);
            GL.Scissor((int)viewportRect.X, (int)viewportRect.Y, (int)viewportRect.W, (int)viewportRect.H);

            // Clear buffers
            ClearBufferMask glClearMask = 0;
            ColorRgba       clearColor  = options.ClearColor;

            if ((options.ClearFlags & ClearFlag.Color) != ClearFlag.None)
            {
                glClearMask |= ClearBufferMask.ColorBufferBit;
            }
            if ((options.ClearFlags & ClearFlag.Depth) != ClearFlag.None)
            {
                glClearMask |= ClearBufferMask.DepthBufferBit;
            }
            GL.ClearColor(clearColor.R / 255.0f, clearColor.G / 255.0f, clearColor.B / 255.0f, clearColor.A / 255.0f);
            GL.ClearDepth((double)options.ClearDepth);             // The "float version" is from OpenGL 4.1..
            GL.Clear(glClearMask);

            // Configure Rendering params
            if (options.RenderMode == RenderMatrix.OrthoScreen)
            {
                GL.Enable(EnableCap.ScissorTest);
                GL.Enable(EnableCap.DepthTest);
                GL.DepthFunc(DepthFunction.Always);
            }
            else
            {
                GL.Enable(EnableCap.ScissorTest);
                GL.Enable(EnableCap.DepthTest);
                GL.DepthFunc(DepthFunction.Lequal);
            }

            OpenTK.Matrix4 openTkModelView;
            Matrix4        modelView = options.ModelViewMatrix;

            GetOpenTKMatrix(ref modelView, out openTkModelView);

            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadMatrix(ref openTkModelView);

            OpenTK.Matrix4 openTkProjection;
            Matrix4        projection = options.ProjectionMatrix;

            GetOpenTKMatrix(ref projection, out openTkProjection);

            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadMatrix(ref openTkProjection);

            if (NativeRenderTarget.BoundRT != null)
            {
                if (options.RenderMode == RenderMatrix.OrthoScreen)
                {
                    GL.Translate(0.0f, viewportRect.H * 0.5f, 0.0f);
                }
                GL.Scale(1.0f, -1.0f, 1.0f);
                if (options.RenderMode == RenderMatrix.OrthoScreen)
                {
                    GL.Translate(0.0f, -viewportRect.H * 0.5f, 0.0f);
                }
            }
        }
Exemple #8
0
        public static void Bind(NativeRenderTarget nextBound)
        {
            if (curBound == nextBound)
            {
                return;
            }

            if (curBound != null && nextBound != curBound)
            {
                // Blit multisampled fbo
                if (curBound.samples > 0)
                {
                    GL.Ext.BindFramebuffer(FramebufferTarget.ReadFramebuffer, curBound.handleMsaaFBO);
                    GL.Ext.BindFramebuffer(FramebufferTarget.DrawFramebuffer, curBound.handleMainFBO);
                    for (int i = 0; i < curBound.targetInfos.Count; i++)
                    {
                        GL.ReadBuffer((ReadBufferMode)((int)ReadBufferMode.ColorAttachment0 + i));
                        GL.DrawBuffer((DrawBufferMode)((int)DrawBufferMode.ColorAttachment0 + i));
                        GL.Ext.BlitFramebuffer(
                            0, 0, curBound.targetInfos.Data[i].Target.Width, curBound.targetInfos.Data[i].Target.Height,
                            0, 0, curBound.targetInfos.Data[i].Target.Width, curBound.targetInfos.Data[i].Target.Height,
                            ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Nearest);
                    }
                    GL.ReadBuffer(ReadBufferMode.Back);
                    GL.DrawBuffer(DrawBufferMode.Back);
                    GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, 0);
                }

                // Generate Mipmaps for last bound
                for (int i = 0; i < curBound.targetInfos.Count; i++)
                {
                    if (curBound.targetInfos.Data[i].Target.HasMipmaps)
                    {
                        GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, 0);

                        int lastTexId;
                        GL.GetInteger(GetPName.TextureBinding2D, out lastTexId);

                        int texId = curBound.targetInfos.Data[i].Target.Handle;
                        if (lastTexId != texId)
                        {
                            GL.BindTexture(TextureTarget.Texture2D, texId);
                        }

                        GL.Ext.GenerateMipmap(GenerateMipmapTarget.Texture2D);

                        if (lastTexId != texId)
                        {
                            GL.BindTexture(TextureTarget.Texture2D, lastTexId);
                        }
                    }
                }
            }

            // Bind new RenderTarget
            if (nextBound == null)
            {
                curBound = null;
                GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, 0);
                GL.ReadBuffer(ReadBufferMode.Back);
                GL.DrawBuffer(DrawBufferMode.Back);
            }
            else
            {
                curBound = nextBound;
                GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, curBound.samples > 0 ? curBound.handleMsaaFBO : curBound.handleMainFBO);
                DrawBuffersEnum[] buffers = new DrawBuffersEnum[curBound.targetInfos.Count];
                for (int i = 0; i < buffers.Length; i++)
                {
                    buffers[i] = (DrawBuffersEnum)((int)DrawBuffersEnum.ColorAttachment0 + i);
                }
                GL.DrawBuffers(curBound.targetInfos.Count, buffers);
            }
        }
        void IGraphicsBackend.BeginRendering(IDrawDevice device, RenderOptions options, RenderStats stats)
        {
            DebugCheckOpenGLErrors();
            this.CheckRenderingCapabilities();

            this.currentDevice = device;
            this.renderOptions = options;
            this.renderStats   = stats;

            // Prepare a shared index buffer object, in case we don't have one yet
            if (this.sharedBatchIBO == null)
            {
                this.sharedBatchIBO = new NativeGraphicsBuffer(GraphicsBufferType.Index);
            }

            // Prepare the target surface for rendering
            NativeRenderTarget.Bind(options.Target as NativeRenderTarget);

            // Determine whether masked blending should use alpha-to-coverage mode
            if (this.msaaIsDriverDisabled)
            {
                this.useAlphaToCoverageBlend = false;
            }
            else if (NativeRenderTarget.BoundRT != null)
            {
                this.useAlphaToCoverageBlend = NativeRenderTarget.BoundRT.Samples > 0;
            }
            else if (this.activeWindow != null)
            {
                this.useAlphaToCoverageBlend = this.activeWindow.IsMultisampled;
            }
            else
            {
                this.useAlphaToCoverageBlend = this.defaultGraphicsMode.Samples > 0;
            }

            // Determine the available size on the active rendering surface
            Point2 availableSize;

            if (NativeRenderTarget.BoundRT != null)
            {
                availableSize = new Point2(NativeRenderTarget.BoundRT.Width, NativeRenderTarget.BoundRT.Height);
            }
            else if (this.activeWindow != null)
            {
                availableSize = new Point2(this.activeWindow.Width, this.activeWindow.Height);
            }
            else
            {
                availableSize = this.externalBackbufferSize;
            }

            // Translate viewport coordinates to OpenGL screen coordinates (borrom-left, rising), unless rendering
            // to a texture, which is laid out Duality-like (top-left, descending)
            Rect openGLViewport = options.Viewport;

            if (NativeRenderTarget.BoundRT == null)
            {
                openGLViewport.Y = (availableSize.Y - openGLViewport.H) - openGLViewport.Y;
            }

            // Setup viewport and scissor rects
            GL.Viewport((int)openGLViewport.X, (int)openGLViewport.Y, (int)MathF.Ceiling(openGLViewport.W), (int)MathF.Ceiling(openGLViewport.H));
            GL.Scissor((int)openGLViewport.X, (int)openGLViewport.Y, (int)MathF.Ceiling(openGLViewport.W), (int)MathF.Ceiling(openGLViewport.H));

            // Clear buffers
            ClearBufferMask glClearMask = 0;
            ColorRgba       clearColor  = options.ClearColor;

            if ((options.ClearFlags & ClearFlag.Color) != ClearFlag.None)
            {
                glClearMask |= ClearBufferMask.ColorBufferBit;
            }
            if ((options.ClearFlags & ClearFlag.Depth) != ClearFlag.None)
            {
                glClearMask |= ClearBufferMask.DepthBufferBit;
            }
            GL.ClearColor(clearColor.R / 255.0f, clearColor.G / 255.0f, clearColor.B / 255.0f, clearColor.A / 255.0f);
            GL.ClearDepth((double)options.ClearDepth);             // The "float version" is from OpenGL 4.1..
            GL.Clear(glClearMask);

            // Configure Rendering params
            GL.Enable(EnableCap.ScissorTest);
            GL.Enable(EnableCap.DepthTest);
            if (options.DepthTest)
            {
                GL.DepthFunc(DepthFunction.Lequal);
            }
            else
            {
                GL.DepthFunc(DepthFunction.Always);
            }

            // Prepare shared matrix stack for rendering
            Matrix4 viewMatrix       = options.ViewMatrix;
            Matrix4 projectionMatrix = options.ProjectionMatrix;

            if (NativeRenderTarget.BoundRT != null)
            {
                Matrix4 flipOutput = Matrix4.CreateScale(1.0f, -1.0f, 1.0f);
                projectionMatrix = projectionMatrix * flipOutput;
            }

            this.renderOptions.ShaderParameters.Set(
                BuiltinShaderFields.ViewMatrix,
                viewMatrix);
            this.renderOptions.ShaderParameters.Set(
                BuiltinShaderFields.ProjectionMatrix,
                projectionMatrix);
            this.renderOptions.ShaderParameters.Set(
                BuiltinShaderFields.ViewProjectionMatrix,
                viewMatrix * projectionMatrix);
        }
Exemple #10
0
        void IGraphicsBackend.BeginRendering(IDrawDevice device, RenderOptions options, RenderStats stats)
        {
            this.currentDevice = device;
            this.renderStats   = stats;

            // Prepare the target surface for rendering
            NativeRenderTarget.Bind(options.Target as NativeRenderTarget);

            if (this.primaryVBO == 0)
            {
                GL.GenBuffers(1, out this.primaryVBO);
            }
            GL.BindBuffer(BufferTarget.ArrayBuffer, this.primaryVBO);

            // Setup viewport
            Rect viewportRect = options.Viewport;

            GL.Viewport((int)viewportRect.X, (int)viewportRect.Y, (int)viewportRect.W, (int)viewportRect.H);
            GL.Scissor((int)viewportRect.X, (int)viewportRect.Y, (int)viewportRect.W, (int)viewportRect.H);

            // Clear buffers
            ClearBufferMask glClearMask = 0;
            ColorRgba       clearColor  = options.ClearColor;

            if ((options.ClearFlags & ClearFlag.Color) != ClearFlag.None)
            {
                glClearMask |= ClearBufferMask.ColorBufferBit;
            }
            if ((options.ClearFlags & ClearFlag.Depth) != ClearFlag.None)
            {
                glClearMask |= ClearBufferMask.DepthBufferBit;
            }
            GL.ClearColor(clearColor.R / 255.0f, clearColor.G / 255.0f, clearColor.B / 255.0f, clearColor.A / 255.0f);
            GL.ClearDepth((double)options.ClearDepth);             // The "float version" is from OpenGL 4.1..
            GL.Clear(glClearMask);

            // Configure Rendering params
            if (options.RenderMode == RenderMatrix.OrthoScreen)
            {
                GL.Enable(EnableCap.ScissorTest);
                GL.Enable(EnableCap.DepthTest);
                GL.DepthFunc(DepthFunction.Always);
            }
            else
            {
                GL.Enable(EnableCap.ScissorTest);
                GL.Enable(EnableCap.DepthTest);
                GL.DepthFunc(DepthFunction.Lequal);
            }

            OpenTK.Matrix4 openTkModelView;
            Matrix4        modelView = options.ModelViewMatrix;

            GetOpenTKMatrix(ref modelView, out openTkModelView);

            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadMatrix(ref openTkModelView);

            OpenTK.Matrix4 openTkProjection;
            Matrix4        projection = options.ProjectionMatrix;

            GetOpenTKMatrix(ref projection, out openTkProjection);

            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadMatrix(ref openTkProjection);

            if (NativeRenderTarget.BoundRT != null)
            {
                if (options.RenderMode == RenderMatrix.OrthoScreen)
                {
                    GL.Translate(0.0f, NativeRenderTarget.BoundRT.Height * 0.5f, 0.0f);
                }
                GL.Scale(1.0f, -1.0f, 1.0f);
                if (options.RenderMode == RenderMatrix.OrthoScreen)
                {
                    GL.Translate(0.0f, -NativeRenderTarget.BoundRT.Height * 0.5f, 0.0f);
                }
            }
        }