예제 #1
0
        void IDisposable.Dispose()
        {
            if (DualityApp.ExecContext == DualityApp.ExecutionContext.Terminated)
            {
                return;
            }
            DefaultOpenTKBackendPlugin.GuardSingleThreadState();

            if (this.handleMainFBO != 0)
            {
                GL.Ext.DeleteFramebuffers(1, ref this.handleMainFBO);
                this.handleMainFBO = 0;
            }
            if (this.handleDepthRBO != 0)
            {
                GL.Ext.DeleteRenderbuffers(1, ref this.handleDepthRBO);
                this.handleDepthRBO = 0;
            }
            if (this.handleMsaaFBO != 0)
            {
                GL.Ext.DeleteFramebuffers(1, ref this.handleMsaaFBO);
                this.handleMsaaFBO = 0;
            }
            for (int i = 0; i < this.targetInfos.Count; i++)
            {
                if (this.targetInfos.Data[i].HandleMsaaColorRBO != 0)
                {
                    GL.Ext.DeleteRenderbuffers(1, ref this.targetInfos.Data[i].HandleMsaaColorRBO);
                    this.targetInfos.Data[i].HandleMsaaColorRBO = 0;
                }
            }
        }
예제 #2
0
        void IDualityBackend.Shutdown()
        {
            if (activeInstance == this)
            {
                activeInstance = null;
            }

            if (DualityApp.ExecContext != DualityApp.ExecutionContext.Terminated)
            {
                DefaultOpenTKBackendPlugin.GuardSingleThreadState();
                if (this.sharedBatchIBO != null)
                {
                    this.sharedBatchIBO.Dispose();
                    this.sharedBatchIBO = null;
                }
            }

            // Since the window outlives the graphics backend in the usual launcher setup,
            // we'll need to unhook early, so Duality can complete its cleanup before the window does.
            if (this.activeWindow != null)
            {
                this.activeWindow.UnhookFromDuality();
                this.activeWindow = null;
            }
        }
예제 #3
0
        void IDualityBackend.Init()
        {
            AudioLibraryLoader.LoadAudioLibrary();

            // Initialize OpenTK, if not done yet
            DefaultOpenTKBackendPlugin.InitOpenTK();

            Log.Core.Write("Available devices:" + Environment.NewLine + "{0}",
                           AudioContext.AvailableDevices.ToString(d => d == AudioContext.DefaultDevice ? d + " (Default)" : d, "," + Environment.NewLine));

            // Create OpenAL audio context
            this.context = new AudioContext();
            Log.Core.Write("Current device: {0}", this.context.CurrentDevice);

            // Create extension interfaces
            try
            {
                this.extFx = new EffectsExtension();
                if (!this.extFx.IsInitialized)
                {
                    this.extFx = null;
                }
            }
            catch (Exception)
            {
                this.extFx = null;
            }

            activeInstance = this;

            // Log all OpenAL specs for diagnostic purposes
            LogOpenALSpecs();

            // Generate OpenAL source pool
            for (int i = 0; i < 256; i++)
            {
                int newSrc = AL.GenSource();
                if (!Backend.DefaultOpenTK.AudioBackend.CheckOpenALErrors(true))
                {
                    this.sourcePool.Push(newSrc);
                }
                else
                {
                    break;
                }
            }
            this.availSources = this.sourcePool.Count;
            Log.Core.Write("{0} sources available", this.sourcePool.Count);

            // Set up the streaming thread
            this.streamWorkerEnd           = false;
            this.streamWorkerQueue         = new List <NativeAudioSource>();
            this.streamWorkerQueueEvent    = new AutoResetEvent(false);
            this.streamWorker              = new Thread(ThreadStreamFunc);
            this.streamWorker.IsBackground = true;
            this.streamWorker.Start();
        }
예제 #4
0
        void IDualityBackend.Init()
        {
            // Initialize OpenTK, if not done yet
            DefaultOpenTKBackendPlugin.InitOpenTK();

            // Determine available and default graphics modes
            this.QueryGraphicsModes();
            activeInstance = this;
        }
예제 #5
0
        void INativeShaderPart.LoadSource(string sourceCode, ShaderType type)
        {
            DefaultOpenTKBackendPlugin.GuardSingleThreadState();

            this.type = type;
            if (this.handle == 0)
            {
                this.handle = GL.CreateShader(GetOpenTKShaderType(type));
            }
            GL.ShaderSource(this.handle, sourceCode);
            GL.CompileShader(this.handle);

            // Log all errors and warnings from the info log
            string infoLog = GL.GetShaderInfoLog(this.handle);

            if (!string.IsNullOrWhiteSpace(infoLog))
            {
                using (StringReader reader = new StringReader(infoLog))
                {
                    while (true)
                    {
                        string line = reader.ReadLine();
                        if (line == null)
                        {
                            break;
                        }
                        if (string.IsNullOrWhiteSpace(line))
                        {
                            continue;
                        }

                        if (line.IndexOf("warning", StringComparison.InvariantCultureIgnoreCase) != -1)
                        {
                            Logs.Core.WriteWarning("{0}", line);
                        }
                        else if (line.IndexOf("error", StringComparison.InvariantCultureIgnoreCase) != -1)
                        {
                            Logs.Core.WriteError("{0}", line);
                        }
                        else
                        {
                            Logs.Core.Write("{0}", line);
                        }
                    }
                }
            }

            // If compilation failed, throw an exception
            int result;

            GL.GetShader(this.handle, ShaderParameter.CompileStatus, out result);
            if (result == 0)
            {
                throw new BackendException(string.Format("Failed to compile {0} shader:{2}{1}", type, infoLog, Environment.NewLine));
            }
        }
예제 #6
0
 void IDisposable.Dispose()
 {
     if (DualityApp.ExecContext != DualityApp.ExecutionContext.Terminated &&
         this.handle != 0)
     {
         DefaultOpenTKBackendPlugin.GuardSingleThreadState();
         GL.DeleteTexture(this.handle);
         this.handle = 0;
     }
 }
예제 #7
0
        public void ApplyPostRender()
        {
            DefaultOpenTKBackendPlugin.GuardSingleThreadState();

            if (!this.pendingPostRender)
            {
                return;
            }

            // Resolve multisampling to the main FBO
            if (this.samples > 0)
            {
                GL.Ext.BindFramebuffer(FramebufferTarget.ReadFramebuffer, this.handleMsaaFBO);
                GL.Ext.BindFramebuffer(FramebufferTarget.DrawFramebuffer, this.handleMainFBO);
                for (int i = 0; i < this.targetInfos.Count; i++)
                {
                    GL.ReadBuffer((ReadBufferMode)((int)ReadBufferMode.ColorAttachment0 + i));
                    GL.DrawBuffer((DrawBufferMode)((int)DrawBufferMode.ColorAttachment0 + i));
                    GL.Ext.BlitFramebuffer(
                        0, 0, this.targetInfos.Data[i].Target.Width, this.targetInfos.Data[i].Target.Height,
                        0, 0, this.targetInfos.Data[i].Target.Width, this.targetInfos.Data[i].Target.Height,
                        ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Nearest);
                }
            }

            // Generate mipmaps for the target textures
            int lastTexId = -1;

            for (int i = 0; i < this.targetInfos.Count; i++)
            {
                if (!this.targetInfos.Data[i].Target.HasMipmaps)
                {
                    continue;
                }

                if (lastTexId == -1)
                {
                    GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, 0);
                    GL.GetInteger(GetPName.TextureBinding2D, out lastTexId);
                }

                int texId = this.targetInfos.Data[i].Target.Handle;
                GL.BindTexture(TextureTarget.Texture2D, texId);
                GL.Ext.GenerateMipmap(GenerateMipmapTarget.Texture2D);
            }

            // Reset OpenGL state
            if (lastTexId != -1)
            {
                GL.BindTexture(TextureTarget.Texture2D, lastTexId);
            }
            ApplyGLBind(curBound);

            this.pendingPostRender = false;
        }
예제 #8
0
 public void Dispose()
 {
     if (DualityApp.ExecContext != DualityApp.ExecutionContext.Terminated &&
         this.handle != 0)
     {
         DefaultOpenTKBackendPlugin.GuardSingleThreadState();
         GL.DeleteBuffer(this.handle);
     }
     this.handle     = 0;
     this.bufferSize = 0;
 }
예제 #9
0
        void IDualityBackend.Init()
        {
            // Initialize OpenTK, if not done yet
            DefaultOpenTKBackendPlugin.InitOpenTK();

            // Log information about the available display devices
            GraphicsBackend.LogDisplayDevices();

            // Determine available and default graphics modes
            this.QueryGraphicsModes();
            activeInstance = this;
        }
예제 #10
0
        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);
        }
예제 #11
0
        void INativeTexture.GetData(IntPtr target, ColorDataLayout dataLayout, ColorDataElementType dataElementType)
        {
            DefaultOpenTKBackendPlugin.GuardSingleThreadState();

            int lastTexId;

            GL.GetInteger(GetPName.TextureBinding2D, out lastTexId);
            GL.BindTexture(TextureTarget.Texture2D, this.handle);

            GL.GetTexImage(TextureTarget.Texture2D, 0,
                           dataLayout.ToOpenTK(), dataElementType.ToOpenTK(),
                           target);

            GL.BindTexture(TextureTarget.Texture2D, lastTexId);
        }
예제 #12
0
        void INativeRenderTarget.GetData(IntPtr buffer, ColorDataLayout dataLayout, ColorDataElementType dataElementType, int targetIndex, int x, int y, int width, int height)
        {
            DefaultOpenTKBackendPlugin.GuardSingleThreadState();

            this.ApplyPostRender();
            if (curBound != this)
            {
                ApplyGLBind(this);
            }
            {
                GL.Ext.BindFramebuffer(FramebufferTarget.ReadFramebuffer, this.handleMainFBO);
                GL.ReadBuffer((ReadBufferMode)((int)ReadBufferMode.ColorAttachment0 + targetIndex));
                GL.ReadPixels(x, y, width, height, dataLayout.ToOpenTK(), dataElementType.ToOpenTK(), buffer);
            }
            ApplyGLBind(curBound);
        }
예제 #13
0
        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);
        }
예제 #14
0
        void INativeTexture.SetupEmpty(TexturePixelFormat format, int width, int height, TextureMinFilter minFilter, TextureMagFilter magFilter, TextureWrapMode wrapX, TextureWrapMode wrapY, int anisoLevel, bool mipmaps)
        {
            DefaultOpenTKBackendPlugin.GuardSingleThreadState();

            int lastTexId;

            GL.GetInteger(GetPName.TextureBinding2D, out lastTexId);
            if (lastTexId != this.handle)
            {
                GL.BindTexture(TextureTarget.Texture2D, this.handle);
            }

            // Set texture parameters
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)ToOpenTKTextureMinFilter(minFilter));
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)ToOpenTKTextureMagFilter(magFilter));
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)ToOpenTKTextureWrapMode(wrapX));
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)ToOpenTKTextureWrapMode(wrapY));

            // Anisotropic filtering
            if (anisoLevel > 0)
            {
                GL.TexParameter(TextureTarget.Texture2D, (TextureParameterName)ExtTextureFilterAnisotropic.TextureMaxAnisotropyExt, (float)anisoLevel);
            }

            // If needed, care for Mipmaps
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.GenerateMipmap, mipmaps ? 1 : 0);

            // Setup pixel format
            GL.TexImage2D(TextureTarget.Texture2D, 0,
                          ToOpenTKPixelFormat(format), width, height, 0,
                          GLPixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);

            this.width   = width;
            this.height  = height;
            this.format  = format;
            this.mipmaps = mipmaps;

            if (lastTexId != this.handle)
            {
                GL.BindTexture(TextureTarget.Texture2D, lastTexId);
            }
        }
예제 #15
0
        void INativeTexture.LoadData(TexturePixelFormat format, int width, int height, IntPtr data, ColorDataLayout dataLayout, ColorDataElementType dataElementType)
        {
            DefaultOpenTKBackendPlugin.GuardSingleThreadState();

            int lastTexId;

            GL.GetInteger(GetPName.TextureBinding2D, out lastTexId);
            GL.BindTexture(TextureTarget.Texture2D, this.handle);

            // Load pixel data to video memory
            GL.TexImage2D(TextureTarget.Texture2D, 0,
                          ToOpenTKPixelFormat(format), width, height, 0,
                          dataLayout.ToOpenTK(), dataElementType.ToOpenTK(),
                          data);

            this.width  = width;
            this.height = height;
            this.format = format;

            GL.BindTexture(TextureTarget.Texture2D, lastTexId);
        }
예제 #16
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);
        }
예제 #17
0
        void IDisposable.Dispose()
        {
            if (DualityApp.ExecContext == DualityApp.ExecutionContext.Terminated)
            {
                return;
            }
            DefaultOpenTKBackendPlugin.GuardSingleThreadState();

            // If there are changes pending to be applied to the bound textures,
            // they should be executed before the render target is gone.
            this.ApplyPostRender();

            if (this.handleMainFBO != 0)
            {
                GL.Ext.DeleteFramebuffers(1, ref this.handleMainFBO);
                this.handleMainFBO = 0;
            }
            if (this.handleDepthRBO != 0)
            {
                GL.Ext.DeleteRenderbuffers(1, ref this.handleDepthRBO);
                this.handleDepthRBO = 0;
            }
            if (this.handleMsaaFBO != 0)
            {
                GL.Ext.DeleteFramebuffers(1, ref this.handleMsaaFBO);
                this.handleMsaaFBO = 0;
            }
            for (int i = 0; i < this.targetInfos.Count; i++)
            {
                if (this.targetInfos.Data[i].HandleMsaaColorRBO != 0)
                {
                    GL.Ext.DeleteRenderbuffers(1, ref this.targetInfos.Data[i].HandleMsaaColorRBO);
                    this.targetInfos.Data[i].HandleMsaaColorRBO = 0;
                }
            }
        }
예제 #18
0
        void INativeShaderProgram.LoadProgram(INativeShaderPart vertex, INativeShaderPart fragment)
        {
            DefaultOpenTKBackendPlugin.GuardSingleThreadState();

            if (this.handle == 0)
            {
                this.handle = GL.CreateProgram();
            }
            else
            {
                this.DetachShaders();
            }

            // Attach both shaders
            if (vertex != null)
            {
                GL.AttachShader(this.handle, (vertex as NativeShaderPart).Handle);
            }
            if (fragment != null)
            {
                GL.AttachShader(this.handle, (fragment as NativeShaderPart).Handle);
            }

            // Link the shader program
            GL.LinkProgram(this.handle);

            int result;

            GL.GetProgram(this.handle, GetProgramParameterName.LinkStatus, out result);
            if (result == 0)
            {
                string errorLog = GL.GetProgramInfoLog(this.handle);
                this.RollbackAtFault();
                throw new BackendException(string.Format("Linker error:{1}{0}", errorLog, Environment.NewLine));
            }

            // Collect variable infos from sub programs
            {
                NativeShaderPart vert = vertex as NativeShaderPart;
                NativeShaderPart frag = fragment as NativeShaderPart;

                ShaderFieldInfo[] fragVarArray = frag != null ? frag.Fields : null;
                ShaderFieldInfo[] vertVarArray = vert != null ? vert.Fields : null;

                if (fragVarArray != null && vertVarArray != null)
                {
                    this.fields = vertVarArray.Union(fragVarArray).ToArray();
                }
                else if (vertVarArray != null)
                {
                    this.fields = vertVarArray.ToArray();
                }
                else
                {
                    this.fields = fragVarArray.ToArray();
                }
            }

            // Determine each variables location
            this.fieldLocations = new int[this.fields.Length];
            for (int i = 0; i < this.fields.Length; i++)
            {
                if (this.fields[i].Scope == ShaderFieldScope.Uniform)
                {
                    this.fieldLocations[i] = GL.GetUniformLocation(this.handle, this.fields[i].Name);
                }
                else
                {
                    this.fieldLocations[i] = GL.GetAttribLocation(this.handle, this.fields[i].Name);
                }
            }

            // Determine whether we're using builtin shader variables
            this.builtinIndex = new int[this.fields.Length];
            bool anyBuildinUsed = false;

            for (int i = 0; i < this.fields.Length; i++)
            {
                if (this.fields[i].Scope == ShaderFieldScope.Uniform)
                {
                    this.builtinIndex[i] = BuiltinShaderFields.GetIndex(this.fields[i].Name);
                    if (this.builtinIndex[i] != BuiltinShaderFields.InvalidIndex)
                    {
                        anyBuildinUsed = true;
                    }
                }
                else
                {
                    this.builtinIndex[i] = BuiltinShaderFields.InvalidIndex;
                }
            }
            if (!anyBuildinUsed)
            {
                this.builtinIndex = new int[0];
            }
        }
예제 #19
0
        void INativeShaderPart.LoadSource(string sourceCode, ShaderType type)
        {
            DefaultOpenTKBackendPlugin.GuardSingleThreadState();

            if (this.handle == 0)
            {
                this.handle = GL.CreateShader(GetOpenTKShaderType(type));
            }
            GL.ShaderSource(this.handle, sourceCode);
            GL.CompileShader(this.handle);

            int result;

            GL.GetShader(this.handle, ShaderParameter.CompileStatus, out result);
            if (result == 0)
            {
                string infoLog = GL.GetShaderInfoLog(this.handle);
                throw new BackendException(string.Format("{0} Compiler error:{2}{1}", type, infoLog, Environment.NewLine));
            }

            // Remove comments from source code before extracting variables
            string sourceWithoutComments;
            {
                const string blockComments   = @"/\*(.*?)\*/";
                const string lineComments    = @"//(.*?)\r?\n";
                const string strings         = @"""((\\[^\n]|[^""\n])*)""";
                const string verbatimStrings = @"@(""[^""]*"")+";
                sourceWithoutComments = Regex.Replace(sourceCode,
                                                      blockComments + "|" + lineComments + "|" + strings + "|" + verbatimStrings,
                                                      match =>
                {
                    if (match.Value.StartsWith("/*") || match.Value.StartsWith("//"))
                    {
                        return(match.Value.StartsWith("//") ? Environment.NewLine : "");
                    }
                    else
                    {
                        return(match.Value);
                    }
                },
                                                      RegexOptions.Singleline);
            }

            // Scan remaining code chunk for variable declarations
            List <ShaderFieldInfo> varInfoList = new List <ShaderFieldInfo>();

            string[] lines = sourceWithoutComments.Split(new[] { ';', '\n' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string t in lines)
            {
                string curLine = t.TrimStart();

                ShaderFieldScope scope;
                int arrayLength;

                if (curLine.StartsWith("uniform"))
                {
                    scope = ShaderFieldScope.Uniform;
                }
                else if (curLine.StartsWith("attribute"))
                {
                    scope = ShaderFieldScope.Attribute;
                }
                else
                {
                    continue;
                }

                string[]        curLineSplit = curLine.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                ShaderFieldType varType      = ShaderFieldType.Unknown;
                switch (curLineSplit[1].ToUpper())
                {
                case "FLOAT":           varType = ShaderFieldType.Float; break;

                case "VEC2":            varType = ShaderFieldType.Vec2; break;

                case "VEC3":            varType = ShaderFieldType.Vec3; break;

                case "VEC4":            varType = ShaderFieldType.Vec4; break;

                case "MAT2":            varType = ShaderFieldType.Mat2; break;

                case "MAT3":            varType = ShaderFieldType.Mat3; break;

                case "MAT4":            varType = ShaderFieldType.Mat4; break;

                case "INT":                     varType = ShaderFieldType.Int; break;

                case "SAMPLER2D":       varType = ShaderFieldType.Sampler2D; break;
                }

                curLineSplit = curLineSplit[2].Split(new char[] { '[', ']' }, StringSplitOptions.RemoveEmptyEntries);
                arrayLength  = (curLineSplit.Length > 1) ? int.Parse(curLineSplit[1]) : 1;

                varInfoList.Add(new ShaderFieldInfo(curLineSplit[0], varType, scope, arrayLength));
            }

            this.fields = varInfoList.ToArray();
        }
예제 #20
0
        void INativeShaderProgram.LoadProgram(IEnumerable <INativeShaderPart> shaderParts, IEnumerable <ShaderFieldInfo> shaderFields)
        {
            DefaultOpenTKBackendPlugin.GuardSingleThreadState();

            // Verify that we have exactly one shader part for each stage.
            // Other scenarios are valid in desktop GL, but not GL ES, so
            // we'll enforce the stricter rules manually to ease portability.
            int vertexCount   = 0;
            int fragmentCount = 0;

            foreach (INativeShaderPart part in shaderParts)
            {
                Resources.ShaderType type = (part as NativeShaderPart).Type;
                if (type == Resources.ShaderType.Fragment)
                {
                    fragmentCount++;
                }
                else if (type == Resources.ShaderType.Vertex)
                {
                    vertexCount++;
                }
            }
            if (vertexCount == 0)
            {
                throw new ArgumentException("Cannot load program without vertex shader.");
            }
            if (fragmentCount == 0)
            {
                throw new ArgumentException("Cannot load program without fragment shader.");
            }
            if (vertexCount > 1)
            {
                throw new ArgumentException("Cannot attach multiple vertex shaders to the same program.");
            }
            if (fragmentCount > 1)
            {
                throw new ArgumentException("Cannot attach multiple fragment shaders to the same program.");
            }

            // Create or reset GL program
            if (this.handle == 0)
            {
                this.handle = GL.CreateProgram();
            }
            else
            {
                this.DetachShaders();
            }

            // Attach all individual shaders to the program
            foreach (INativeShaderPart part in shaderParts)
            {
                GL.AttachShader(this.handle, (part as NativeShaderPart).Handle);
            }

            // Link the shader program
            GL.LinkProgram(this.handle);

            int result;

            GL.GetProgram(this.handle, GetProgramParameterName.LinkStatus, out result);
            if (result == 0)
            {
                string errorLog = GL.GetProgramInfoLog(this.handle);
                this.RollbackAtFault();
                throw new BackendException(string.Format("Linker error:{1}{0}", errorLog, Environment.NewLine));
            }

            // Collect variables that are available through shader reflection, e.g.
            // haven't been optimized of #ifdef'd away.
            List <int>             validLocations = new List <int>();
            List <ShaderFieldInfo> validFields    = new List <ShaderFieldInfo>();

            foreach (ShaderFieldInfo field in shaderFields)
            {
                int location;
                if (field.Scope == ShaderFieldScope.Uniform)
                {
                    location = GL.GetUniformLocation(this.handle, field.Name);
                }
                else
                {
                    location = GL.GetAttribLocation(this.handle, field.Name);
                }

                if (location >= 0)
                {
                    validLocations.Add(location);
                    validFields.Add(field);
                }
            }

            this.fields         = validFields.ToArray();
            this.fieldLocations = validLocations.ToArray();
        }
예제 #21
0
        void INativeRenderTarget.Setup(IReadOnlyList <INativeTexture> targets, AAQuality multisample, bool depthBuffer)
        {
            DefaultOpenTKBackendPlugin.GuardSingleThreadState();

            if (targets == null)
            {
                return;
            }
            if (targets.Count == 0)
            {
                return;
            }
            if (targets.All(i => i == null))
            {
                return;
            }

            int highestAALevel = MathF.RoundToInt(MathF.Log(MathF.Max(MaxRenderTargetSamples, 1.0f), 2.0f));
            int targetAALevel  = highestAALevel;

            switch (multisample)
            {
            case AAQuality.High:    targetAALevel = highestAALevel;         break;

            case AAQuality.Medium:  targetAALevel = highestAALevel / 2; break;

            case AAQuality.Low:             targetAALevel = highestAALevel / 4; break;

            case AAQuality.Off:             targetAALevel = 0;                                      break;
            }
            int          targetSampleCount = MathF.RoundToInt(MathF.Pow(2.0f, targetAALevel));
            GraphicsMode sampleMode        =
                GraphicsBackend.ActiveInstance.AvailableGraphicsModes.LastOrDefault(m => m.Samples <= targetSampleCount) ??
                GraphicsBackend.ActiveInstance.AvailableGraphicsModes.Last();

            this.samples     = sampleMode.Samples;
            this.depthBuffer = depthBuffer;

            // Synchronize target information
            {
                this.targetInfos.Reserve(targets.Count);
                int localIndex = 0;
                for (int i = 0; i < targets.Count; i++)
                {
                    if (targets[i] == null)
                    {
                        continue;
                    }

                    this.targetInfos.Count = Math.Max(this.targetInfos.Count, localIndex + 1);
                    this.targetInfos.Data[localIndex].Target = targets[i] as NativeTexture;

                    localIndex++;
                }
            }

            // Setup OpenGL resources
            if (this.samples > 0)
            {
                this.SetupMultisampled();
            }
            else
            {
                this.SetupNonMultisampled();
            }
        }
예제 #22
0
        void INativeRenderTarget.Setup(IReadOnlyList <INativeTexture> targets, AAQuality multisample)
        {
            DefaultOpenTKBackendPlugin.GuardSingleThreadState();

            if (targets == null)
            {
                return;
            }
            if (targets.Count == 0)
            {
                return;
            }
            if (targets.All(i => i == null))
            {
                return;
            }

            int highestAALevel = MathF.RoundToInt(MathF.Log(MathF.Max(MaxRenderTargetSamples, 1.0f), 2.0f));
            int targetAALevel  = highestAALevel;

            switch (multisample)
            {
            case AAQuality.High:    targetAALevel = highestAALevel;         break;

            case AAQuality.Medium:  targetAALevel = highestAALevel / 2; break;

            case AAQuality.Low:             targetAALevel = highestAALevel / 4; break;

            case AAQuality.Off:             targetAALevel = 0;                                      break;
            }
            int          targetSampleCount = MathF.RoundToInt(MathF.Pow(2.0f, targetAALevel));
            GraphicsMode sampleMode        =
                GraphicsBackend.ActiveInstance.AvailableGraphicsModes.LastOrDefault(m => m.Samples <= targetSampleCount) ??
                GraphicsBackend.ActiveInstance.AvailableGraphicsModes.Last();

            this.samples = sampleMode.Samples;

            // Synchronize target information
            {
                this.targetInfos.Reserve(targets.Count);
                int localIndex = 0;
                for (int i = 0; i < targets.Count; i++)
                {
                    if (targets[i] == null)
                    {
                        continue;
                    }

                    this.targetInfos.Count = Math.Max(this.targetInfos.Count, localIndex + 1);
                    this.targetInfos.Data[localIndex].Target = targets[i] as NativeTexture;

                    localIndex++;
                }
            }

            #region Setup FBO & RBO: Non-multisampled
            if (this.samples == 0)
            {
                // Generate FBO
                if (this.handleMainFBO == 0)
                {
                    GL.Ext.GenFramebuffers(1, out this.handleMainFBO);
                }
                GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, this.handleMainFBO);

                // Attach textures
                int oglWidth  = 0;
                int oglHeight = 0;
                for (int i = 0; i < this.targetInfos.Count; i++)
                {
                    NativeTexture tex = this.targetInfos[i].Target;

                    FramebufferAttachment attachment = (FramebufferAttachment)((int)FramebufferAttachment.ColorAttachment0Ext + i);
                    GL.Ext.FramebufferTexture2D(
                        FramebufferTarget.FramebufferExt,
                        attachment,
                        TextureTarget.Texture2D,
                        tex.Handle,
                        0);
                    oglWidth  = tex.Width;
                    oglHeight = tex.Height;
                }

                // Generate Depth Renderbuffer
                if (this.handleDepthRBO == 0)
                {
                    GL.Ext.GenRenderbuffers(1, out this.handleDepthRBO);
                }
                GL.Ext.BindRenderbuffer(RenderbufferTarget.RenderbufferExt, this.handleDepthRBO);
                GL.Ext.RenderbufferStorage(RenderbufferTarget.RenderbufferExt, RenderbufferStorage.DepthComponent24, oglWidth, oglHeight);
                GL.Ext.FramebufferRenderbuffer(FramebufferTarget.FramebufferExt, FramebufferAttachment.DepthAttachmentExt, RenderbufferTarget.RenderbufferExt, this.handleDepthRBO);

                // Check status
                FramebufferErrorCode status = GL.Ext.CheckFramebufferStatus(FramebufferTarget.FramebufferExt);
                if (status != FramebufferErrorCode.FramebufferCompleteExt)
                {
                    throw new BackendException(string.Format("Incomplete Framebuffer: {0}", status));
                }

                GL.Ext.BindRenderbuffer(RenderbufferTarget.RenderbufferExt, 0);
                GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, 0);
            }
            #endregion

            #region Setup FBO & RBO: Multisampled
            if (this.samples > 0)
            {
                // Generate texture target FBO
                if (this.handleMainFBO == 0)
                {
                    GL.Ext.GenFramebuffers(1, out this.handleMainFBO);
                }
                GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, this.handleMainFBO);

                // Attach textures
                int oglWidth  = 0;
                int oglHeight = 0;
                for (int i = 0; i < this.targetInfos.Count; i++)
                {
                    NativeTexture tex = this.targetInfos[i].Target;

                    FramebufferAttachment attachment = (FramebufferAttachment)((int)FramebufferAttachment.ColorAttachment0Ext + i);
                    GL.Ext.FramebufferTexture2D(
                        FramebufferTarget.FramebufferExt,
                        attachment,
                        TextureTarget.Texture2D,
                        tex.Handle,
                        0);
                    oglWidth  = tex.Width;
                    oglHeight = tex.Height;
                }

                // Check status
                FramebufferErrorCode status = GL.Ext.CheckFramebufferStatus(FramebufferTarget.FramebufferExt);
                if (status != FramebufferErrorCode.FramebufferCompleteExt)
                {
                    throw new BackendException(string.Format("Incomplete Framebuffer: {0}", status));
                }

                // Generate rendering FBO
                if (this.handleMsaaFBO == 0)
                {
                    GL.Ext.GenFramebuffers(1, out this.handleMsaaFBO);
                }
                GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, this.handleMsaaFBO);

                // Attach color renderbuffers
                for (int i = 0; i < this.targetInfos.Count; i++)
                {
                    TargetInfo info = this.targetInfos.Data[i];

                    FramebufferAttachment attachment    = (FramebufferAttachment)((int)FramebufferAttachment.ColorAttachment0Ext + i);
                    RenderbufferStorage   rbColorFormat = TexFormatToRboFormat(info.Target.Format);

                    if (info.HandleMsaaColorRBO == 0)
                    {
                        GL.GenRenderbuffers(1, out info.HandleMsaaColorRBO);
                    }
                    GL.Ext.BindRenderbuffer(RenderbufferTarget.RenderbufferExt, info.HandleMsaaColorRBO);
                    GL.Ext.RenderbufferStorageMultisample(RenderbufferTarget.RenderbufferExt, this.samples, rbColorFormat, oglWidth, oglHeight);
                    GL.Ext.FramebufferRenderbuffer(FramebufferTarget.FramebufferExt, attachment, RenderbufferTarget.RenderbufferExt, info.HandleMsaaColorRBO);

                    this.targetInfos.Data[i] = info;
                }
                GL.Ext.BindRenderbuffer(RenderbufferTarget.Renderbuffer, 0);

                // Attach depth renderbuffer
                if (this.handleDepthRBO == 0)
                {
                    GL.Ext.GenRenderbuffers(1, out this.handleDepthRBO);
                }
                GL.Ext.BindRenderbuffer(RenderbufferTarget.RenderbufferExt, this.handleDepthRBO);
                GL.Ext.RenderbufferStorageMultisample(RenderbufferTarget.RenderbufferExt, this.samples, RenderbufferStorage.DepthComponent24, oglWidth, oglHeight);
                GL.Ext.FramebufferRenderbuffer(FramebufferTarget.FramebufferExt, FramebufferAttachment.DepthAttachmentExt, RenderbufferTarget.RenderbufferExt, this.handleDepthRBO);
                GL.Ext.BindRenderbuffer(RenderbufferTarget.RenderbufferExt, 0);

                // Check status
                status = GL.Ext.CheckFramebufferStatus(FramebufferTarget.FramebufferExt);
                if (status != FramebufferErrorCode.FramebufferCompleteExt)
                {
                    throw new BackendException(string.Format("Incomplete Multisample Framebuffer: {0}", status));
                }

                GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, 0);
            }
            #endregion
        }