public static void UseProgram(int?shader) { ThreadSafety.EnsureDrawThread(); if (shader != null) { shader_stack.Push(shader.Value); } else { shader_stack.Pop(); //check if the stack is empty, and if so don't restore the previous shader. if (shader_stack.Count == 0) { return; } } int s = shader ?? shader_stack.Peek(); if (currentShader == s) { return; } FrameStatistics.Increment(StatisticsCounterType.ShaderBinds); FlushCurrentBatch(); GL.UseProgram(s); currentShader = s; }
public static void UseProgram(int?shader) { ThreadSafety.EnsureDrawThread(); if (shader != null) { shaderStack.Push(shader.Value); } else { shaderStack.Pop(); //check if the stack is empty, and if so don't restore the previous shader. if (shaderStack.Count == 0) { return; } } int s = shader ?? shaderStack.Peek(); if (currentShader == s) { return; } GL.UseProgram(s); currentShader = s; }
/// <summary> /// Initialises this <see cref="VertexBuffer{T}"/>. Guaranteed to be run on the draw thread. /// </summary> protected virtual void Initialise() { ThreadSafety.EnsureDrawThread(); GL.GenBuffers(1, out vboId); if (GLWrapper.BindBuffer(BufferTarget.ArrayBuffer, vboId)) VertexUtils<DepthWrappingVertex<T>>.Bind(); GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Length * STRIDE), IntPtr.Zero, usage); }
/// <summary> /// Rezizes the buffer to the target size in bytes /// </summary> /// <param name="targetSize"></param> public void Resize(int targetSize) { if (targetSize != currentBufferSize) { EnsureCreated(); // We should never run raw OGL calls on another thread than the main thread due to race conditions. ThreadSafety.EnsureDrawThread(); GL.BindBuffer(BufferTarget.TextureBuffer, bufferId); // Reallocate GL.BufferData(BufferTarget.TextureBuffer, targetSize, IntPtr.Zero, BufferUsageHint.DynamicDraw); currentBufferSize = targetSize; } }
public void SetData(float[] data) { // We should never run raw OGL calls on another thread than the main thread due to race conditions. ThreadSafety.EnsureDrawThread(); EnsureCreated(); int byteLength = data.Length * 4; // Set buffer data if (currentBufferSize < byteLength) { Resize(byteLength); } // Update GL.BindBuffer(BufferTarget.TextureBuffer, bufferId); GL.BufferSubData(BufferTarget.TextureBuffer, IntPtr.Zero, byteLength, data); }
internal override bool Upload() { // We should never run raw OGL calls on another thread than the main thread due to race conditions. ThreadSafety.EnsureDrawThread(); if (IsDisposed) { throw new ObjectDisposedException(ToString(), "Can not upload data to a disposed texture."); } bool didUpload = false; while (uploadQueue.TryDequeue(out TextureUpload upload)) { IntPtr dataPointer; GCHandle?h0; if (upload.Data.Length == 0) { h0 = null; dataPointer = IntPtr.Zero; } else { h0 = GCHandle.Alloc(upload.Data, GCHandleType.Pinned); dataPointer = h0.Value.AddrOfPinnedObject(); didUpload = true; } try { // Do we need to generate a new texture? if (textureId <= 0 || internalWidth != width || internalHeight != height) { internalWidth = width; internalHeight = height; // We only need to generate a new texture if we don't have one already. Otherwise just re-use the current one. if (textureId <= 0) { int[] textures = new int[1]; GL.GenTextures(1, textures); textureId = textures[0]; GLWrapper.BindTexture(this); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)(manualMipmaps ? filteringMode : (filteringMode == All.Linear ? All.LinearMipmapLinear : All.Nearest))); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)filteringMode); // 33085 is GL_TEXTURE_MAX_LEVEL, which is not available within TextureParameterName. // It controls the amount of mipmap levels generated by GL.GenerateMipmap later on. GL.TexParameter(TextureTarget.Texture2D, (TextureParameterName)33085, MAX_MIPMAP_LEVELS); updateWrapMode(); } else { GLWrapper.BindTexture(this); } if (width == upload.Bounds.Width && height == upload.Bounds.Height || dataPointer == IntPtr.Zero) { GL.TexImage2D(TextureTarget2d.Texture2D, upload.Level, TextureComponentCount.Srgb8Alpha8, width, height, 0, upload.Format, PixelType.UnsignedByte, dataPointer); } else { initializeLevel(upload.Level, width, height); GL.TexSubImage2D(TextureTarget2d.Texture2D, upload.Level, upload.Bounds.X, upload.Bounds.Y, upload.Bounds.Width, upload.Bounds.Height, upload.Format, PixelType.UnsignedByte, dataPointer); } } // Just update content of the current texture else if (dataPointer != IntPtr.Zero) { GLWrapper.BindTexture(this); if (!manualMipmaps && upload.Level > 0) { //allocate mipmap levels int level = 1; int d = 2; while (width / d > 0) { initializeLevel(level, width / d, height / d); level++; d *= 2; } manualMipmaps = true; } int div = (int)Math.Pow(2, upload.Level); GL.TexSubImage2D(TextureTarget2d.Texture2D, upload.Level, upload.Bounds.X / div, upload.Bounds.Y / div, upload.Bounds.Width / div, upload.Bounds.Height / div, upload.Format, PixelType.UnsignedByte, dataPointer); } } finally { h0?.Free(); upload.Dispose(); } } if (didUpload && !manualMipmaps) { GL.Hint(HintTarget.GenerateMipmapHint, HintMode.Nicest); GL.GenerateMipmap(TextureTarget.Texture2D); } return(didUpload); }
internal override bool Upload() { // We should never run raw OGL calls on another thread than the main thread due to race conditions. ThreadSafety.EnsureDrawThread(); if (isDisposed) { return(false); } IntPtr dataPointer; GCHandle? h0; TextureUpload upload; bool didUpload = false; while (uploadQueue.TryDequeue(out upload)) { if (upload.Data.Length == 0) { h0 = null; dataPointer = IntPtr.Zero; } else { h0 = GCHandle.Alloc(upload.Data, GCHandleType.Pinned); dataPointer = h0.Value.AddrOfPinnedObject(); didUpload = true; } try { // Do we need to generate a new texture? if (textureId <= 0 || internalWidth < width || internalHeight < height) { internalWidth = width; internalHeight = height; // We only need to generate a new texture if we don't have one already. Otherwise just re-use the current one. if (textureId <= 0) { int[] textures = new int[1]; GL.GenTextures(1, textures); textureId = textures[0]; GLWrapper.BindTexture(textureId); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.LinearMipmapLinear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear); updateWrapMode(); } else { GLWrapper.BindTexture(textureId); } if (width == upload.Bounds.Width && height == upload.Bounds.Height || dataPointer == IntPtr.Zero) { GL.TexImage2D(TextureTarget2d.Texture2D, upload.Level, TextureComponentCount.Rgba, width, height, 0, upload.Format, PixelType.UnsignedByte, dataPointer); } else { initializeLevel(upload.Level, width, height); GL.TexSubImage2D(TextureTarget2d.Texture2D, upload.Level, upload.Bounds.X, upload.Bounds.Y, upload.Bounds.Width, upload.Bounds.Height, upload.Format, PixelType.UnsignedByte, dataPointer); } } // Just update content of the current texture else if (dataPointer != IntPtr.Zero) { GLWrapper.BindTexture(textureId); if (!manualMipmaps && upload.Level > 0) { //allocate mipmap levels int level = 1; int d = 2; while (width / d > 0) { initializeLevel(level, width / d, height / d); level++; d *= 2; } manualMipmaps = true; } int div = (int)Math.Pow(2, upload.Level); GL.TexSubImage2D(TextureTarget2d.Texture2D, upload.Level, upload.Bounds.X / div, upload.Bounds.Y / div, upload.Bounds.Width / div, upload.Bounds.Height / div, upload.Format, PixelType.UnsignedByte, dataPointer); } } finally { h0?.Free(); upload?.Dispose(); } } if (didUpload && !manualMipmaps) { GL.Hint(HintTarget.GenerateMipmapHint, HintMode.Nicest); GL.GenerateMipmap(TextureTarget.Texture2D); } return(didUpload); }