예제 #1
0
        private ClydeTexture GenTexture(GLHandle glHandle, Vector2i size, string?name, long memoryPressure = 0)
        {
            if (name != null)
            {
                ObjectLabelMaybe(ObjectLabelIdentifier.Texture, glHandle, name);
            }

            var(width, height) = size;

            var id       = AllocRid();
            var instance = new ClydeTexture(id, size, this);
            var loaded   = new LoadedTexture
            {
                OpenGLObject   = glHandle,
                Width          = width,
                Height         = height,
                Name           = name,
                MemoryPressure = memoryPressure
                                 // TextureInstance = new WeakReference<ClydeTexture>(instance)
            };

            _loadedTextures.Add(id, loaded);
            //GC.AddMemoryPressure(memoryPressure);

            return(instance);
        }
예제 #2
0
        private unsafe void CreateMiscGLObjects()
        {
            // Quad drawing.
            {
                var quadVertices = new[]
                {
                    new Vertex2D(1, 0, 1, 1),
                    new Vertex2D(0, 0, 0, 1),
                    new Vertex2D(1, 1, 1, 0),
                    new Vertex2D(0, 1, 0, 0)
                };

                QuadVBO = new GLBuffer <Vertex2D>(this, BufferTarget.ArrayBuffer, BufferUsageHint.StaticDraw, quadVertices,
                                                  nameof(QuadVBO));

                QuadVAO = new GLHandle((uint)GL.GenVertexArray());
                GL.BindVertexArray(QuadVAO.Handle);
                ObjectLabelMaybe(ObjectLabelIdentifier.VertexArray, QuadVAO, nameof(QuadVAO));
                // Vertex Coords
                GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, Vertex2D.SizeOf, 0);
                GL.EnableVertexAttribArray(0);
                // Texture Coords.
                GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, Vertex2D.SizeOf, 2 * sizeof(float));
                GL.EnableVertexAttribArray(1);
            }

            // Batch rendering
            {
                BatchVBO = new GLBuffer(this, BufferTarget.ArrayBuffer, BufferUsageHint.DynamicDraw,
                                        Vertex2D.SizeOf * BatchVertexData.Length, nameof(BatchVBO));

                BatchVAO = new GLHandle(GL.GenVertexArray());
                GL.BindVertexArray(BatchVAO.Handle);
                ObjectLabelMaybe(ObjectLabelIdentifier.VertexArray, BatchVAO, nameof(BatchVAO));
                // Vertex Coords
                GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, Vertex2D.SizeOf, 0);
                GL.EnableVertexAttribArray(0);
                // Texture Coords.
                GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, Vertex2D.SizeOf, 2 * sizeof(float));
                GL.EnableVertexAttribArray(1);

                BatchEBO = new GLBuffer(this, BufferTarget.ElementArrayBuffer, BufferUsageHint.DynamicDraw,
                                        sizeof(ushort) * BatchIndexData.Length, nameof(BatchEBO));
            }

            ProjViewUBO = new GLBuffer(this, BufferTarget.UniformBuffer, BufferUsageHint.StreamDraw, nameof(ProjViewUBO));
            ProjViewUBO.Reallocate(sizeof(ProjViewMatrices));

            GL.BindBufferBase(BufferRangeTarget.UniformBuffer, ProjViewBindingIndex, ProjViewUBO.ObjectHandle);

            UniformConstantsUBO = new GLBuffer(this, BufferTarget.UniformBuffer, BufferUsageHint.StreamDraw,
                                               nameof(UniformConstantsUBO));
            UniformConstantsUBO.Reallocate(sizeof(UniformConstants));

            GL.BindBufferBase(BufferRangeTarget.UniformBuffer, UniformConstantsBindingIndex,
                              UniformConstantsUBO.ObjectHandle);

            EntityPostRenderTarget = CreateRenderTarget(Vector2i.One * 4 * EyeManager.PIXELSPERMETER,
                                                        RenderTargetColorFormat.Rgba8Srgb, name: nameof(EntityPostRenderTarget), hasStencilBuffer: true);
        }
예제 #3
0
        internal int GetShaderHandle()
        {
            // If the shader has already been created then return it.
            if (!_handle.IsNull)
            {
                return(_handle);
            }

            var shaderType = Stage == ShaderStage.Vertex ? ShaderType.VertexShader : ShaderType.FragmentShader;
            var shader     = GL.CreateShader(shaderType);

            GL.CheckError();

            GL.ShaderSource(shader, GlslCode);
            GL.CheckError();

            GL.CompileShader(shader);
            GL.CheckError();

            GL.GetShader(shader, ShaderParameter.CompileStatus, out int compiled);
            GL.CheckError();

            _handle = GLHandle.Shader(shader);
            if (compiled == (int)Bool.True)
            {
                return(_handle);
            }

            var log = GL.GetShaderInfoLog(shader);

            Debug.WriteLine(log);

            _handle.Free();
            throw new InvalidOperationException("Shader compilation failed.");
        }
예제 #4
0
        private void PlatformConstruct()
        {
            GL.GenQueries(1, out int query);
            GL.CheckError();

            _glQuery = GLHandle.Query(query);
        }
        private unsafe void InitLighting()
        {
            LoadLightingShaders();

            RegenerateLightingRenderTargets();

            // Occlusion VAO.
            // Only handles positions, no other vertex data necessary.
            _occlusionVao = new GLHandle(GL.GenVertexArray());
            GL.BindVertexArray(_occlusionVao.Handle);

            ObjectLabelMaybe(ObjectLabelIdentifier.VertexArray, _occlusionVao, nameof(_occlusionVao));

            _occlusionVbo = new GLBuffer(this, BufferTarget.ArrayBuffer, BufferUsageHint.DynamicDraw,
                                         nameof(_occlusionVbo));

            _occlusionEbo = new GLBuffer(this, BufferTarget.ElementArrayBuffer, BufferUsageHint.DynamicDraw,
                                         nameof(_occlusionEbo));

            GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, sizeof(Vector3), IntPtr.Zero);
            GL.EnableVertexAttribArray(0);

            // FOV FBO.
            _fovRenderTarget = CreateRenderTarget((ShadowMapSize, 1),
                                                  new RenderTargetFormatParameters(RenderTargetColorFormat.R32F, true),
                                                  new TextureSampleParameters {
                WrapMode = TextureWrapMode.Repeat
            }, "FOV depth render target");

            _fovDepthTextureObject = _fovRenderTarget.Texture;
        }
예제 #6
0
        /// <summary>
        /// Creates a FrameBuffer that wraps a given Texture2D object. This Texture2D will not be disposed when the
        /// FrameBuffer itself is disposed, unlike other constructors.
        /// </summary>
        public FrameBuffer(RenderContext renderContext, Texture2D wrappedTexture)
            : base(renderContext)
        {
            Width  = wrappedTexture._width;
            Height = wrappedTexture._height;
            Flags  = FrameBufferFlags.Color;

            Handle = GLHelper.CreateFrameBuffer();
            GLHelper.EnsureValid(Handle);

            GLHandle prevFrameBuffer = (GLHandle)GL.GetInteger(GetPName.FramebufferBinding);

            GL.BindFramebuffer(FramebufferTarget.Framebuffer, Handle);

            GL.FramebufferTexture2D(FramebufferTarget.Framebuffer,
                                    FramebufferAttachment.ColorAttachment0,
                                    TextureTarget.Texture2D,
                                    wrappedTexture.Handle,
                                    0);

            GL.BindFramebuffer(FramebufferTarget.Framebuffer, prevFrameBuffer);

            if (!IsComplete())
            {
                throw new InvalidOperationException();
            }
        }
예제 #7
0
 private void PlatformGraphicsDeviceResetting()
 {
     if (!_handle.IsNull)
     {
         GraphicsDevice.DisposeResource(_handle);
         _handle = default;
     }
 }
예제 #8
0
        /// <summary>
        /// Creates a FrameBuffer with components depending on the FrameBufferFlags given.
        /// </summary>
        public FrameBuffer(RenderContext renderContext, int width, int height, FrameBufferFlags flags)
            : base(renderContext)
        {
            Width  = width;
            Height = height;
            Flags  = flags;

            Handle = GLHelper.CreateFrameBuffer();
            GLHelper.EnsureValid(Handle);

            // Initialize Color Component (Texture2D)
            if ((Flags & FrameBufferFlags.Color) != 0)
            {
                ColorTexture = Texture2D.CreateEmpty(renderContext, width, height);

                GLHandle prevFrameBuffer = (GLHandle)GL.GetInteger(GetPName.FramebufferBinding);
                GL.BindFramebuffer(FramebufferTarget.Framebuffer, Handle);

                GL.FramebufferTexture2D(FramebufferTarget.Framebuffer,
                                        FramebufferAttachment.ColorAttachment0,
                                        TextureTarget.Texture2D,
                                        ColorTexture.Handle,
                                        0);

                GL.BindFramebuffer(FramebufferTarget.Framebuffer, prevFrameBuffer);
            }

            // Initialize Depth Component (Renderbuffer)
            if ((Flags & FrameBufferFlags.Depth) != 0)
            {
                DepthHandle = (GLHandle)GL.GenRenderbuffer();

                GLHandle prevFrameBuffer = (GLHandle)GL.GetInteger(GetPName.FramebufferBinding);
                GL.BindFramebuffer(FramebufferTarget.Framebuffer, Handle);

                GLHandle prevRenderBuffer = (GLHandle)GL.GetInteger(GetPName.RenderbufferBinding);
                GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, DepthHandle);

                GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer,
                                       RenderbufferStorage.DepthComponent,
                                       width,
                                       height);
                GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer,
                                           FramebufferAttachment.DepthAttachment,
                                           RenderbufferTarget.Renderbuffer,
                                           DepthHandle);

                GL.BindFramebuffer(FramebufferTarget.Framebuffer, prevFrameBuffer);
                GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, prevRenderBuffer);
            }

            if (!IsComplete())
            {
                throw new InvalidOperationException();
            }
        }
 public RenderTarget(Vector2i size, ClydeTexture texture, GLHandle objectHandle, Clyde clyde,
                     ClydeHandle handle, GLHandle depthStencilBuffer)
 {
     Size               = size;
     Texture            = texture;
     ObjectHandle       = objectHandle;
     _clyde             = clyde;
     Handle             = handle;
     DepthStencilBuffer = depthStencilBuffer;
 }
예제 #10
0
        protected override void Dispose(bool disposing)
        {
            if (!IsDisposed && _handle.IsNull)
            {
                GraphicsDevice.DisposeResource(_handle);
                _handle = default;
            }

            base.Dispose(disposing);
        }
예제 #11
0
        internal void DisposeResource(GLHandle handle)
        {
            if (IsDisposed || handle.IsNull)
            {
                return;
            }

            lock (ResourceFreeingLock)
                _resourceFreeQueue.Add(handle);
        }
예제 #12
0
        private bool IsComplete()
        {
            GLHandle prevFBO = (GLHandle)GL.GetInteger(GetPName.FramebufferBinding);

            GL.BindFramebuffer(FramebufferTarget.Framebuffer, Handle);

            var status = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer);

            GL.BindFramebuffer(FramebufferTarget.Framebuffer, prevFBO);

            return(status == FramebufferErrorCode.FramebufferComplete);
        }
예제 #13
0
        private GLHandle MakeQuadVao()
        {
            var vao = new GLHandle(GenVertexArray());

            BindVertexArray(vao.Handle);
            ObjectLabelMaybe(ObjectLabelIdentifier.VertexArray, vao, nameof(QuadVAO));
            GL.BindBuffer(BufferTarget.ArrayBuffer, QuadVBO.ObjectHandle);
            // Vertex Coords
            GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, Vertex2D.SizeOf, 0);
            GL.EnableVertexAttribArray(0);
            // Texture Coords.
            GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, Vertex2D.SizeOf, 2 * sizeof(float));
            GL.EnableVertexAttribArray(1);

            return(vao);
        }
        private ShaderProgram Link(Shader vertexShader, Shader pixelShader)
        {
            // NOTE: No need to worry about background threads here
            // as this is only called at draw time when we're in the
            // main drawing thread.
            var program = GL.CreateProgram();

            GL.CheckError();

            GL.AttachShader(program, vertexShader.GetShaderHandle());
            GL.CheckError();

            GL.AttachShader(program, pixelShader.GetShaderHandle());
            GL.CheckError();

            //vertexShader.BindVertexAttributes(program);

            GL.LinkProgram(program);
            GL.CheckError();

            GL.UseProgram(program);
            GL.CheckError();

            vertexShader.GetVertexAttributeLocations(program);

            pixelShader.ApplySamplerTextureUnits(program);

            GL.GetProgram(program, GetProgramParameterName.LinkStatus, out int linked);
            GL.LogError("VertexShaderCache.Link(), GL.GetProgram");

            var programHandle = GLHandle.Program(program);

            if (linked == (int)Bool.False)
            {
                var log = GL.GetProgramInfoLog(program);
                Debug.WriteLine(log);

                GL.DetachShader(program, vertexShader.GetShaderHandle());
                GL.DetachShader(program, pixelShader.GetShaderHandle());

                programHandle.Free();
                throw new InvalidOperationException("Unable to link effect program");
            }

            return(new ShaderProgram(programHandle));
        }
예제 #15
0
        internal void GenerateIfRequired()
        {
            if (!_glBuffer.IsNull)
            {
                return;
            }

            _glBuffer = GL.GenBuffer();
            GL.CheckError();

            GL.BindBuffer(_target, _glBuffer);
            GL.CheckError();

            int sizeInBytes = Capacity * _elementSize;

            GL.BufferData(_target, (IntPtr)sizeInBytes, IntPtr.Zero, _usageHint);
            GL.CheckError();
        }
예제 #16
0
        private ClydeTexture GenTexture(GLHandle glHandle, Vector2i size, string name)
        {
            if (name != null)
            {
                ObjectLabelMaybe(ObjectLabelIdentifier.Texture, glHandle, name);
            }

            var(width, height) = size;

            var loaded = new LoadedTexture
            {
                OpenGLObject = glHandle,
                Width        = width,
                Height       = height,
                Name         = name
            };

            var id = AllocRid();

            _loadedTextures.Add(id, loaded);

            return(new ClydeTexture(id, size, this));
        }
        private unsafe void InitLighting()
        {
            LoadLightingShaders();

            {
                // Occlusion VAO.
                // Only handles positions, no other vertex data necessary.
                _occlusionVao = new GLHandle(GL.GenVertexArray());
                GL.BindVertexArray(_occlusionVao.Handle);

                ObjectLabelMaybe(ObjectLabelIdentifier.VertexArray, _occlusionVao, nameof(_occlusionVao));

                _occlusionVbo = new GLBuffer(this, BufferTarget.ArrayBuffer, BufferUsageHint.DynamicDraw,
                                             nameof(_occlusionVbo));

                _occlusionEbo = new GLBuffer(this, BufferTarget.ElementArrayBuffer, BufferUsageHint.DynamicDraw,
                                             nameof(_occlusionEbo));

                GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, sizeof(Vector3), IntPtr.Zero);
                GL.EnableVertexAttribArray(0);
            }

            {
                // Occlusion mask VAO.
                // Only handles positions, no other vertex data necessary.

                _occlusionMaskVao = new GLHandle(GL.GenVertexArray());
                GL.BindVertexArray(_occlusionMaskVao.Handle);

                ObjectLabelMaybe(ObjectLabelIdentifier.VertexArray, _occlusionMaskVao, nameof(_occlusionMaskVao));

                _occlusionMaskVbo = new GLBuffer(this, BufferTarget.ArrayBuffer, BufferUsageHint.DynamicDraw,
                                                 nameof(_occlusionMaskVbo));

                _occlusionMaskEbo = new GLBuffer(this, BufferTarget.ElementArrayBuffer, BufferUsageHint.DynamicDraw,
                                                 nameof(_occlusionMaskEbo));

                GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, sizeof(Vector2), IntPtr.Zero);
                GL.EnableVertexAttribArray(0);
            }

            // FOV FBO.
            _fovRenderTarget = CreateRenderTarget((FovMapSize, 2),
                                                  new RenderTargetFormatParameters(RenderTargetColorFormat.RG32F, true),
                                                  new TextureSampleParameters {
                WrapMode = TextureWrapMode.Repeat
            },
                                                  nameof(_fovRenderTarget));

            _fovFilterSampler = new GLHandle(GL.GenSampler());
            GL.SamplerParameter(_fovFilterSampler.Handle, SamplerParameterName.TextureMagFilter, (int)All.Linear);
            GL.SamplerParameter(_fovFilterSampler.Handle, SamplerParameterName.TextureMinFilter, (int)All.Linear);
            GL.SamplerParameter(_fovFilterSampler.Handle, SamplerParameterName.TextureWrapS, (int)All.Repeat);
            GL.SamplerParameter(_fovFilterSampler.Handle, SamplerParameterName.TextureWrapT, (int)All.Repeat);

            // Shadow FBO.
            _shadowRenderTarget = CreateRenderTarget((ShadowMapSize, MaxLightsPerScene),
                                                     new RenderTargetFormatParameters(RenderTargetColorFormat.RG32F, true),
                                                     new TextureSampleParameters {
                WrapMode = TextureWrapMode.Repeat, Filter = true
            },
                                                     nameof(_shadowRenderTarget));
        }
 public ShaderProgram(GLHandle program)
 {
     Program = program;
 }
예제 #19
0
 private void ObjectLabelMaybe(ObjectLabelIdentifier identifier, GLHandle name, string?label)
 {
     ObjectLabelMaybe(identifier, name.Handle, label);
 }
예제 #20
0
        private RenderTarget CreateRenderTarget(Vector2i size, RenderTargetFormatParameters format,
                                                TextureSampleParameters?sampleParameters = null, string name = null)
        {
            // Cache currently bound framebuffers
            // so if somebody creates a framebuffer while drawing it won't ruin everything.
            var boundDrawBuffer = GL.GetInteger(GetPName.DrawFramebufferBinding);
            var boundReadBuffer = GL.GetInteger(GetPName.ReadFramebufferBinding);

            // Generate FBO.
            var fbo = new GLHandle(GL.GenFramebuffer());

            // Bind color attachment to FBO.
            GL.BindFramebuffer(FramebufferTarget.Framebuffer, fbo.Handle);

            ObjectLabelMaybe(ObjectLabelIdentifier.Framebuffer, fbo, name);

            var(width, height) = size;

            ClydeTexture textureObject;
            GLHandle     depthStencilBuffer = default;

            // Color attachment.
            {
                var texture = new GLHandle(GL.GenTexture());

                GL.BindTexture(TextureTarget.Texture2D, texture.Handle);

                ApplySampleParameters(sampleParameters);

                var internalFormat = format.ColorFormat switch
                {
                    RenderTargetColorFormat.Rgba8 => PixelInternalFormat.Rgba8,
                    RenderTargetColorFormat.Rgba16F => PixelInternalFormat.Rgba16f,
                    RenderTargetColorFormat.Rgba8Srgb => PixelInternalFormat.Srgb8Alpha8,
                    RenderTargetColorFormat.R11FG11FB10F => PixelInternalFormat.R11fG11fB10f,
                    RenderTargetColorFormat.R32F => PixelInternalFormat.R32f,
                    _ => throw new ArgumentOutOfRangeException(nameof(format.ColorFormat), format.ColorFormat, null)
                };

                GL.TexImage2D(TextureTarget.Texture2D, 0, internalFormat, width, height, 0, PixelFormat.Red,
                              PixelType.Byte, IntPtr.Zero);

                GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0,
                                      texture.Handle,
                                      0);

                textureObject = GenTexture(texture, size, name == null ? null : $"{name}-color");
            }

            // Depth/stencil buffers.
            if (format.HasDepthStencil)
            {
                depthStencilBuffer = new GLHandle(GL.GenRenderbuffer());
                GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, depthStencilBuffer.Handle);

                ObjectLabelMaybe(ObjectLabelIdentifier.Renderbuffer, depthStencilBuffer,
                                 name == null ? null : $"{name}-depth-stencil");

                GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.Depth24Stencil8, width,
                                       height);

                GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthStencilAttachment,
                                           RenderbufferTarget.Renderbuffer, depthStencilBuffer.Handle);
            }

            // This should always pass but OpenGL makes it easy to check for once so let's.
            var status = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer);

            DebugTools.Assert(status == FramebufferErrorCode.FramebufferComplete,
                              $"new framebuffer has bad status {status}");

            // Re-bind previous framebuffers.
            GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, boundDrawBuffer);
            GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, boundReadBuffer);

            var handle       = AllocRid();
            var renderTarget = new RenderTarget(size, textureObject, fbo, this, handle, depthStencilBuffer);

            _renderTargets.Add(handle, renderTarget);
            return(renderTarget);
        }
예제 #21
0
        private unsafe void CreateMiscGLObjects()
        {
            // Quad drawing.
            {
                Span <Vertex2D> quadVertices = stackalloc[]
                {
                    new Vertex2D(1, 0, 1, 1),
                    new Vertex2D(0, 0, 0, 1),
                    new Vertex2D(1, 1, 1, 0),
                    new Vertex2D(0, 1, 0, 0)
                };

                QuadVBO = new GLBuffer <Vertex2D>(this, BufferTarget.ArrayBuffer, BufferUsageHint.StaticDraw,
                                                  quadVertices,
                                                  nameof(QuadVBO));

                QuadVAO = MakeQuadVao();

                CheckGlError();
            }

            // Window VBO
            {
                Span <Vertex2D> winVertices = stackalloc[]
                {
                    new Vertex2D(-1, 1, 0, 1),
                    new Vertex2D(-1, -1, 0, 0),
                    new Vertex2D(1, 1, 1, 1),
                    new Vertex2D(1, -1, 1, 0),
                };

                WindowVBO = new GLBuffer <Vertex2D>(
                    this,
                    BufferTarget.ArrayBuffer,
                    BufferUsageHint.StaticDraw,
                    winVertices,
                    nameof(WindowVBO));

                CheckGlError();
            }

            // Batch rendering
            {
                BatchVBO = new GLBuffer(this, BufferTarget.ArrayBuffer, BufferUsageHint.DynamicDraw,
                                        Vertex2D.SizeOf * BatchVertexData.Length, nameof(BatchVBO));

                BatchVAO = new GLHandle(GenVertexArray());
                BindVertexArray(BatchVAO.Handle);
                ObjectLabelMaybe(ObjectLabelIdentifier.VertexArray, BatchVAO, nameof(BatchVAO));
                // Vertex Coords
                GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, Vertex2D.SizeOf, 0);
                GL.EnableVertexAttribArray(0);
                // Texture Coords.
                GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, Vertex2D.SizeOf, 2 * sizeof(float));
                GL.EnableVertexAttribArray(1);

                CheckGlError();

                BatchEBO = new GLBuffer(this, BufferTarget.ElementArrayBuffer, BufferUsageHint.DynamicDraw,
                                        sizeof(ushort) * BatchIndexData.Length, nameof(BatchEBO));
            }

            ProjViewUBO         = new GLUniformBuffer <ProjViewMatrices>(this, BindingIndexProjView, nameof(ProjViewUBO));
            UniformConstantsUBO = new GLUniformBuffer <UniformConstants>(this, BindingIndexUniformConstants, nameof(UniformConstantsUBO));

            screenBufferHandle = new GLHandle(GL.GenTexture());
            GL.BindTexture(TextureTarget.Texture2D, screenBufferHandle.Handle);
            ApplySampleParameters(TextureSampleParameters.Default);
            ScreenBufferTexture = GenTexture(screenBufferHandle, _windowing !.MainWindow !.FramebufferSize, true, null, TexturePixelType.Rgba32);
        }
예제 #22
0
 private void DeleteGLTexture()
 {
     GraphicsDevice.DisposeResource(_glTexture);
     _glTexture = default;
 }
        private unsafe void InitLighting()
        {
            // Other...
            LoadLightingShaders();

            {
                // Occlusion VAO.
                // Only handles positions, no other vertex data necessary.
                _occlusionVao = new GLHandle(GenVertexArray());
                BindVertexArray(_occlusionVao.Handle);
                CheckGlError();

                ObjectLabelMaybe(ObjectLabelIdentifier.VertexArray, _occlusionVao, nameof(_occlusionVao));

                // aPos
                _occlusionVbo = new GLBuffer(this, BufferTarget.ArrayBuffer, BufferUsageHint.DynamicDraw,
                                             nameof(_occlusionVbo));
                GL.VertexAttribPointer(0, 4, VertexAttribPointerType.Float, false, sizeof(Vector4), IntPtr.Zero);
                GL.EnableVertexAttribArray(0);

                CheckGlError();

                // subVertex
                _occlusionVIVbo = new GLBuffer(this, BufferTarget.ArrayBuffer, BufferUsageHint.DynamicDraw,
                                               nameof(_occlusionVIVbo));
                GL.VertexAttribPointer(1, 2, VertexAttribPointerType.UnsignedByte, true, sizeof(byte) * 2, IntPtr.Zero);
                GL.EnableVertexAttribArray(1);

                // index
                _occlusionEbo = new GLBuffer(this, BufferTarget.ElementArrayBuffer, BufferUsageHint.DynamicDraw,
                                             nameof(_occlusionEbo));

                CheckGlError();
            }

            {
                // Occlusion mask VAO.
                // Only handles positions, no other vertex data necessary.

                _occlusionMaskVao = new GLHandle(GenVertexArray());
                BindVertexArray(_occlusionMaskVao.Handle);
                CheckGlError();

                ObjectLabelMaybe(ObjectLabelIdentifier.VertexArray, _occlusionMaskVao, nameof(_occlusionMaskVao));

                _occlusionMaskVbo = new GLBuffer(this, BufferTarget.ArrayBuffer, BufferUsageHint.DynamicDraw,
                                                 nameof(_occlusionMaskVbo));

                _occlusionMaskEbo = new GLBuffer(this, BufferTarget.ElementArrayBuffer, BufferUsageHint.DynamicDraw,
                                                 nameof(_occlusionMaskEbo));

                GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, sizeof(Vector2), IntPtr.Zero);
                GL.EnableVertexAttribArray(0);
                CheckGlError();
            }

            // FOV FBO.
            _fovRenderTarget = CreateRenderTarget((FovMapSize, 2),
                                                  new RenderTargetFormatParameters(_hasGLFloatFramebuffers ? RenderTargetColorFormat.RG32F : RenderTargetColorFormat.Rgba8, true),
                                                  new TextureSampleParameters {
                WrapMode = TextureWrapMode.Repeat
            },
                                                  nameof(_fovRenderTarget));

            if (_hasGLSamplerObjects)
            {
                _fovFilterSampler = new GLHandle(GL.GenSampler());
                GL.SamplerParameter(_fovFilterSampler.Handle, SamplerParameterName.TextureMagFilter, (int)All.Linear);
                GL.SamplerParameter(_fovFilterSampler.Handle, SamplerParameterName.TextureMinFilter, (int)All.Linear);
                GL.SamplerParameter(_fovFilterSampler.Handle, SamplerParameterName.TextureWrapS, (int)All.Repeat);
                GL.SamplerParameter(_fovFilterSampler.Handle, SamplerParameterName.TextureWrapT, (int)All.Repeat);
                CheckGlError();
            }

            // Shadow FBO.
            _shadowRenderTargetCanInitializeSafely = true;
            MaxLightsPerSceneChanged(_maxLightsPerScene);
        }
예제 #24
0
        public Texture LoadTextureFromImage <T>(Image <T> image, string?name     = null,
                                                TextureLoadParameters?loadParams = null) where T : unmanaged, IPixel <T>
        {
            DebugTools.Assert(_mainThread == Thread.CurrentThread);

            var actualParams = loadParams ?? TextureLoadParameters.Default;
            var pixelType    = typeof(T);

            if (!_hasGLTextureSwizzle)
            {
                // If texture swizzle isn't available we have to pre-process the images to apply it ourselves
                // and then upload as RGBA8.
                // Yes this is inefficient but the alternative is modifying the shaders,
                // which I CBA to do.
                // Even 8 year old iGPUs support texture swizzle.
                if (pixelType == typeof(A8))
                {
                    // Disable sRGB so stuff doesn't get interpreter wrong.
                    actualParams.Srgb = false;
                    var img = ApplyA8Swizzle((Image <A8>)(object) image);
                    return(LoadTextureFromImage(img, name, loadParams));
                }

                if (pixelType == typeof(L8) && !actualParams.Srgb)
                {
                    var img = ApplyL8Swizzle((Image <L8>)(object) image);
                    return(LoadTextureFromImage(img, name, loadParams));
                }
            }

            // Flip image because OpenGL reads images upside down.
            var copy = FlipClone(image);

            var texture = new GLHandle((uint)GL.GenTexture());

            CheckGlError();
            GL.BindTexture(TextureTarget.Texture2D, texture.Handle);
            CheckGlError();
            ApplySampleParameters(actualParams.SampleParameters);

            PixelInternalFormat internalFormat;
            PixelFormat         pixelDataFormat;
            PixelType           pixelDataType;

            if (pixelType == typeof(Rgba32))
            {
                internalFormat  = actualParams.Srgb ? PixelInternalFormat.Srgb8Alpha8 : PixelInternalFormat.Rgba8;
                pixelDataFormat = PixelFormat.Rgba;
                pixelDataType   = PixelType.UnsignedByte;
            }
            else if (pixelType == typeof(A8))
            {
                if (image.Width % 4 != 0 || image.Height % 4 != 0)
                {
                    throw new ArgumentException("Alpha8 images must have multiple of 4 sizes.");
                }

                internalFormat  = PixelInternalFormat.R8;
                pixelDataFormat = PixelFormat.Red;
                pixelDataType   = PixelType.UnsignedByte;

                unsafe
                {
                    // TODO: Does it make sense to default to 1 for RGB parameters?
                    // It might make more sense to pass some options to change swizzling.
                    var swizzle = stackalloc[] { (int)All.One, (int)All.One, (int)All.One, (int)All.Red };
                    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleRgba, swizzle);
                }
            }
            else if (pixelType == typeof(L8) && !actualParams.Srgb)
            {
                // Can only use R8 for L8 if sRGB is OFF.
                // Because OpenGL doesn't provide sRGB single/dual channel image formats.
                // Vulkan when?
                if (copy.Width % 4 != 0 || copy.Height % 4 != 0)
                {
                    throw new ArgumentException("L8 non-sRGB images must have multiple of 4 sizes.");
                }

                internalFormat  = PixelInternalFormat.R8;
                pixelDataFormat = PixelFormat.Red;
                pixelDataType   = PixelType.UnsignedByte;

                unsafe
                {
                    var swizzle = stackalloc[] { (int)All.Red, (int)All.Red, (int)All.Red, (int)All.One };
                    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleRgba, swizzle);
                }
            }
            else
            {
                throw new NotImplementedException($"Unable to handle pixel type '{pixelType.Name}'");
            }

            unsafe
            {
                var span = copy.GetPixelSpan();
                fixed(T *ptr = span)
                {
                    GL.TexImage2D(TextureTarget.Texture2D, 0, internalFormat, copy.Width, copy.Height, 0,
                                  pixelDataFormat, pixelDataType, (IntPtr)ptr);
                    CheckGlError();
                }
            }

            var pressureEst = EstPixelSize(internalFormat) * copy.Width * copy.Height;

            return(GenTexture(texture, (copy.Width, copy.Height), name, pressureEst));
        }
예제 #25
0
 /// <inheritdoc/>
 protected override void GraphicsDeviceResetting()
 {
     _glBuffer = default;
 }
예제 #26
0
        private RenderTexture CreateRenderTarget(Vector2i size, RenderTargetFormatParameters format,
                                                 TextureSampleParameters?sampleParameters = null, string?name = null)
        {
            DebugTools.Assert(size.X != 0);
            DebugTools.Assert(size.Y != 0);

            // Cache currently bound framebuffers
            // so if somebody creates a framebuffer while drawing it won't ruin everything.
            // Note that this means _currentBoundRenderTarget goes temporarily out of sync here
            var boundDrawBuffer = GL.GetInteger(GetPName.DrawFramebufferBinding);
            var boundReadBuffer = 0;

            if (_hasGLReadFramebuffer)
            {
                boundReadBuffer = GL.GetInteger(GetPName.ReadFramebufferBinding);
            }

            // Generate FBO.
            var fbo = new GLHandle(GL.GenFramebuffer());

            // Bind color attachment to FBO.
            GL.BindFramebuffer(FramebufferTarget.Framebuffer, fbo.Handle);
            CheckGlError();

            ObjectLabelMaybe(ObjectLabelIdentifier.Framebuffer, fbo, name);

            var(width, height) = size;

            ClydeTexture textureObject;
            GLHandle     depthStencilBuffer = default;

            var estPixSize = 0L;

            // Color attachment.
            {
                var texture = new GLHandle(GL.GenTexture());
                CheckGlError();

                GL.BindTexture(TextureTarget.Texture2D, texture.Handle);
                CheckGlError();

                ApplySampleParameters(sampleParameters);

                var colorFormat = format.ColorFormat;
                if ((!_hasGLSrgb) && (colorFormat == RTCF.Rgba8Srgb))
                {
                    // If SRGB is not supported, switch formats.
                    // The shaders will have to compensate.
                    // Note that a check is performed on the *original* format.
                    colorFormat = RTCF.Rgba8;
                }
                // This isn't good
                if (!_hasGLFloatFramebuffers)
                {
                    switch (colorFormat)
                    {
                    case RTCF.R32F:
                    case RTCF.RG32F:
                    case RTCF.R11FG11FB10F:
                    case RTCF.Rgba16F:
                        Logger.WarningS("clyde.ogl", "The framebuffer {0} [{1}] is trying to be floating-point when that's not supported. Forcing Rgba8.", name == null ? "[unnamed]" : name, size);
                        colorFormat = RTCF.Rgba8;
                        break;
                    }
                }

                // Make sure to specify the correct pixel type and formats even if we're not uploading any data.
                // Not doing this (just sending red/byte) is fine on desktop GL but illegal on ES.
                var(internalFormat, pixFormat, pixType) = colorFormat switch
                {
                    // using block comments to force formatters to not f**k this up.
                    RTCF.Rgba8 => /*       */ (PIF.Rgba8, /*       */ PF.Rgba, /**/ PT.UnsignedByte),
                    RTCF.Rgba16F => /*     */ (PIF.Rgba16f, /*     */ PF.Rgba, /**/ PT.Float),
                    RTCF.Rgba8Srgb => /*   */ (PIF.Srgb8Alpha8, /* */ PF.Rgba, /**/ PT.UnsignedByte),
                    RTCF.R11FG11FB10F => /**/ (PIF.R11fG11fB10f, /**/ PF.Rgb, /* */ PT.Float),
                    RTCF.R32F => /*        */ (PIF.R32f, /*        */ PF.Red, /* */ PT.Float),
                    RTCF.RG32F => /*       */ (PIF.Rg32f, /*       */ PF.Rg, /*  */ PT.Float),
                    RTCF.R8 => /*          */ (PIF.R8, /*          */ PF.Red, /* */ PT.UnsignedByte),
                    _ => throw new ArgumentOutOfRangeException(nameof(format.ColorFormat), format.ColorFormat, null)
                };

                estPixSize += EstPixelSize(internalFormat);

                GL.TexImage2D(TextureTarget.Texture2D, 0, internalFormat, width, height, 0, pixFormat,
                              pixType, IntPtr.Zero);
                CheckGlError();

                if (!_isGLES)
                {
                    GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0,
                                          texture.Handle,
                                          0);
                }
                else
                {
                    // OpenGL ES uses a different name, and has an odd added target argument
                    GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0,
                                            TextureTarget.Texture2D, texture.Handle, 0);
                }
                CheckGlError();

                // Check on original format is NOT a bug, this is so srgb emulation works
                textureObject = GenTexture(texture, size, format.ColorFormat == RTCF.Rgba8Srgb, name == null ? null : $"{name}-color");
            }

            // Depth/stencil buffers.
            if (format.HasDepthStencil)
            {
                depthStencilBuffer = new GLHandle(GL.GenRenderbuffer());
                GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, depthStencilBuffer.Handle);
                CheckGlError();

                ObjectLabelMaybe(ObjectLabelIdentifier.Renderbuffer, depthStencilBuffer,
                                 name == null ? null : $"{name}-depth-stencil");

                GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.Depth24Stencil8, width,
                                       height);
                CheckGlError();

                estPixSize += 4;

                GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthAttachment,
                                           RenderbufferTarget.Renderbuffer, depthStencilBuffer.Handle);
                GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.StencilAttachment,
                                           RenderbufferTarget.Renderbuffer, depthStencilBuffer.Handle);
                CheckGlError();
            }

            // This should always pass but OpenGL makes it easy to check for once so let's.
            var status = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer);

            CheckGlError();
            DebugTools.Assert(status == FramebufferErrorCode.FramebufferComplete,
                              $"new framebuffer has bad status {status}");

            // Re-bind previous framebuffers (thus _currentBoundRenderTarget is back in sync)
            GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, boundDrawBuffer);
            CheckGlError();
            if (_hasGLReadFramebuffer)
            {
                GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, boundReadBuffer);
                CheckGlError();
            }

            var pressure = estPixSize * size.X * size.Y;

            var handle = AllocRid();
            var data   = new LoadedRenderTarget
            {
                IsWindow           = false,
                IsSrgb             = textureObject.IsSrgb,
                DepthStencilHandle = depthStencilBuffer,
                FramebufferHandle  = fbo,
                Size           = size,
                TextureHandle  = textureObject.TextureId,
                MemoryPressure = pressure
            };

            //GC.AddMemoryPressure(pressure);
            var renderTarget = new RenderTexture(size, textureObject, this, handle);

            _renderTargets.Add(handle, data);
            return(renderTarget);
        }
예제 #27
0
파일: Texture2D.cs 프로젝트: Perksey/Mana
        public static unsafe Texture2D CreateFromStreamUnsynchronized(RenderContext renderContext, Stream stream)
        {
            using var image = Image.Load <Rgba32>(stream);
            image.Mutate(x => x.Flip(FlipMode.Vertical));

            var texture = new Texture2D(renderContext)
            {
                Width  = image.Width,
                Height = image.Height,
            };

            var span = image.GetPixelSpan();
            int size = span.Length * sizeof(Rgba32);

            fixed(void *data = &MemoryMarshal.GetReference(span))
            {
                var start = new IntPtr(data);

                using var pixelBuffer = PixelBuffer.Create <Rgba32>(renderContext, size, true, true);

                GLHandle prevPixelBuffer = (GLHandle)GL.GetInteger(GetPName.PixelUnpackBufferBinding);

                GL.BindBuffer(BufferTarget.PixelUnpackBuffer, pixelBuffer.Handle);

                // When we load assets asynchronously, using SubData to set the data will cause the main thread
                // to wait for the GL call to complete, so we use a PBO and fill it with a mapped memory range to
                // prevent OpenGL synchronization from causing frame drops on the main thread.

                IntPtr pixelPointer = GL.MapBufferRange(BufferTarget.PixelUnpackBuffer,
                                                        IntPtr.Zero,
                                                        size,
                                                        BufferAccessMask.MapWriteBit
                                                        | BufferAccessMask.MapUnsynchronizedBit
                                                        | BufferAccessMask.MapInvalidateRangeBit);

                if (pixelPointer == IntPtr.Zero)
                {
                    throw new GraphicsContextException("Could not map PixelUnbackBuffer range.");
                }

                // We send the data to mapped memory in multiple batches instead of one large one for the same
                // reason.

                int       remaining = size;
                const int step      = 2048;

                while (remaining > 0)
                {
                    int   currentStep = Math.Min(remaining, step);
                    int   point       = size - remaining;
                    void *dest        = (void *)IntPtr.Add(pixelPointer, point);
                    void *src         = (void *)IntPtr.Add(start, point);
                    Unsafe.CopyBlock(dest, src, (uint)currentStep);

                    remaining -= step;
                }

                GL.UnmapBuffer(BufferTarget.PixelUnpackBuffer);

                if (GLInfo.HasDirectStateAccess)
                {
                    GL.TextureStorage2D(texture.Handle,
                                        1,
                                        SizedInternalFormat.Rgba8,
                                        texture.Width,
                                        texture.Height);

                    GL.TextureSubImage2D(texture.Handle,
                                         0,
                                         0,
                                         0,
                                         texture.Width,
                                         texture.Height,
                                         PixelFormat.Rgba,
                                         PixelType.UnsignedByte,
                                         IntPtr.Zero);

                    GL.GenerateTextureMipmap(texture.Handle);
                }
                else
                {
                    var previousTexture = renderContext.TextureUnits[0].Texture2D;
                    renderContext.BindTexture(0, texture);

                    GL.TexImage2D(TextureTarget.Texture2D,
                                  0,
                                  PixelInternalFormat.Rgba,
                                  texture.Width,
                                  texture.Height,
                                  0,
                                  PixelFormat.Rgba,
                                  PixelType.UnsignedByte,
                                  IntPtr.Zero);

                    GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);

                    renderContext.BindTexture(0, previousTexture);
                }

                GL.BindBuffer(BufferTarget.PixelUnpackBuffer, prevPixelBuffer);
            }

            texture.SetDefaultTextureParameters(renderContext);

            // TODO: Look into if this is necessary (?)
            GL.Finish();

            return(texture);
        }
예제 #28
0
        public Texture LoadTextureFromImage <T>(Image <T> image, string name     = null,
                                                TextureLoadParameters?loadParams = null) where T : unmanaged, IPixel <T>
        {
            DebugTools.Assert(_mainThread == Thread.CurrentThread);

            var actualParams = loadParams ?? TextureLoadParameters.Default;
            var pixelType    = typeof(T);

            // Flip image because OpenGL reads images upside down.
            var copy = FlipClone(image);

            var texture = new GLHandle((uint)GL.GenTexture());

            GL.BindTexture(TextureTarget.Texture2D, texture.Handle);
            ApplySampleParameters(actualParams.SampleParameters);

            PixelInternalFormat internalFormat;
            PixelFormat         pixelDataFormat;
            PixelType           pixelDataType;

            if (pixelType == typeof(Rgba32))
            {
                internalFormat  = actualParams.Srgb ? PixelInternalFormat.Srgb8Alpha8 : PixelInternalFormat.Rgba8;
                pixelDataFormat = PixelFormat.Rgba;
                pixelDataType   = PixelType.UnsignedByte;
            }
            else if (pixelType == typeof(Alpha8))
            {
                if (image.Width % 4 != 0 || image.Height % 4 != 0)
                {
                    throw new ArgumentException("Alpha8 images must have multiple of 4 sizes.");
                }
                internalFormat  = PixelInternalFormat.R8;
                pixelDataFormat = PixelFormat.Red;
                pixelDataType   = PixelType.UnsignedByte;

                // TODO: Does it make sense to default to 1 for RGB parameters?
                // It might make more sense to pass some options to change swizzling.
                var swizzle = new[] { (int)All.One, (int)All.One, (int)All.One, (int)All.Red };
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleRgba, swizzle);
            }
            else if (pixelType == typeof(Gray8) && !actualParams.Srgb)
            {
                // Can only use R8 for Gray8 if sRGB is OFF.
                // Because OpenGL doesn't provide non-sRGB single/dual channel image formats.
                // Vulkan when?
                if (copy.Width % 4 != 0 || copy.Height % 4 != 0)
                {
                    throw new ArgumentException("Gray8 non-sRGB images must have multiple of 4 sizes.");
                }

                internalFormat  = PixelInternalFormat.R8;
                pixelDataFormat = PixelFormat.Red;
                pixelDataType   = PixelType.UnsignedByte;

                var swizzle = new[] { (int)All.Red, (int)All.Red, (int)All.Red, (int)All.One };
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleRgba, swizzle);
            }
            else
            {
                throw new NotImplementedException($"Unable to handle pixel type '{pixelType.Name}'");
            }

            unsafe
            {
                var span = copy.GetPixelSpan();
                fixed(T *ptr = span)
                {
                    GL.TexImage2D(TextureTarget.Texture2D, 0, internalFormat, copy.Width, copy.Height, 0,
                                  pixelDataFormat, pixelDataType, (IntPtr)ptr);
                }
            }

            return(GenTexture(texture, (copy.Width, copy.Height), name));
        }
예제 #29
0
        private RenderTexture CreateRenderTarget(Vector2i size, RenderTargetFormatParameters format,
                                                 TextureSampleParameters?sampleParameters = null, string?name = null)
        {
            DebugTools.Assert(size.X != 0);
            DebugTools.Assert(size.Y != 0);

            // Cache currently bound framebuffers
            // so if somebody creates a framebuffer while drawing it won't ruin everything.
            var boundDrawBuffer = GL.GetInteger(GetPName.DrawFramebufferBinding);
            var boundReadBuffer = GL.GetInteger(GetPName.ReadFramebufferBinding);

            // Generate FBO.
            var fbo = new GLHandle(GL.GenFramebuffer());

            // Bind color attachment to FBO.
            GL.BindFramebuffer(FramebufferTarget.Framebuffer, fbo.Handle);

            ObjectLabelMaybe(ObjectLabelIdentifier.Framebuffer, fbo, name);

            var(width, height) = size;

            ClydeTexture textureObject;
            GLHandle     depthStencilBuffer = default;

            var estPixSize = 0L;

            // Color attachment.
            {
                var texture = new GLHandle(GL.GenTexture());

                GL.BindTexture(TextureTarget.Texture2D, texture.Handle);

                ApplySampleParameters(sampleParameters);

                // Make sure to specify the correct pixel type and formats even if we're not uploading any data.
                // Not doing this (just sending red/byte) is fine on desktop GL but illegal on ES.
                var(internalFormat, pixFormat, pixType) = format.ColorFormat switch
                {
                    // using block comments to force formatters to not f**k this up.
                    RTCF.Rgba8 => /*       */ (PIF.Rgba8, /*       */ PF.Rgba, /**/ PT.UnsignedByte),
                    RTCF.Rgba16F => /*     */ (PIF.Rgba16f, /*     */ PF.Rgba, /**/ PT.Float),
                    RTCF.Rgba8Srgb => /*   */ (PIF.Srgb8Alpha8, /* */ PF.Rgba, /**/ PT.UnsignedByte),
                    RTCF.R11FG11FB10F => /**/ (PIF.R11fG11fB10f, /**/ PF.Rgb, /* */ PT.Float),
                    RTCF.R32F => /*        */ (PIF.R32f, /*        */ PF.Red, /* */ PT.Float),
                    RTCF.RG32F => /*       */ (PIF.Rg32f, /*       */ PF.Rg, /*  */ PT.Float),
                    RTCF.R8 => /*          */ (PIF.R8, /*          */ PF.Red, /* */ PT.UnsignedByte),
                    _ => throw new ArgumentOutOfRangeException(nameof(format.ColorFormat), format.ColorFormat, null)
                };

                estPixSize += EstPixelSize(internalFormat);

                GL.TexImage2D(TextureTarget.Texture2D, 0, internalFormat, width, height, 0, pixFormat,
                              pixType, IntPtr.Zero);

                GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0,
                                      texture.Handle,
                                      0);

                textureObject = GenTexture(texture, size, name == null ? null : $"{name}-color");
            }

            // Depth/stencil buffers.
            if (format.HasDepthStencil)
            {
                depthStencilBuffer = new GLHandle(GL.GenRenderbuffer());
                GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, depthStencilBuffer.Handle);

                ObjectLabelMaybe(ObjectLabelIdentifier.Renderbuffer, depthStencilBuffer,
                                 name == null ? null : $"{name}-depth-stencil");

                GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.Depth24Stencil8, width,
                                       height);

                estPixSize += 4;

                GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthStencilAttachment,
                                           RenderbufferTarget.Renderbuffer, depthStencilBuffer.Handle);
            }

            // This should always pass but OpenGL makes it easy to check for once so let's.
            var status = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer);

            DebugTools.Assert(status == FramebufferErrorCode.FramebufferComplete,
                              $"new framebuffer has bad status {status}");

            // Re-bind previous framebuffers.
            GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, boundDrawBuffer);
            GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, boundReadBuffer);

            var pressure = estPixSize * size.X * size.Y;

            var handle = AllocRid();
            var data   = new LoadedRenderTarget
            {
                IsWindow           = false,
                DepthStencilHandle = depthStencilBuffer,
                FramebufferHandle  = fbo,
                Size           = size,
                TextureHandle  = textureObject.TextureId,
                MemoryPressure = pressure
            };

            //GC.AddMemoryPressure(pressure);
            var renderTarget = new RenderTexture(size, textureObject, this, handle);

            _renderTargets.Add(handle, data);
            return(renderTarget);
        }
예제 #30
0
 /// <summary>
 ///   IComparable Implementation
 /// </summary>
 public int CompareTo(T other)
 {
     return(GLHandle.CompareTo(other.GLHandle));
 }