public void Apply(CommandList commandList, BlendState oldBlendState) { // note: need to update blend equation, blend function and color mask even when the blend state is disable in order to keep the hash based caching system valid if (blendEnable && !oldBlendState.blendEnable) { GL.Enable(EnableCap.Blend); } if (blendEquationHash != oldBlendState.blendEquationHash) { GL.BlendEquationSeparate(blendEquationModeColor, blendEquationModeAlpha); } if (blendFuncHash != oldBlendState.blendFuncHash) { GL.BlendFuncSeparate(blendFactorSrcColor, blendFactorDestColor, blendFactorSrcAlpha, blendFactorDestAlpha); } if (commandList.NewBlendFactor != commandList.BoundBlendFactor) { commandList.BoundBlendFactor = commandList.NewBlendFactor; GL.BlendColor(OpenGLConvertExtensions.ToOpenGL(commandList.NewBlendFactor)); } if (ColorWriteChannels != oldBlendState.ColorWriteChannels) { RestoreColorMask(); } if (!blendEnable && oldBlendState.blendEnable) { GL.Disable(EnableCap.Blend); } }
/// <summary> /// Initializes a new instance of the <see cref="Buffer" /> class. /// </summary> /// <param name="description">The description.</param> /// <param name="viewFlags">Type of the buffer.</param> /// <param name="viewFormat">The view format.</param> /// <param name="dataPointer">The data pointer.</param> protected Buffer InitializeFromImpl(BufferDescription description, BufferFlags viewFlags, PixelFormat viewFormat, IntPtr dataPointer) { bufferDescription = description; ViewFlags = viewFlags; bool isCompressed; OpenGLConvertExtensions.ConvertPixelFormat(GraphicsDevice, ref viewFormat, out TextureInternalFormat, out TextureFormat, out TextureType, out bufferTextureElementSize, out isCompressed); ViewFormat = viewFormat; Recreate(dataPointer); if (GraphicsDevice != null) { GraphicsDevice.BuffersMemory += SizeInBytes / (float)0x100000; } return(this); }
/// <summary> /// Initializes a new instance of the <see cref="Buffer" /> class. /// </summary> /// <param name="description">The description.</param> /// <param name="viewFlags">Type of the buffer.</param> /// <param name="viewFormat">The view format.</param> /// <param name="dataPointer">The data pointer.</param> protected Buffer InitializeFromImpl(BufferDescription description, BufferFlags viewFlags, PixelFormat viewFormat, IntPtr dataPointer) { bufferDescription = description; ViewFlags = viewFlags; #if !SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES int pixelSize; bool isCompressed; OpenGLConvertExtensions.ConvertPixelFormat(GraphicsDevice, ref viewFormat, out internalFormat, out glPixelFormat, out type, out pixelSize, out isCompressed); #endif ViewFormat = viewFormat; Recreate(dataPointer); if (GraphicsDevice != null) { GraphicsDevice.BuffersMemory += SizeInBytes / (float)0x100000; } return(this); }
private void InitializeFromImpl(DataBox[] dataBoxes = null) { if (ParentTexture != null) { resourceId = ParentTexture.ResourceId; // copy parameters InternalFormat = ParentTexture.InternalFormat; FormatGl = ParentTexture.FormatGl; Type = ParentTexture.Type; Target = ParentTexture.Target; DepthPitch = ParentTexture.DepthPitch; RowPitch = ParentTexture.RowPitch; IsDepthBuffer = ParentTexture.IsDepthBuffer; HasStencil = ParentTexture.HasStencil; IsRenderbuffer = ParentTexture.IsRenderbuffer; resourceIdStencil = ParentTexture.ResourceIdStencil; pixelBufferObjectId = ParentTexture.PixelBufferObjectId; } if (resourceId == 0) { switch (Dimension) { case TextureDimension.Texture1D: #if !SILICONSTUDIO_PLATFORM_MONO_MOBILE Target = TextureTarget.Texture1D; break; #endif case TextureDimension.Texture2D: Target = TextureTarget.Texture2D; break; case TextureDimension.Texture3D: Target = TextureTarget.Texture3D; break; case TextureDimension.TextureCube: Target = TextureTarget.TextureCubeMap; break; default: throw new ArgumentOutOfRangeException(); } PixelInternalFormat internalFormat; PixelFormatGl format; PixelType type; int pixelSize; bool compressed; OpenGLConvertExtensions.ConvertPixelFormat(GraphicsDevice, ref textureDescription.Format, out internalFormat, out format, out type, out pixelSize, out compressed); InternalFormat = internalFormat; FormatGl = format; Type = type; DepthPitch = Description.Width * Description.Height * pixelSize; RowPitch = Description.Width * pixelSize; if ((Description.Flags & TextureFlags.DepthStencil) != 0) { IsDepthBuffer = true; HasStencil = InternalHasStencil(Format); } else { IsDepthBuffer = false; HasStencil = false; } if ((Description.Flags & TextureFlagsCustomResourceId) != 0) { return; } using (GraphicsDevice.UseOpenGLCreationContext()) { // Depth texture are render buffer for now // TODO: enable switch if ((Description.Flags & TextureFlags.DepthStencil) != 0 && (Description.Flags & TextureFlags.ShaderResource) == 0) { RenderbufferStorage depth, stencil; ConvertDepthFormat(GraphicsDevice, Description.Format, out depth, out stencil); GL.GenRenderbuffers(1, out resourceId); GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, resourceId); GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, depth, Width, Height); if (stencil != 0) { // separate stencil GL.GenRenderbuffers(1, out resourceIdStencil); GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, resourceIdStencil); GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, stencil, Width, Height); } else if (HasStencil) { // depth+stencil in a single texture resourceIdStencil = resourceId; } GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, 0); IsRenderbuffer = true; return; } else { GL.GenTextures(1, out resourceId); GL.BindTexture(Target, resourceId); IsRenderbuffer = false; } // No filtering on depth buffer if ((Description.Flags & (TextureFlags.RenderTarget | TextureFlags.DepthStencil)) != TextureFlags.None) { GL.TexParameter(Target, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest); GL.TexParameter(Target, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest); GL.TexParameter(Target, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge); GL.TexParameter(Target, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge); BoundSamplerState = GraphicsDevice.SamplerStates.PointClamp; } #if SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES else if (Description.MipLevels <= 1) { GL.TexParameter(Target, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest); GL.TexParameter(Target, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); } #endif #if SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES if (!GraphicsDevice.IsOpenGLES2) #endif { GL.TexParameter(Target, TextureParameterName.TextureBaseLevel, 0); GL.TexParameter(Target, TextureParameterName.TextureMaxLevel, Description.MipLevels - 1); } if (Description.MipLevels == 0) { throw new NotImplementedException(); } var setSize = TextureSetSize(Target); for (var arrayIndex = 0; arrayIndex < Description.ArraySize; ++arrayIndex) { var offsetArray = arrayIndex * Description.MipLevels; for (int i = 0; i < Description.MipLevels; ++i) { IntPtr data = IntPtr.Zero; var width = CalculateMipSize(Description.Width, i); var height = CalculateMipSize(Description.Height, i); if (dataBoxes != null && i < dataBoxes.Length) { if (setSize > 1 && !compressed && dataBoxes[i].RowPitch != width * pixelSize) { throw new NotSupportedException("Can't upload texture with pitch in glTexImage2D."); } // Might be possible, need to check API better. data = dataBoxes[offsetArray + i].DataPointer; } if (setSize == 2) { var dataSetTarget = GetTextureTargetForDataSet2D(Target, arrayIndex); if (compressed) { GL.CompressedTexImage2D(dataSetTarget, i, (CompressedInternalFormat2D)internalFormat, width, height, 0, dataBoxes[offsetArray + i].SlicePitch, data); } else { GL.TexImage2D(dataSetTarget, i, internalFormat, width, height, 0, format, type, data); } } else if (setSize == 3) { var dataSetTarget = GetTextureTargetForDataSet3D(Target); var depth = Target == TextureTarget.Texture2DArray ? Description.Depth : CalculateMipSize(Description.Depth, i); // no depth mipmaps in Texture2DArray if (compressed) { GL.CompressedTexImage3D(dataSetTarget, i, (CompressedInternalFormat3D)internalFormat, width, height, depth, 0, dataBoxes[offsetArray + i].SlicePitch, data); } else { GL.TexImage3D(dataSetTarget, i, (TextureComponentCount3D)internalFormat, width, height, depth, 0, format, type, data); } } #if !SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES else if (setSize == 1) { if (compressed) { GL.CompressedTexImage1D(TextureTarget.Texture1D, i, internalFormat, width, 0, dataBoxes[offsetArray + i].SlicePitch, data); } else { GL.TexImage1D(TextureTarget.Texture1D, i, internalFormat, width, 0, format, type, data); } } #endif } } GL.BindTexture(Target, 0); InitializePixelBufferObject(); } GraphicsDevice.TextureMemory += (Depth * DepthStride) / (float)0x100000; } }
private void InitializeFromImpl(DataBox[] dataBoxes = null) { if (ParentTexture != null) { TextureId = ParentTexture.TextureId; // copy parameters TextureInternalFormat = ParentTexture.TextureInternalFormat; TextureFormat = ParentTexture.TextureFormat; TextureType = ParentTexture.TextureType; TextureTarget = ParentTexture.TextureTarget; DepthPitch = ParentTexture.DepthPitch; RowPitch = ParentTexture.RowPitch; IsDepthBuffer = ParentTexture.IsDepthBuffer; HasStencil = ParentTexture.HasStencil; IsRenderbuffer = ParentTexture.IsRenderbuffer; stencilId = ParentTexture.StencilId; pixelBufferObjectId = ParentTexture.PixelBufferObjectId; } if (TextureId == 0) { switch (Dimension) { case TextureDimension.Texture1D: #if !SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES if (ArraySize > 1) { throw new PlatformNotSupportedException("Texture1DArray is not implemented under OpenGL"); } TextureTarget = TextureTarget.Texture1D; break; #endif case TextureDimension.Texture2D: TextureTarget = ArraySize > 1 ? TextureTarget.Texture2DArray : TextureTarget.Texture2D; break; case TextureDimension.Texture3D: TextureTarget = TextureTarget.Texture3D; break; case TextureDimension.TextureCube: if (ArraySize > 6) { throw new PlatformNotSupportedException("TextureCubeArray is not implemented under OpenGL"); } TextureTarget = TextureTarget.TextureCubeMap; break; default: throw new ArgumentOutOfRangeException(); } bool compressed; OpenGLConvertExtensions.ConvertPixelFormat(GraphicsDevice, ref textureDescription.Format, out TextureInternalFormat, out TextureFormat, out TextureType, out TexturePixelSize, out compressed); DepthPitch = Description.Width * Description.Height * TexturePixelSize; RowPitch = Description.Width * TexturePixelSize; if ((Description.Flags & TextureFlags.DepthStencil) != 0) { IsDepthBuffer = true; HasStencil = InternalHasStencil(Format); } else { IsDepthBuffer = false; HasStencil = false; } if ((Description.Flags & TextureFlagsCustomResourceId) != 0) { return; } using (var openglContext = GraphicsDevice.UseOpenGLCreationContext()) { // Depth texture are render buffer for now // TODO: enable switch if ((Description.Flags & TextureFlags.DepthStencil) != 0 && (Description.Flags & TextureFlags.ShaderResource) == 0) { RenderbufferStorage depth, stencil; ConvertDepthFormat(GraphicsDevice, Description.Format, out depth, out stencil); GL.GenRenderbuffers(1, out TextureId); GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, TextureId); GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, depth, Width, Height); if (stencil != 0) { // separate stencil GL.GenRenderbuffers(1, out stencilId); GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, stencilId); GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, stencil, Width, Height); } else if (HasStencil) { // depth+stencil in a single texture stencilId = TextureId; } GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, 0); IsRenderbuffer = true; return; } IsRenderbuffer = false; TextureTotalSize = ComputeBufferTotalSize(); if (Description.Usage == GraphicsResourceUsage.Staging) { InitializeStagingPixelBufferObject(dataBoxes); return; } GL.GenTextures(1, out TextureId); GL.BindTexture(TextureTarget, TextureId); // No filtering on depth buffer if ((Description.Flags & (TextureFlags.RenderTarget | TextureFlags.DepthStencil)) != TextureFlags.None) { GL.TexParameter(TextureTarget, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest); GL.TexParameter(TextureTarget, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest); GL.TexParameter(TextureTarget, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge); GL.TexParameter(TextureTarget, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge); BoundSamplerState = GraphicsDevice.SamplerStates.PointClamp; if (HasStencil) { // depth+stencil in a single texture stencilId = TextureId; } } #if SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES else if (Description.MipLevels <= 1) { GL.TexParameter(TextureTarget, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest); GL.TexParameter(TextureTarget, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); } #endif #if SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES if (!GraphicsDevice.IsOpenGLES2) #endif { GL.TexParameter(TextureTarget, TextureParameterName.TextureBaseLevel, 0); GL.TexParameter(TextureTarget, TextureParameterName.TextureMaxLevel, Description.MipLevels - 1); } if (Description.MipLevels == 0) { throw new NotImplementedException(); } var setSize = TextureSetSize(TextureTarget); for (var arrayIndex = 0; arrayIndex < Description.ArraySize; ++arrayIndex) { var offsetArray = arrayIndex * Description.MipLevels; for (int i = 0; i < Description.MipLevels; ++i) { DataBox dataBox; var width = CalculateMipSize(Description.Width, i); var height = CalculateMipSize(Description.Height, i); var depth = CalculateMipSize(Description.Depth, i); if (dataBoxes != null && i < dataBoxes.Length) { if (setSize > 1 && !compressed && dataBoxes[i].RowPitch != width * TexturePixelSize) { throw new NotSupportedException("Can't upload texture with pitch in glTexImage2D/3D."); } // Might be possible, need to check API better. dataBox = dataBoxes[offsetArray + i]; } else { dataBox = new DataBox(); } switch (TextureTarget) { #if !SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES case TextureTarget.Texture1D: if (compressed) { GL.CompressedTexImage1D(TextureTarget, i, TextureInternalFormat, width, 0, dataBox.SlicePitch, dataBox.DataPointer); } else { GL.TexImage1D(TextureTarget, i, TextureInternalFormat, width, 0, TextureFormat, TextureType, dataBox.DataPointer); } break; #endif case TextureTarget.Texture2D: case TextureTarget.TextureCubeMap: { var dataSetTarget = GetTextureTargetForDataSet2D(TextureTarget, arrayIndex); if (compressed) { GL.CompressedTexImage2D(dataSetTarget, i, (CompressedInternalFormat2D)TextureInternalFormat, width, height, 0, dataBox.SlicePitch, dataBox.DataPointer); } else { GL.TexImage2D(dataSetTarget, i, (TextureComponentCount2D)TextureInternalFormat, width, height, 0, TextureFormat, TextureType, dataBox.DataPointer); } break; } case TextureTarget.Texture3D: { if (compressed) { GL.CompressedTexImage3D((TextureTarget3d)TextureTarget, i, (CompressedInternalFormat3D)TextureInternalFormat, width, height, depth, 0, dataBox.SlicePitch, dataBox.DataPointer); } else { GL.TexImage3D((TextureTarget3d)TextureTarget, i, (TextureComponentCount3D)TextureInternalFormat, width, height, depth, 0, TextureFormat, TextureType, dataBox.DataPointer); } break; } case TextureTarget.Texture2DArray: { // We create all array slices at once, but upload them one by one if (arrayIndex == 0) { if (compressed) { GL.CompressedTexImage3D((TextureTarget3d)TextureTarget, i, (CompressedInternalFormat3D)TextureInternalFormat, width, height, ArraySize, 0, 0, IntPtr.Zero); } else { GL.TexImage3D((TextureTarget3d)TextureTarget, i, (TextureComponentCount3D)TextureInternalFormat, width, height, ArraySize, 0, TextureFormat, TextureType, IntPtr.Zero); } } if (dataBox.DataPointer != IntPtr.Zero) { if (compressed) { GL.CompressedTexSubImage3D((TextureTarget3d)TextureTarget, i, 0, 0, arrayIndex, width, height, 1, TextureFormat, dataBox.SlicePitch, dataBox.DataPointer); } else { GL.TexSubImage3D((TextureTarget3d)TextureTarget, i, 0, 0, arrayIndex, width, height, 1, TextureFormat, TextureType, dataBox.DataPointer); } } break; } } } } GL.BindTexture(TextureTarget, 0); if (openglContext.CommandList != null) { // If we messed up with some states of a command list, mark dirty states openglContext.CommandList.boundShaderResourceViews[openglContext.CommandList.activeTexture] = null; } } GraphicsDevice.TextureMemory += (Depth * DepthStride) / (float)0x100000; } }
/// <summary> /// Inits this instance with the specified texture datas. /// </summary> /// <param name="textureDatas">The texture datas.</param> protected virtual void Init(DataBox[] textureDatas) { if (Target != TextureTarget.Texture2D && Target != TextureTarget.TextureCubeMap) { throw new Exception("incorrect type of Texture2D, it should be TextureTarget.Texture2D or TextureTarget.TextureCubeMap"); } using (var creationContext = GraphicsDevice.UseOpenGLCreationContext()) { // Can we just do a renderbuffer? if ((Description.Flags & TextureFlags.ShaderResource) == 0) { if ((Description.Flags & TextureFlags.DepthStencil) == TextureFlags.DepthStencil) { RenderbufferStorage depth, stencil; ConvertDepthFormat(GraphicsDevice, Description.Format, out depth, out stencil); // Create depth render buffer (might contain stencil data too) GL.GenRenderbuffers(1, out resourceId); GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, resourceId); GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, depth, Description.Width, Description.Height); if (OpenGLConvertExtensions.GetErrorCode() != ErrorCode.NoError) { throw new InvalidOperationException("Could not create render buffer"); } // If stencil buffer is separate, create it as well if (stencil != 0) { GL.GenRenderbuffers(1, out ResouceIdStencil); GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, ResouceIdStencil); GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, stencil, Description.Width, Description.Height); if (OpenGLConvertExtensions.GetErrorCode() != ErrorCode.NoError) { throw new InvalidOperationException("Could not create render buffer"); } } GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, 0); return; } } PixelInternalFormat internalFormat; PixelFormatGl format; PixelType type; int pixelSize; bool compressed; ConvertPixelFormat(GraphicsDevice, Description.Format, out internalFormat, out format, out type, out pixelSize, out compressed); InternalFormat = internalFormat; FormatGl = format; Type = type; DepthPitch = Description.Width * Description.Height * pixelSize; RowPitch = Description.Width * pixelSize; if (Description.Usage == GraphicsResourceUsage.Staging) { #if !SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES GL.GenBuffers(1, out resourceId); GL.BindBuffer(BufferTarget.PixelPackBuffer, resourceId); GL.BufferData(BufferTarget.PixelPackBuffer, (IntPtr)DepthPitch, IntPtr.Zero, BufferUsageHint.StreamRead); GL.BindBuffer(BufferTarget.PixelPackBuffer, 0); #else StagingData = Marshal.AllocHGlobal(DepthPitch); #endif } else { int textureId; // If we're on main context, change internal states so that texture is bound again if (!creationContext.UseDeviceCreationContext) { GraphicsDevice.UseTemporaryFirstTexture(); } GL.GenTextures(1, out textureId); GL.BindTexture(TextureTarget.Texture2D, textureId); // No filtering on depth buffer if ((Description.Flags & (TextureFlags.RenderTarget | TextureFlags.DepthStencil)) != TextureFlags.None) { GL.TexParameter(Target, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest); GL.TexParameter(Target, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest); GL.TexParameter(Target, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge); GL.TexParameter(Target, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge); } #if SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES else if (Description.MipLevels <= 1) { GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); } #endif #if !SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES GL.TexParameter(Target, TextureParameterName.TextureBaseLevel, 0); GL.TexParameter(Target, TextureParameterName.TextureMaxLevel, Description.MipLevels - 1); #endif if (Description.MipLevels == 0) { throw new NotImplementedException(); } for (int i = 0; i < Description.MipLevels; ++i) { IntPtr data = IntPtr.Zero; var width = CalculateMipSize(Description.Width, i); var height = CalculateMipSize(Description.Height, i); if (textureDatas != null && i < textureDatas.Length) { if (!compressed && textureDatas[i].RowPitch != width * pixelSize) { throw new NotSupportedException("Can't upload texture with pitch in glTexImage2D."); } // Might be possible, need to check API better. data = textureDatas[i].DataPointer; } if (compressed) { #if SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES && !SILICONSTUDIO_PLATFORM_MONO_MOBILE throw new NotSupportedException("Can't use compressed textures on desktop OpenGL ES."); #else GL.CompressedTexImage2D(Target, i, internalFormat, width, height, 0, textureDatas[i].SlicePitch, data); #endif } else { #if SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES && !SILICONSTUDIO_PLATFORM_MONO_MOBILE GL.TexImage2D(TextureTarget2d.Texture2D, i, internalFormat.ToOpenGL(), width, height, 0, format, type, data); #else GL.TexImage2D(Target, i, internalFormat, width, height, 0, format, type, data); #endif } } GL.BindTexture(Target, 0); resourceId = textureId; #if SILICONSTUDIO_XENKO_GRAPHICS_API_OPENGLES if (!GraphicsDevice.IsOpenGLES2) #endif { if (Description.Usage == GraphicsResourceUsage.Dynamic) { InitializePixelBufferObject(); } } } } }