internal void Activate(TextureTarget target, bool useMipmaps = false) { switch (Filter) { case TextureFilter.Point: if (GraphicsCapabilities.SupportsTextureFilterAnisotropic) { GL.TexParameter(target, TextureParameterNameTextureMaxAnisotropy, 1.0f); GraphicsExtensions.CheckGLError(); } GL.TexParameter(target, TextureParameterName.TextureMinFilter, (int)(useMipmaps ? TextureMinFilter.NearestMipmapNearest : TextureMinFilter.Nearest)); GraphicsExtensions.CheckGLError(); GL.TexParameter(target, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest); GraphicsExtensions.CheckGLError(); break; case TextureFilter.Linear: if (GraphicsCapabilities.SupportsTextureFilterAnisotropic) { GL.TexParameter(target, TextureParameterNameTextureMaxAnisotropy, 1.0f); GraphicsExtensions.CheckGLError(); } GL.TexParameter(target, TextureParameterName.TextureMinFilter, (int)(useMipmaps ? TextureMinFilter.LinearMipmapLinear : TextureMinFilter.Linear)); GraphicsExtensions.CheckGLError(); GL.TexParameter(target, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); GraphicsExtensions.CheckGLError(); break; case TextureFilter.Anisotropic: if (GraphicsCapabilities.SupportsTextureFilterAnisotropic) { GL.TexParameter(target, TextureParameterNameTextureMaxAnisotropy, MathHelper.Clamp(this.MaxAnisotropy, 1.0f, SamplerState.MaxTextureMaxAnisotropy)); GraphicsExtensions.CheckGLError(); } GL.TexParameter(target, TextureParameterName.TextureMinFilter, (int)(useMipmaps ? TextureMinFilter.LinearMipmapLinear : TextureMinFilter.Linear)); GraphicsExtensions.CheckGLError(); GL.TexParameter(target, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); GraphicsExtensions.CheckGLError(); break; case TextureFilter.PointMipLinear: if (GraphicsCapabilities.SupportsTextureFilterAnisotropic) { GL.TexParameter(target, TextureParameterNameTextureMaxAnisotropy, 1.0f); GraphicsExtensions.CheckGLError(); } GL.TexParameter(target, TextureParameterName.TextureMinFilter, (int)(useMipmaps ? TextureMinFilter.NearestMipmapLinear : TextureMinFilter.Nearest)); GraphicsExtensions.CheckGLError(); GL.TexParameter(target, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest); GraphicsExtensions.CheckGLError(); break; case TextureFilter.LinearMipPoint: if (GraphicsCapabilities.SupportsTextureFilterAnisotropic) { GL.TexParameter(target, TextureParameterNameTextureMaxAnisotropy, 1.0f); GraphicsExtensions.CheckGLError(); } GL.TexParameter(target, TextureParameterName.TextureMinFilter, (int)(useMipmaps ? TextureMinFilter.LinearMipmapNearest : TextureMinFilter.Linear)); GraphicsExtensions.CheckGLError(); GL.TexParameter(target, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); GraphicsExtensions.CheckGLError(); break; case TextureFilter.MinLinearMagPointMipLinear: if (GraphicsCapabilities.SupportsTextureFilterAnisotropic) { GL.TexParameter(target, TextureParameterNameTextureMaxAnisotropy, 1.0f); GraphicsExtensions.CheckGLError(); } GL.TexParameter(target, TextureParameterName.TextureMinFilter, (int)(useMipmaps ? TextureMinFilter.LinearMipmapLinear : TextureMinFilter.Linear)); GraphicsExtensions.CheckGLError(); GL.TexParameter(target, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest); GraphicsExtensions.CheckGLError(); break; case TextureFilter.MinLinearMagPointMipPoint: if (GraphicsCapabilities.SupportsTextureFilterAnisotropic) { GL.TexParameter(target, TextureParameterNameTextureMaxAnisotropy, 1.0f); GraphicsExtensions.CheckGLError(); } GL.TexParameter(target, TextureParameterName.TextureMinFilter, (int)(useMipmaps ? TextureMinFilter.LinearMipmapNearest: TextureMinFilter.Linear)); GraphicsExtensions.CheckGLError(); GL.TexParameter(target, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest); GraphicsExtensions.CheckGLError(); break; case TextureFilter.MinPointMagLinearMipLinear: if (GraphicsCapabilities.SupportsTextureFilterAnisotropic) { GL.TexParameter(target, TextureParameterNameTextureMaxAnisotropy, 1.0f); GraphicsExtensions.CheckGLError(); } GL.TexParameter(target, TextureParameterName.TextureMinFilter, (int)(useMipmaps ? TextureMinFilter.NearestMipmapLinear: TextureMinFilter.Nearest)); GraphicsExtensions.CheckGLError(); GL.TexParameter(target, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); GraphicsExtensions.CheckGLError(); break; case TextureFilter.MinPointMagLinearMipPoint: if (GraphicsCapabilities.SupportsTextureFilterAnisotropic) { GL.TexParameter(target, TextureParameterNameTextureMaxAnisotropy, 1.0f); GraphicsExtensions.CheckGLError(); } GL.TexParameter(target, TextureParameterName.TextureMinFilter, (int)(useMipmaps ? TextureMinFilter.NearestMipmapNearest: TextureMinFilter.Nearest)); GraphicsExtensions.CheckGLError(); GL.TexParameter(target, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); GraphicsExtensions.CheckGLError(); break; default: throw new NotSupportedException(); } // Set up texture addressing. GL.TexParameter(target, TextureParameterName.TextureWrapS, (int)GetWrapMode(AddressU)); GraphicsExtensions.CheckGLError(); GL.TexParameter(target, TextureParameterName.TextureWrapT, (int)GetWrapMode(AddressV)); GraphicsExtensions.CheckGLError(); #if !GLES // LOD bias is not supported by glTexParameter in OpenGL ES 2.0 GL.TexParameter(target, TextureParameterName.TextureLodBias, MipMapLevelOfDetailBias); GraphicsExtensions.CheckGLError(); #endif }
public void PlatformClear(ClearOptions options, Vector4 color, float depth, int stencil) { // TODO: We need to figure out how to detect if we have a // depth stencil buffer or not, and clear options relating // to them if not attached. // Unlike with XNA and DirectX... GL.Clear() obeys several // different render states: // // - The color write flags. // - The scissor rectangle. // - The depth/stencil state. // // So overwrite these states with what is needed to perform // the clear correctly and restore it afterwards. // var prevScissorRect = ScissorRectangle; var prevDepthStencilState = DepthStencilState; var prevBlendState = BlendState; ScissorRectangle = _viewport.Bounds; // DepthStencilState.Default has the Stencil Test disabled; // make sure stencil test is enabled before we clear since // some drivers won't clear with stencil test disabled DepthStencilState = this.clearDepthStencilState; BlendState = BlendState.Opaque; ApplyState(false); ClearBufferMask bufferMask = 0; if ((options & ClearOptions.Target) == ClearOptions.Target) { if (color != _lastClearColor) { GL.ClearColor(color.X, color.Y, color.Z, color.W); GraphicsExtensions.CheckGLError(); _lastClearColor = color; } bufferMask = bufferMask | ClearBufferMask.ColorBufferBit; } if ((options & ClearOptions.Stencil) == ClearOptions.Stencil) { if (stencil != _lastClearStencil) { GL.ClearStencil(stencil); GraphicsExtensions.CheckGLError(); _lastClearStencil = stencil; } bufferMask = bufferMask | ClearBufferMask.StencilBufferBit; } if ((options & ClearOptions.DepthBuffer) == ClearOptions.DepthBuffer) { if (depth != _lastClearDepth) { GL.ClearDepth(depth); GraphicsExtensions.CheckGLError(); _lastClearDepth = depth; } bufferMask = bufferMask | ClearBufferMask.DepthBufferBit; } GL.Clear(bufferMask); GraphicsExtensions.CheckGLError(); // Restore the previous render state. ScissorRectangle = prevScissorRect; DepthStencilState = prevDepthStencilState; BlendState = prevBlendState; }
/// <summary> /// Activates the Current Vertex/Pixel shader pair into a program. /// </summary> private unsafe void ActivateShaderProgram() { // Lookup the shader program. var shaderProgram = _programCache.GetProgram(VertexShader, PixelShader); if (shaderProgram.Program == -1) { return; } // Set the new program if it has changed. if (_shaderProgram != shaderProgram) { GL.UseProgram(shaderProgram.Program); GraphicsExtensions.CheckGLError(); _shaderProgram = shaderProgram; } var posFixupLoc = shaderProgram.GetUniformLocation("posFixup"); if (posFixupLoc == -1) { return; } // Apply vertex shader fix: // The following two lines are appended to the end of vertex shaders // to account for rendering differences between OpenGL and DirectX: // // gl_Position.y = gl_Position.y * posFixup.y; // gl_Position.xy += posFixup.zw * gl_Position.ww; // // (the following paraphrased from wine, wined3d/state.c and wined3d/glsl_shader.c) // // - We need to flip along the y-axis in case of offscreen rendering. // - D3D coordinates refer to pixel centers while GL coordinates refer // to pixel corners. // - D3D has a top-left filling convention. We need to maintain this // even after the y-flip mentioned above. // In order to handle the last two points, we translate by // (63.0 / 128.0) / VPw and (63.0 / 128.0) / VPh. This is equivalent to // translating slightly less than half a pixel. We want the difference to // be large enough that it doesn't get lost due to rounding inside the // driver, but small enough to prevent it from interfering with any // anti-aliasing. // // OpenGL coordinates specify the center of the pixel while d3d coords specify // the corner. The offsets are stored in z and w in posFixup. posFixup.y contains // 1.0 or -1.0 to turn the rendering upside down for offscreen rendering. PosFixup.x // contains 1.0 to allow a mad. _posFixup[0] = 1.0f; _posFixup[1] = 1.0f; _posFixup[2] = (63.0f / 64.0f) / Viewport.Width; _posFixup[3] = -(63.0f / 64.0f) / Viewport.Height; //If we have a render target bound (rendering offscreen) if (IsRenderTargetBound) { //flip vertically _posFixup[1] *= -1.0f; _posFixup[3] *= -1.0f; } fixed(float *floatPtr = _posFixup) { GL.Uniform4(posFixupLoc, 1, floatPtr); } GraphicsExtensions.CheckGLError(); }
internal void PlatformApplyState(GraphicsDevice device, bool force = false) { var blendEnabled = !(this.ColorSourceBlend == Blend.One && this.ColorDestinationBlend == Blend.Zero && this.AlphaSourceBlend == Blend.One && this.AlphaDestinationBlend == Blend.Zero); if (force || blendEnabled != device._lastBlendEnable) { if (blendEnabled) { GL.Enable(EnableCap.Blend); } else { GL.Disable(EnableCap.Blend); } GraphicsExtensions.CheckGLError(); device._lastBlendEnable = blendEnabled; } if (force || this.BlendFactor != device._lastBlendState.BlendFactor) { GL.BlendColor( this.BlendFactor.R / 255.0f, this.BlendFactor.G / 255.0f, this.BlendFactor.B / 255.0f, this.BlendFactor.A / 255.0f); GraphicsExtensions.CheckGLError(); device._lastBlendState.BlendFactor = this.BlendFactor; } if (force || this.ColorBlendFunction != device._lastBlendState.ColorBlendFunction || this.AlphaBlendFunction != device._lastBlendState.AlphaBlendFunction) { GL.BlendEquationSeparate( this.ColorBlendFunction.GetBlendEquationMode(), this.AlphaBlendFunction.GetBlendEquationMode()); GraphicsExtensions.CheckGLError(); device._lastBlendState.ColorBlendFunction = this.ColorBlendFunction; device._lastBlendState.AlphaBlendFunction = this.AlphaBlendFunction; } if (force || this.ColorSourceBlend != device._lastBlendState.ColorSourceBlend || this.ColorDestinationBlend != device._lastBlendState.ColorDestinationBlend || this.AlphaSourceBlend != device._lastBlendState.AlphaSourceBlend || this.AlphaDestinationBlend != device._lastBlendState.AlphaDestinationBlend) { GL.BlendFuncSeparate( this.ColorSourceBlend.GetBlendFactorSrc(), this.ColorDestinationBlend.GetBlendFactorDest(), this.AlphaSourceBlend.GetBlendFactorSrc(), this.AlphaDestinationBlend.GetBlendFactorDest()); GraphicsExtensions.CheckGLError(); device._lastBlendState.ColorSourceBlend = this.ColorSourceBlend; device._lastBlendState.ColorDestinationBlend = this.ColorDestinationBlend; device._lastBlendState.AlphaSourceBlend = this.AlphaSourceBlend; device._lastBlendState.AlphaDestinationBlend = this.AlphaDestinationBlend; } if (force || this.ColorWriteChannels != device._lastBlendState.ColorWriteChannels) { GL.ColorMask( (this.ColorWriteChannels & ColorWriteChannels.Red) != 0, (this.ColorWriteChannels & ColorWriteChannels.Green) != 0, (this.ColorWriteChannels & ColorWriteChannels.Blue) != 0, (this.ColorWriteChannels & ColorWriteChannels.Alpha) != 0); GraphicsExtensions.CheckGLError(); device._lastBlendState.ColorWriteChannels = this.ColorWriteChannels; } }
internal void SetSamplers(GraphicsDevice device) { #if DIRECTX // Skip out if nothing has changed. if (_d3dDirty == 0) { return; } // NOTE: We make the assumption here that the caller has // locked the d3dContext for us to use. var pixelShaderStage = device._d3dContext.PixelShader; for (var i = 0; i < _samplers.Length; i++) { var mask = 1 << i; if ((_d3dDirty & mask) == 0) { continue; } var sampler = _samplers[i]; SharpDX.Direct3D11.SamplerState state = null; if (sampler != null) { state = sampler.GetState(device); } pixelShaderStage.SetSampler(i, state); _d3dDirty &= ~mask; if (_d3dDirty == 0) { break; } } _d3dDirty = 0; #elif OPENGL for (var i = 0; i < _samplers.Length; i++) { var sampler = _samplers[i]; var texture = device.Textures[i]; if (sampler != null && texture != null && sampler != texture.glLastSamplerState) { // TODO: Avoid doing this redundantly (see TextureCollection.SetTextures()) // However, I suspect that rendering from the same texture with different sampling modes // is a relatively rare occurrence... GL.ActiveTexture(TextureUnit.Texture0 + i); GraphicsExtensions.CheckGLError(); // NOTE: We don't have to bind the texture here because it is already bound in // TextureCollection.SetTextures(). This, of course, assumes that SetTextures() is called // before this method is called. If that ever changes this code will misbehave. // GL.BindTexture(texture.glTarget, texture.glTexture); // GraphicsExtensions.CheckGLError(); sampler.Activate(texture.glTarget, texture.LevelCount > 1); texture.glLastSamplerState = sampler; } } #elif PSM for (var i = 0; i < _samplers.Length; i++) { var sampler = _samplers[i]; var texture = device.Textures[i] as Texture2D; if (texture == null) { continue; } var psmTexture = texture._texture2D; // FIXME: Handle mip attributes // FIXME: Separable filters psmTexture.SetFilter( sampler.Filter == TextureFilter.Point ? Sce.PlayStation.Core.Graphics.TextureFilterMode.Nearest : Sce.PlayStation.Core.Graphics.TextureFilterMode.Linear ); // FIXME: The third address mode psmTexture.SetWrap( sampler.AddressU == TextureAddressMode.Clamp ? Sce.PlayStation.Core.Graphics.TextureWrapMode.ClampToEdge : Sce.PlayStation.Core.Graphics.TextureWrapMode.Repeat, sampler.AddressV == TextureAddressMode.Clamp ? Sce.PlayStation.Core.Graphics.TextureWrapMode.ClampToEdge : Sce.PlayStation.Core.Graphics.TextureWrapMode.Repeat ); } #endif }
internal void ApplyState(GraphicsDevice device) { // When rendering offscreen the faces change order. var offscreen = device.GetRenderTargets().Length > 0; if (CullMode == CullMode.None) { GL.Disable(EnableCap.CullFace); GraphicsExtensions.CheckGLError(); } else { GL.Enable(EnableCap.CullFace); GraphicsExtensions.CheckGLError(); GL.CullFace(CullFaceMode.Back); GraphicsExtensions.CheckGLError(); if (CullMode == CullMode.CullClockwiseFace) { if (offscreen) { GL.FrontFace(FrontFaceDirection.Cw); } else { GL.FrontFace(FrontFaceDirection.Ccw); } GraphicsExtensions.CheckGLError(); } else { if (offscreen) { GL.FrontFace(FrontFaceDirection.Ccw); } else { GL.FrontFace(FrontFaceDirection.Cw); } GraphicsExtensions.CheckGLError(); } } #if SDL2 if (FillMode == FillMode.Solid) { GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); } else { GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line); } #else if (FillMode != FillMode.Solid) { throw new NotImplementedException(); } #endif if (ScissorTestEnable) { GL.Enable(EnableCap.ScissorTest); } else { GL.Disable(EnableCap.ScissorTest); } GraphicsExtensions.CheckGLError(); if (this.DepthBias != 0 || this.SlopeScaleDepthBias != 0) { GL.Enable(EnableCap.PolygonOffsetFill); GL.PolygonOffset(this.SlopeScaleDepthBias, this.DepthBias); } else { GL.Disable(EnableCap.PolygonOffsetFill); } GraphicsExtensions.CheckGLError(); // TODO: Implement MultiSampleAntiAlias }
public RenderTarget2D(GraphicsDevice graphicsDevice, int width, int height, bool mipMap, SurfaceFormat preferredFormat, DepthFormat preferredDepthFormat, int preferredMultiSampleCount, RenderTargetUsage usage) : base(graphicsDevice, width, height, mipMap, preferredFormat, true) { DepthStencilFormat = preferredDepthFormat; MultiSampleCount = preferredMultiSampleCount; RenderTargetUsage = usage; #if DIRECTX // Create a view interface on the rendertarget to use on bind. _renderTargetView = new SharpDX.Direct3D11.RenderTargetView(graphicsDevice._d3dDevice, _texture); #endif // If we don't need a depth buffer then we're done. if (preferredDepthFormat == DepthFormat.None) { return; } #if DIRECTX // Setup the multisampling description. var multisampleDesc = new SharpDX.DXGI.SampleDescription(1, 0); if (preferredMultiSampleCount > 1) { multisampleDesc.Count = preferredMultiSampleCount; multisampleDesc.Quality = (int)SharpDX.Direct3D11.StandardMultisampleQualityLevels.StandardMultisamplePattern; } // Create a descriptor for the depth/stencil buffer. // Allocate a 2-D surface as the depth/stencil buffer. // Create a DepthStencil view on this surface to use on bind. using (var depthBuffer = new SharpDX.Direct3D11.Texture2D(graphicsDevice._d3dDevice, new SharpDX.Direct3D11.Texture2DDescription() { Format = SharpDXHelper.ToFormat(preferredDepthFormat), ArraySize = 1, MipLevels = 1, Width = width, Height = height, SampleDescription = multisampleDesc, BindFlags = SharpDX.Direct3D11.BindFlags.DepthStencil, })) // Create the view for binding to the device. _depthStencilView = new SharpDX.Direct3D11.DepthStencilView(graphicsDevice._d3dDevice, depthBuffer, new SharpDX.Direct3D11.DepthStencilViewDescription() { Format = SharpDXHelper.ToFormat(preferredDepthFormat), Dimension = SharpDX.Direct3D11.DepthStencilViewDimension.Texture2D }); #elif OPENGL #if GLES GL.GenRenderbuffers(1, ref glDepthStencilBuffer); #else GL.GenRenderbuffers(1, out glDepthStencilBuffer); #endif GraphicsExtensions.CheckGLError(); GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, this.glDepthStencilBuffer); GraphicsExtensions.CheckGLError(); var glDepthStencilFormat = GLDepthComponent16; switch (preferredDepthFormat) { case DepthFormat.Depth16: glDepthStencilFormat = GLDepthComponent16; break; case DepthFormat.Depth24: glDepthStencilFormat = GLDepthComponent24; break; case DepthFormat.Depth24Stencil8: glDepthStencilFormat = GLDepth24Stencil8; break; } GL.RenderbufferStorage(GLRenderbuffer, glDepthStencilFormat, this.width, this.height); GraphicsExtensions.CheckGLError(); #endif }
internal virtual void DeleteFramebuffer(int framebuffer) { GL.DeleteFramebuffers(1, ref framebuffer); GraphicsExtensions.CheckGLError(); }
internal virtual void FramebufferTexture2D(int attachement, int target, int texture, int level = 0, int samples = 0) { GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, (FramebufferAttachment)attachement, (TextureTarget)target, texture, level); GraphicsExtensions.CheckGLError(); }
public void SetData<T>(int level, Rectangle? rect, T[] data, int startIndex, int elementCount) where T : struct { if (data == null) throw new ArgumentNullException("data"); #if OPENGL Threading.BlockOnUIThread(() => { #endif #if !PSM var elementSizeInByte = Marshal.SizeOf(typeof(T)); var dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned); // Use try..finally to make sure dataHandle is freed in case of an error try { var startBytes = startIndex * elementSizeInByte; var dataPtr = (IntPtr)(dataHandle.AddrOfPinnedObject().ToInt64() + startBytes); #endif int x, y, w, h; if (rect.HasValue) { x = rect.Value.X; y = rect.Value.Y; w = rect.Value.Width; h = rect.Value.Height; } else { x = 0; y = 0; w = Math.Max(width >> level, 1); h = Math.Max(height >> level, 1); // For DXT textures the width and height of each level is a multiple of 4. // OpenGL only: The last two mip levels require the width and height to be // passed as 2x2 and 1x1, but there needs to be enough data passed to occupy // a 4x4 block. // Ref: http://www.mentby.com/Group/mac-opengl/issue-with-dxt-mipmapped-textures.html if (_format == SurfaceFormat.Dxt1 || _format == SurfaceFormat.Dxt1a || _format == SurfaceFormat.Dxt3 || _format == SurfaceFormat.Dxt5) { #if DIRECTX w = (w + 3) & ~3; h = (h + 3) & ~3; #else if (w > 4) w = (w + 3) & ~3; if (h > 4) h = (h + 3) & ~3; #endif } } #if DIRECTX var box = new SharpDX.DataBox(dataPtr, GetPitch(w), 0); var region = new SharpDX.Direct3D11.ResourceRegion(); region.Top = y; region.Front = 0; region.Back = 1; region.Bottom = y + h; region.Left = x; region.Right = x + w; // TODO: We need to deal with threaded contexts here! var d3dContext = GraphicsDevice._d3dContext; lock (d3dContext) d3dContext.UpdateSubresource(box, GetTexture(), level, region); #elif PSM _texture2D.SetPixels(level, data, _texture2D.Format, startIndex, 0, x, y, w, h); #elif OPENGL // Store the current bound texture. var prevTexture = GraphicsExtensions.GetBoundTexture2D(); GenerateGLTextureIfRequired(); GL.BindTexture(TextureTarget.Texture2D, this.glTexture); GraphicsExtensions.CheckGLError(); if (glFormat == (GLPixelFormat)All.CompressedTextureFormats) { if (rect.HasValue) { GL.CompressedTexSubImage2D(TextureTarget.Texture2D, level, x, y, w, h, #if GLES glInternalFormat, #else glFormat, #endif data.Length - startBytes, dataPtr); GraphicsExtensions.CheckGLError(); } else { GL.CompressedTexImage2D(TextureTarget.Texture2D, level, glInternalFormat, w, h, 0, data.Length - startBytes, dataPtr); GraphicsExtensions.CheckGLError(); } } else { // Set pixel alignment to match texel size in bytes GL.PixelStore(PixelStoreParameter.UnpackAlignment, GraphicsExtensions.Size(this.Format)); if (rect.HasValue) { GL.TexSubImage2D(TextureTarget.Texture2D, level, x, y, w, h, glFormat, glType, dataPtr); GraphicsExtensions.CheckGLError(); } else { GL.TexImage2D(TextureTarget.Texture2D, level, #if GLES (int)glInternalFormat, #else glInternalFormat, #endif w, h, 0, glFormat, glType, dataPtr); GraphicsExtensions.CheckGLError(); } // Return to default pixel alignment GL.PixelStore(PixelStoreParameter.UnpackAlignment, 4); } #if !ANDROID GL.Finish(); GraphicsExtensions.CheckGLError(); #endif // Restore the bound texture. GL.BindTexture(TextureTarget.Texture2D, prevTexture); GraphicsExtensions.CheckGLError(); #endif // OPENGL #if !PSM } finally { dataHandle.Free(); } #endif #if OPENGL #if !ANDROID // Required to make sure that any texture uploads on a thread are completed // before the main thread tries to use the texture. GL.Finish(); #endif }); #endif }
internal void SetTextures(GraphicsDevice device) { #if !DIRECTX Threading.EnsureUIThread(); #endif // Skip out if nothing has changed. if (_dirty == 0) { return; } #if DIRECTX // NOTE: We make the assumption here that the caller has // locked the d3dContext for us to use. var pixelShaderStage = device._d3dContext.PixelShader; #endif for (var i = 0; i < _textures.Length; i++) { var mask = 1 << i; if ((_dirty & mask) == 0) { continue; } var tex = _textures[i]; #if OPENGL GL.ActiveTexture(TextureUnit.Texture0 + i); GraphicsExtensions.CheckGLError(); // Clear the previous binding if the // target is different from the new one. if (_targets[i] != 0 && (tex == null || _targets[i] != tex.glTarget)) { GL.BindTexture(_targets[i], 0); GraphicsExtensions.CheckGLError(); } if (tex != null) { _targets[i] = tex.glTarget; GL.BindTexture(tex.glTarget, tex.glTexture); GraphicsExtensions.CheckGLError(); } #elif DIRECTX if (_textures[i] == null) { pixelShaderStage.SetShaderResource(i, null); } else { pixelShaderStage.SetShaderResource(i, _textures[i].GetShaderResourceView()); } #endif _dirty &= ~mask; if (_dirty == 0) { break; } } _dirty = 0; }
protected Texture2D(GraphicsDevice graphicsDevice, int width, int height, bool mipmap, SurfaceFormat format, SurfaceType type, bool shared) { if (graphicsDevice == null) throw new ArgumentNullException("Graphics Device Cannot Be Null"); this.GraphicsDevice = graphicsDevice; this.width = width; this.height = height; this._format = format; this._levelCount = mipmap ? CalculateMipLevels(width, height) : 1; // Texture will be assigned by the swap chain. if (type == SurfaceType.SwapChainRenderTarget) return; #if DIRECTX _shared = shared; _renderTarget = (type == SurfaceType.RenderTarget); _mipmap = mipmap; // Create texture GetTexture(); #elif PSM PixelBufferOption option = PixelBufferOption.None; if (type == SurfaceType.RenderTarget) option = PixelBufferOption.Renderable; _texture2D = new Sce.PlayStation.Core.Graphics.Texture2D(width, height, mipmap, PSSHelper.ToFormat(format),option); #else this.glTarget = TextureTarget.Texture2D; Threading.BlockOnUIThread(() => { // Store the current bound texture. var prevTexture = GraphicsExtensions.GetBoundTexture2D(); GenerateGLTextureIfRequired(); format.GetGLFormat(out glInternalFormat, out glFormat, out glType); if (glFormat == (GLPixelFormat)All.CompressedTextureFormats) { var imageSize = 0; switch (format) { case SurfaceFormat.RgbPvrtc2Bpp: case SurfaceFormat.RgbaPvrtc2Bpp: imageSize = (Math.Max(this.width, 16) * Math.Max(this.height, 8) * 2 + 7) / 8; break; case SurfaceFormat.RgbPvrtc4Bpp: case SurfaceFormat.RgbaPvrtc4Bpp: imageSize = (Math.Max(this.width, 8) * Math.Max(this.height, 8) * 4 + 7) / 8; break; case SurfaceFormat.RgbEtc1: case SurfaceFormat.Dxt1: case SurfaceFormat.Dxt1a: case SurfaceFormat.Dxt3: case SurfaceFormat.Dxt5: imageSize = ((this.width + 3) / 4) * ((this.height + 3) / 4) * format.Size(); break; default: throw new NotSupportedException(); } GL.CompressedTexImage2D(TextureTarget.Texture2D, 0, glInternalFormat, this.width, this.height, 0, imageSize, IntPtr.Zero); GraphicsExtensions.CheckGLError(); } else { GL.TexImage2D(TextureTarget.Texture2D, 0, #if IOS || ANDROID (int)glInternalFormat, #else glInternalFormat, #endif this.width, this.height, 0, glFormat, glType, IntPtr.Zero); GraphicsExtensions.CheckGLError(); } // Restore the bound texture. GL.BindTexture(TextureTarget.Texture2D, prevTexture); GraphicsExtensions.CheckGLError(); }); #endif }
private byte[] GetTextureData(int ThreadPriorityLevel) { int framebufferId = -1; int renderBufferID = -1; GL.GenFramebuffers(1, ref framebufferId); GraphicsExtensions.CheckGLError(); GL.BindFramebuffer(All.Framebuffer, framebufferId); GraphicsExtensions.CheckGLError(); //renderBufferIDs = new int[currentRenderTargets]; GL.GenRenderbuffers(1, ref renderBufferID); GraphicsExtensions.CheckGLError(); // attach the texture to FBO color attachment point GL.FramebufferTexture2D(All.Framebuffer, All.ColorAttachment0, All.Texture2D, this.glTexture, 0); GraphicsExtensions.CheckGLError(); // create a renderbuffer object to store depth info GL.BindRenderbuffer(All.Renderbuffer, renderBufferID); GraphicsExtensions.CheckGLError(); var glDepthFormat = GraphicsCapabilities.SupportsDepth24 ? All.DepthComponent24Oes : GraphicsCapabilities.SupportsDepthNonLinear ? (OpenTK.Graphics.ES20.All)0x8E2C /*GLDepthComponent16NonLinear */: All.DepthComponent16; GL.RenderbufferStorage(All.Renderbuffer, glDepthFormat, Width, Height); GraphicsExtensions.CheckGLError(); // attach the renderbuffer to depth attachment point GL.FramebufferRenderbuffer(All.Framebuffer, All.DepthAttachment, All.Renderbuffer, renderBufferID); GraphicsExtensions.CheckGLError(); All status = GL.CheckFramebufferStatus(All.Framebuffer); if (status != All.FramebufferComplete) throw new Exception("Error creating framebuffer: " + status); byte[] imageInfo; int sz = 0; switch (this.Format) { case SurfaceFormat.Color: //kTexture2DPixelFormat_RGBA8888 case SurfaceFormat.Dxt3: sz = 4; imageInfo = new byte[(Width * Height) * sz]; break; case SurfaceFormat.Bgra4444: //kTexture2DPixelFormat_RGBA4444 sz = 2; imageInfo = new byte[(Width * Height) * sz]; break; case SurfaceFormat.Bgra5551: //kTexture2DPixelFormat_RGB5A1 sz = 2; imageInfo = new byte[(Width * Height) * sz]; break; case SurfaceFormat.Alpha8: // kTexture2DPixelFormat_A8 sz = 1; imageInfo = new byte[(Width * Height) * sz]; break; default: throw new NotSupportedException("Texture format"); } GL.ReadPixels(0,0,Width, Height, All.Rgba, All.UnsignedByte, imageInfo); GraphicsExtensions.CheckGLError(); GL.FramebufferRenderbuffer(All.Framebuffer, All.DepthAttachment, All.Renderbuffer, 0); GraphicsExtensions.CheckGLError(); GL.DeleteRenderbuffers(1, ref renderBufferID); GraphicsExtensions.CheckGLError(); GL.DeleteFramebuffers(1, ref framebufferId); GraphicsExtensions.CheckGLError(); GL.BindFramebuffer(All.Framebuffer, 0); GraphicsExtensions.CheckGLError(); return imageInfo; }
static SamplerState() { #if OPENGL #if GLES if (GraphicsCapabilities.SupportsTextureFilterAnisotropic) { GL.GetFloat(GetPNameMaxTextureMaxAnisotropy, ref SamplerState.MaxTextureMaxAnisotropy); } #else GL.GetFloat(GetPNameMaxTextureMaxAnisotropy, out SamplerState.MaxTextureMaxAnisotropy); #endif GraphicsExtensions.CheckGLError(); #endif _anisotropicClamp = new Utilities.ObjectFactoryWithReset <SamplerState>(() => new SamplerState { Name = "SamplerState.AnisotropicClamp", Filter = TextureFilter.Anisotropic, AddressU = TextureAddressMode.Clamp, AddressV = TextureAddressMode.Clamp, AddressW = TextureAddressMode.Clamp, }); _anisotropicWrap = new Utilities.ObjectFactoryWithReset <SamplerState>(() => new SamplerState { Name = "SamplerState.AnisotropicWrap", Filter = TextureFilter.Anisotropic, AddressU = TextureAddressMode.Wrap, AddressV = TextureAddressMode.Wrap, AddressW = TextureAddressMode.Wrap, }); _linearClamp = new Utilities.ObjectFactoryWithReset <SamplerState>(() => new SamplerState { Name = "SamplerState.LinearClamp", Filter = TextureFilter.Linear, AddressU = TextureAddressMode.Clamp, AddressV = TextureAddressMode.Clamp, AddressW = TextureAddressMode.Clamp, }); _linearWrap = new Utilities.ObjectFactoryWithReset <SamplerState>(() => new SamplerState { Name = "SamplerState.LinearWrap", Filter = TextureFilter.Linear, AddressU = TextureAddressMode.Wrap, AddressV = TextureAddressMode.Wrap, AddressW = TextureAddressMode.Wrap, }); _pointClamp = new Utilities.ObjectFactoryWithReset <SamplerState>(() => new SamplerState { Name = "SamplerState.PointClamp", Filter = TextureFilter.Point, AddressU = TextureAddressMode.Clamp, AddressV = TextureAddressMode.Clamp, AddressW = TextureAddressMode.Clamp, }); _pointWrap = new Utilities.ObjectFactoryWithReset <SamplerState>(() => new SamplerState { Name = "SamplerState.PointWrap", Filter = TextureFilter.Point, AddressU = TextureAddressMode.Wrap, AddressV = TextureAddressMode.Wrap, AddressW = TextureAddressMode.Wrap, }); }
internal void PlatformApplyState(bool applyShaders) { if (_scissorRectangleDirty) { var scissorRect = _scissorRectangle; if (!IsRenderTargetBound) { scissorRect.Y = PresentationParameters.BackBufferHeight - (scissorRect.Y + scissorRect.Height); } gl.scissor(scissorRect.X, scissorRect.Y, scissorRect.Width, scissorRect.Height); GraphicsExtensions.CheckGLError(); _scissorRectangleDirty = false; } // If we're not applying shaders then early out now. if (!applyShaders) { return; } if (_indexBufferDirty) { if (_indexBuffer != null) { gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, _indexBuffer.ibo); GraphicsExtensions.CheckGLError(); } _indexBufferDirty = false; } if (_vertexShader == null) { throw new InvalidOperationException("A vertex shader must be set!"); } if (_pixelShader == null) { throw new InvalidOperationException("A pixel shader must be set!"); } if (_vertexShaderDirty || _pixelShaderDirty) { ActivateShaderProgram(); if (_vertexShaderDirty) { unchecked { _graphicsMetrics._vertexShaderCount++; } } if (_pixelShaderDirty) { unchecked { _graphicsMetrics._pixelShaderCount++; } } _vertexShaderDirty = _pixelShaderDirty = false; } _vertexConstantBuffers.SetConstantBuffers(this, _shaderProgram); _pixelConstantBuffers.SetConstantBuffers(this, _shaderProgram); Textures.SetTextures(this); SamplerStates.PlatformSetSamplers(this); }
internal virtual void FramebufferRenderbuffer(int attachement, int renderbuffer, int level = 0) { GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, (FramebufferAttachment)attachement, RenderbufferTarget.Renderbuffer, renderbuffer); GraphicsExtensions.CheckGLError(); }
internal void ApplyState(GraphicsDevice device) { if (!DepthBufferEnable) { GL.Disable(EnableCap.DepthTest); GraphicsExtensions.CheckGLError(); } else { // enable Depth Buffer GL.Enable(EnableCap.DepthTest); GraphicsExtensions.CheckGLError(); DepthFunction func; switch (DepthBufferFunction) { default: case CompareFunction.Always: func = DepthFunction.Always; break; case CompareFunction.Equal: func = DepthFunction.Equal; break; case CompareFunction.Greater: func = DepthFunction.Greater; break; case CompareFunction.GreaterEqual: func = DepthFunction.Gequal; break; case CompareFunction.Less: func = DepthFunction.Less; break; case CompareFunction.LessEqual: func = DepthFunction.Lequal; break; case CompareFunction.Never: func = DepthFunction.Never; break; case CompareFunction.NotEqual: func = DepthFunction.Notequal; break; } GL.DepthFunc(func); GraphicsExtensions.CheckGLError(); } GL.DepthMask(DepthBufferWriteEnable); GraphicsExtensions.CheckGLError(); if (!StencilEnable) { GL.Disable(EnableCap.StencilTest); GraphicsExtensions.CheckGLError(); } else { // enable Stencil GL.Enable(EnableCap.StencilTest); GraphicsExtensions.CheckGLError(); // Set color mask - not needed //GL.ColorMask(false, false, false, false); //Disable drawing colors to the screen // set function GLStencilFunction func; switch (StencilFunction) { default: case CompareFunction.Always: func = GLStencilFunction.Always; break; case CompareFunction.Equal: func = GLStencilFunction.Equal; break; case CompareFunction.Greater: func = GLStencilFunction.Greater; break; case CompareFunction.GreaterEqual: func = GLStencilFunction.Gequal; break; case CompareFunction.Less: func = GLStencilFunction.Less; break; case CompareFunction.LessEqual: func = GLStencilFunction.Lequal; break; case CompareFunction.Never: func = GLStencilFunction.Never; break; case CompareFunction.NotEqual: func = GLStencilFunction.Notequal; break; } GL.StencilFunc(func, ReferenceStencil, StencilMask); GraphicsExtensions.CheckGLError(); GL.StencilOp(GetStencilOp(StencilFail), GetStencilOp(StencilDepthBufferFail), GetStencilOp(StencilPass)); GraphicsExtensions.CheckGLError(); } }
internal virtual void GenerateMipmap(int target) { GL.GenerateMipmap((GenerateMipmapTarget)target); GraphicsExtensions.CheckGLError(); }
private void PlatformConstruct(GraphicsDevice graphicsDevice, int size, bool mipMap, SurfaceFormat format, bool renderTarget) { this.glTarget = gl.TEXTURE_CUBE_MAP; this.glTexture = gl.createTexture(); GraphicsExtensions.CheckGLError(); gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.glTexture); GraphicsExtensions.CheckGLError(); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, mipMap ? gl.LINEAR_MIPMAP_LINEAR : gl.LINEAR); GraphicsExtensions.CheckGLError(); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR); GraphicsExtensions.CheckGLError(); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); GraphicsExtensions.CheckGLError(); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); GraphicsExtensions.CheckGLError(); format.GetGLFormat(GraphicsDevice, out glInternalFormat, out glFormat, out glType); for (var i = 0; i < 6; i++) { var target = GetGLCubeFace((CubeMapFace)i); if (glFormat == gl.COMPRESSED_TEXTURE_FORMATS) { var imageSize = 0; switch (format) { case SurfaceFormat.RgbPvrtc2Bpp: case SurfaceFormat.RgbaPvrtc2Bpp: imageSize = (Math.Max(size, 16) * Math.Max(size, 8) * 2 + 7) / 8; break; case SurfaceFormat.RgbPvrtc4Bpp: case SurfaceFormat.RgbaPvrtc4Bpp: imageSize = (Math.Max(size, 8) * Math.Max(size, 8) * 4 + 7) / 8; break; case SurfaceFormat.Dxt1: case SurfaceFormat.Dxt1a: case SurfaceFormat.Dxt1SRgb: case SurfaceFormat.Dxt3: case SurfaceFormat.Dxt3SRgb: case SurfaceFormat.Dxt5: case SurfaceFormat.Dxt5SRgb: case SurfaceFormat.RgbEtc1: case SurfaceFormat.RgbaAtcExplicitAlpha: case SurfaceFormat.RgbaAtcInterpolatedAlpha: imageSize = (size + 3) / 4 * ((size + 3) / 4) * format.GetSize(); break; default: throw new NotSupportedException(); } gl.compressedTexImage2D(target, 0, glInternalFormat, size, size, 0, new Int8Array(0)); GraphicsExtensions.CheckGLError(); } else { gl.texImage2D(target, 0, glInternalFormat, size, size, 0, glFormat, glType, new Int8Array(0).As <ArrayBufferView>()); GraphicsExtensions.CheckGLError(); } } if (mipMap) { gl.generateMipmap(gl.TEXTURE_CUBE_MAP); GraphicsExtensions.CheckGLError(); } }
internal virtual void GenRenderbuffer(out int renderbuffer) { GL.GenRenderbuffers(1, out renderbuffer); GraphicsExtensions.CheckGLError(); }
protected void SetDataInternal <T>(int offsetInBytes, T[] data, int startIndex, int elementCount, SetDataOptions options) where T : struct { if (data == null) { throw new ArgumentNullException("data is null"); } if (data.Length < (startIndex + elementCount)) { throw new InvalidOperationException("The array specified in the data parameter is not the correct size for the amount of data requested."); } #if DIRECTX if (_isDynamic) { // We assume discard by default. var mode = SharpDX.Direct3D11.MapMode.WriteDiscard; if ((options & SetDataOptions.NoOverwrite) == SetDataOptions.NoOverwrite) { mode = SharpDX.Direct3D11.MapMode.WriteNoOverwrite; } SharpDX.DataStream stream; lock (graphicsDevice._d3dContext) { graphicsDevice._d3dContext.MapSubresource( _buffer, mode, SharpDX.Direct3D11.MapFlags.None, out stream); stream.Position = offsetInBytes; stream.WriteRange(data, startIndex, elementCount); graphicsDevice._d3dContext.UnmapSubresource(_buffer, 0); } } else { var elementSizeInBytes = Marshal.SizeOf(typeof(T)); var dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned); var startBytes = startIndex * elementSizeInBytes; var dataPtr = (IntPtr)(dataHandle.AddrOfPinnedObject().ToInt64() + startBytes); var box = new SharpDX.DataBox(dataPtr, 1, 0); var region = new SharpDX.Direct3D11.ResourceRegion(); region.Top = 0; region.Front = 0; region.Back = 1; region.Bottom = 1; region.Left = offsetInBytes; region.Right = offsetInBytes + (elementCount * elementSizeInBytes); // TODO: We need to deal with threaded contexts here! lock (graphicsDevice._d3dContext) graphicsDevice._d3dContext.UpdateSubresource(box, _buffer, 0, region); dataHandle.Free(); } #elif PSS if (typeof(T) == typeof(ushort)) { Array.Copy(data, offsetInBytes / sizeof(ushort), _buffer, startIndex, elementCount); } else { throw new NotImplementedException("PSS Currently only supports ushort (SixteenBits) index elements"); //Something like as follows probably works if you really need this, but really just make a ushort array! /* * int indexOffset = offsetInBytes / sizeof(T); * for (int i = 0; i < elementCount; i++) * _buffer[i + startIndex] = (ushort)(object)data[i + indexOffset]; */ } #else Threading.BlockOnUIThread(() => { var elementSizeInByte = Marshal.SizeOf(typeof(T)); var sizeInBytes = elementSizeInByte * elementCount; var dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned); var dataPtr = (IntPtr)(dataHandle.AddrOfPinnedObject().ToInt64() + startIndex * elementSizeInByte); var bufferSize = IndexCount * (IndexElementSize == IndexElementSize.SixteenBits ? 2 : 4); GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo); GraphicsExtensions.CheckGLError(); if (options == SetDataOptions.Discard) { // By assigning NULL data to the buffer this gives a hint // to the device to discard the previous content. GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)bufferSize, IntPtr.Zero, _isDynamic ? BufferUsageHint.StreamDraw : BufferUsageHint.StaticDraw); GraphicsExtensions.CheckGLError(); } GL.BufferSubData(BufferTarget.ElementArrayBuffer, (IntPtr)offsetInBytes, (IntPtr)sizeInBytes, dataPtr); GraphicsExtensions.CheckGLError(); dataHandle.Free(); }); #endif }
internal virtual void BindRenderbuffer(int renderbuffer) { GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, renderbuffer); GraphicsExtensions.CheckGLError(); }
private void PlatformGetData <T>(int level, int arraySlice, Rectangle rect, T[] data, int startIndex, int elementCount) where T : struct { Threading.EnsureUIThread(); #if GLES // TODO: check for for non renderable formats (formats that can't be attached to FBO) var framebufferId = 0; GL.GenFramebuffers(1, out framebufferId); GraphicsExtensions.CheckGLError(); GL.BindFramebuffer(FramebufferTarget.Framebuffer, framebufferId); GraphicsExtensions.CheckGLError(); GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, this.glTexture, 0); GraphicsExtensions.CheckGLError(); GL.ReadPixels(rect.X, rect.Y, rect.Width, rect.Height, this.glFormat, this.glType, data); GraphicsExtensions.CheckGLError(); GraphicsDevice.DisposeFramebuffer(framebufferId); #else var tSizeInByte = ReflectionHelpers.SizeOf <T> .Get(); GL.BindTexture(TextureTarget.Texture2D, this.glTexture); GL.PixelStore(PixelStoreParameter.PackAlignment, Math.Min(tSizeInByte, 8)); if (glFormat == (PixelFormat)GLPixelFormat.CompressedTextureFormats) { // Note: for compressed format Format.GetSize() returns the size of a 4x4 block var pixelToT = Format.GetSize() / tSizeInByte; var tFullWidth = Math.Max(this.width >> level, 1) / 4 * pixelToT; var temp = new T[Math.Max(this.height >> level, 1) / 4 * tFullWidth]; GL.GetCompressedTexImage(TextureTarget.Texture2D, level, temp); GraphicsExtensions.CheckGLError(); var rowCount = rect.Height / 4; var tRectWidth = rect.Width / 4 * Format.GetSize() / tSizeInByte; for (var r = 0; r < rowCount; r++) { var tempStart = rect.X / 4 * pixelToT + (rect.Top / 4 + r) * tFullWidth; var dataStart = startIndex + r * tRectWidth; Array.Copy(temp, tempStart, data, dataStart, tRectWidth); } } else { // we need to convert from our format size to the size of T here var tFullWidth = Math.Max(this.width >> level, 1) * Format.GetSize() / tSizeInByte; var temp = new T[Math.Max(this.height >> level, 1) * tFullWidth]; GL.GetTexImage(TextureTarget.Texture2D, level, glFormat, glType, temp); GraphicsExtensions.CheckGLError(); var pixelToT = Format.GetSize() / tSizeInByte; var rowCount = rect.Height; var tRectWidth = rect.Width * pixelToT; for (var r = 0; r < rowCount; r++) { var tempStart = rect.X * pixelToT + (r + rect.Top) * tFullWidth; var dataStart = startIndex + r * tRectWidth; Array.Copy(temp, tempStart, data, dataStart, tRectWidth); } } #endif }
internal virtual void DeleteRenderbuffer(int renderbuffer) { GL.DeleteRenderbuffers(1, ref renderbuffer); GraphicsExtensions.CheckGLError(); }
internal void PlatformApplyState(GraphicsDevice device, bool force = false) { if (force || this.DepthBufferEnable != device._lastDepthStencilState.DepthBufferEnable) { if (!DepthBufferEnable) { GL.Disable(EnableCap.DepthTest); GraphicsExtensions.CheckGLError(); } else { // enable Depth Buffer GL.Enable(EnableCap.DepthTest); GraphicsExtensions.CheckGLError(); } device._lastDepthStencilState.DepthBufferEnable = this.DepthBufferEnable; } if (force || this.DepthBufferFunction != device._lastDepthStencilState.DepthBufferFunction) { GL.DepthFunc(DepthBufferFunction.GetDepthFunction()); GraphicsExtensions.CheckGLError(); device._lastDepthStencilState.DepthBufferFunction = this.DepthBufferFunction; } if (force || this.DepthBufferWriteEnable != device._lastDepthStencilState.DepthBufferWriteEnable) { GL.DepthMask(DepthBufferWriteEnable); GraphicsExtensions.CheckGLError(); device._lastDepthStencilState.DepthBufferWriteEnable = this.DepthBufferWriteEnable; } if (force || this.StencilEnable != device._lastDepthStencilState.StencilEnable) { if (!StencilEnable) { GL.Disable(EnableCap.StencilTest); GraphicsExtensions.CheckGLError(); } else { // enable Stencil GL.Enable(EnableCap.StencilTest); GraphicsExtensions.CheckGLError(); } device._lastDepthStencilState.StencilEnable = this.StencilEnable; } // set function if (this.TwoSidedStencilMode) { var cullFaceModeFront = StencilFace.Front; var cullFaceModeBack = StencilFace.Back; var stencilFaceFront = StencilFace.Front; var stencilFaceBack = StencilFace.Back; if (force || this.TwoSidedStencilMode != device._lastDepthStencilState.TwoSidedStencilMode || this.StencilFunction != device._lastDepthStencilState.StencilFunction || this.ReferenceStencil != device._lastDepthStencilState.ReferenceStencil || this.StencilMask != device._lastDepthStencilState.StencilMask) { GL.StencilFuncSeparate(cullFaceModeFront, GetStencilFunc(this.StencilFunction), this.ReferenceStencil, this.StencilMask); GraphicsExtensions.CheckGLError(); device._lastDepthStencilState.StencilFunction = this.StencilFunction; device._lastDepthStencilState.ReferenceStencil = this.ReferenceStencil; device._lastDepthStencilState.StencilMask = this.StencilMask; } if (force || this.TwoSidedStencilMode != device._lastDepthStencilState.TwoSidedStencilMode || this.CounterClockwiseStencilFunction != device._lastDepthStencilState.CounterClockwiseStencilFunction || this.ReferenceStencil != device._lastDepthStencilState.ReferenceStencil || this.StencilMask != device._lastDepthStencilState.StencilMask) { GL.StencilFuncSeparate(cullFaceModeBack, GetStencilFunc(this.CounterClockwiseStencilFunction), this.ReferenceStencil, this.StencilMask); GraphicsExtensions.CheckGLError(); device._lastDepthStencilState.CounterClockwiseStencilFunction = this.CounterClockwiseStencilFunction; device._lastDepthStencilState.ReferenceStencil = this.ReferenceStencil; device._lastDepthStencilState.StencilMask = this.StencilMask; } if (force || this.TwoSidedStencilMode != device._lastDepthStencilState.TwoSidedStencilMode || this.StencilFail != device._lastDepthStencilState.StencilFail || this.StencilDepthBufferFail != device._lastDepthStencilState.StencilDepthBufferFail || this.StencilPass != device._lastDepthStencilState.StencilPass) { GL.StencilOpSeparate(stencilFaceFront, GetStencilOp(this.StencilFail), GetStencilOp(this.StencilDepthBufferFail), GetStencilOp(this.StencilPass)); GraphicsExtensions.CheckGLError(); device._lastDepthStencilState.StencilFail = this.StencilFail; device._lastDepthStencilState.StencilDepthBufferFail = this.StencilDepthBufferFail; device._lastDepthStencilState.StencilPass = this.StencilPass; } if (force || this.TwoSidedStencilMode != device._lastDepthStencilState.TwoSidedStencilMode || this.CounterClockwiseStencilFail != device._lastDepthStencilState.CounterClockwiseStencilFail || this.CounterClockwiseStencilDepthBufferFail != device._lastDepthStencilState.CounterClockwiseStencilDepthBufferFail || this.CounterClockwiseStencilPass != device._lastDepthStencilState.CounterClockwiseStencilPass) { GL.StencilOpSeparate(stencilFaceBack, GetStencilOp(this.CounterClockwiseStencilFail), GetStencilOp(this.CounterClockwiseStencilDepthBufferFail), GetStencilOp(this.CounterClockwiseStencilPass)); GraphicsExtensions.CheckGLError(); device._lastDepthStencilState.CounterClockwiseStencilFail = this.CounterClockwiseStencilFail; device._lastDepthStencilState.CounterClockwiseStencilDepthBufferFail = this.CounterClockwiseStencilDepthBufferFail; device._lastDepthStencilState.CounterClockwiseStencilPass = this.CounterClockwiseStencilPass; } } else { if (force || this.TwoSidedStencilMode != device._lastDepthStencilState.TwoSidedStencilMode || this.StencilFunction != device._lastDepthStencilState.StencilFunction || this.ReferenceStencil != device._lastDepthStencilState.ReferenceStencil || this.StencilMask != device._lastDepthStencilState.StencilMask) { GL.StencilFunc(GetStencilFunc(this.StencilFunction), ReferenceStencil, StencilMask); GraphicsExtensions.CheckGLError(); device._lastDepthStencilState.StencilFunction = this.StencilFunction; device._lastDepthStencilState.ReferenceStencil = this.ReferenceStencil; device._lastDepthStencilState.StencilMask = this.StencilMask; } if (force || this.TwoSidedStencilMode != device._lastDepthStencilState.TwoSidedStencilMode || this.StencilFail != device._lastDepthStencilState.StencilFail || this.StencilDepthBufferFail != device._lastDepthStencilState.StencilDepthBufferFail || this.StencilPass != device._lastDepthStencilState.StencilPass) { GL.StencilOp(GetStencilOp(StencilFail), GetStencilOp(StencilDepthBufferFail), GetStencilOp(StencilPass)); GraphicsExtensions.CheckGLError(); device._lastDepthStencilState.StencilFail = this.StencilFail; device._lastDepthStencilState.StencilDepthBufferFail = this.StencilDepthBufferFail; device._lastDepthStencilState.StencilPass = this.StencilPass; } } device._lastDepthStencilState.TwoSidedStencilMode = this.TwoSidedStencilMode; if (force || this.StencilWriteMask != device._lastDepthStencilState.StencilWriteMask) { GL.StencilMask(this.StencilWriteMask); GraphicsExtensions.CheckGLError(); device._lastDepthStencilState.StencilWriteMask = this.StencilWriteMask; } }
internal virtual void GenFramebuffer(out int framebuffer) { GL.GenFramebuffers(1, out framebuffer); GraphicsExtensions.CheckGLError(); }
private void PlatformResolveRenderTargets() { if (this._currentRenderTargetCount == 0) { return; } var renderTargetBinding = this._currentRenderTargetBindings[0]; var renderTarget = renderTargetBinding.RenderTarget as IRenderTarget; if (renderTarget.MultiSampleCount > 0 && this.framebufferHelper.SupportsBlitFramebuffer) { var glResolveFramebuffer = 0; if (!this.glResolveFramebuffers.TryGetValue(this._currentRenderTargetBindings, out glResolveFramebuffer)) { this.framebufferHelper.GenFramebuffer(out glResolveFramebuffer); this.framebufferHelper.BindFramebuffer(glResolveFramebuffer); for (var i = 0; i < this._currentRenderTargetCount; ++i) { this.framebufferHelper.FramebufferTexture2D((int)(FramebufferAttachment.ColorAttachment0 + i), (int)renderTarget.GetFramebufferTarget(renderTargetBinding), renderTarget.GLTexture); } this.glResolveFramebuffers.Add((RenderTargetBinding[])this._currentRenderTargetBindings.Clone(), glResolveFramebuffer); } else { this.framebufferHelper.BindFramebuffer(glResolveFramebuffer); } // The only fragment operations which affect the resolve are the pixel ownership test, the scissor test, and dithering. if (this._lastRasterizerState.ScissorTestEnable) { GL.Disable(EnableCap.ScissorTest); GraphicsExtensions.CheckGLError(); } var glFramebuffer = this.glFramebuffers[this._currentRenderTargetBindings]; this.framebufferHelper.BindReadFramebuffer(glFramebuffer); for (var i = 0; i < this._currentRenderTargetCount; ++i) { renderTargetBinding = this._currentRenderTargetBindings[i]; renderTarget = renderTargetBinding.RenderTarget as IRenderTarget; this.framebufferHelper.BlitFramebuffer(i, renderTarget.Width, renderTarget.Height); } if (renderTarget.RenderTargetUsage == RenderTargetUsage.DiscardContents && this.framebufferHelper.SupportsInvalidateFramebuffer) { this.framebufferHelper.InvalidateReadFramebuffer(); } if (this._lastRasterizerState.ScissorTestEnable) { GL.Enable(EnableCap.ScissorTest); GraphicsExtensions.CheckGLError(); } } for (var i = 0; i < this._currentRenderTargetCount; ++i) { renderTargetBinding = this._currentRenderTargetBindings[i]; renderTarget = renderTargetBinding.RenderTarget as IRenderTarget; if (renderTarget.LevelCount > 1) { GL.BindTexture((TextureTarget)renderTarget.GLTarget, renderTarget.GLTexture); GraphicsExtensions.CheckGLError(); this.framebufferHelper.GenerateMipmap((int)renderTarget.GLTarget); } } }
internal virtual void BindReadFramebuffer(int readFramebuffer) { GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, readFramebuffer); GraphicsExtensions.CheckGLError(); }
internal void PlatformApplyState(bool applyShaders) { if (_scissorRectangleDirty) { var scissorRect = _scissorRectangle; if (!IsRenderTargetBound) { scissorRect.Y = _viewport.Height - scissorRect.Y - scissorRect.Height; } GL.Scissor(scissorRect.X, scissorRect.Y, scissorRect.Width, scissorRect.Height); GraphicsExtensions.CheckGLError(); _scissorRectangleDirty = false; } // If we're not applying shaders then early out now. if (!applyShaders) { return; } if (_indexBufferDirty) { if (_indexBuffer != null) { GL.BindBuffer(BufferTarget.ElementArrayBuffer, _indexBuffer.ibo); GraphicsExtensions.CheckGLError(); } _indexBufferDirty = false; } if (_vertexBuffersDirty) { if (_vertexBuffers.Count > 0) { GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexBuffers.Get(0).VertexBuffer.vbo); GraphicsExtensions.CheckGLError(); } _vertexBuffersDirty = false; } if (_vertexShader == null) { throw new InvalidOperationException("A vertex shader must be set!"); } if (_pixelShader == null) { throw new InvalidOperationException("A pixel shader must be set!"); } if (_vertexShaderDirty || _pixelShaderDirty) { ActivateShaderProgram(); if (_vertexShaderDirty) { unchecked { _graphicsMetrics._vertexShaderCount++; } } if (_pixelShaderDirty) { unchecked { _graphicsMetrics._pixelShaderCount++; } } _vertexShaderDirty = _pixelShaderDirty = false; } _vertexConstantBuffers.SetConstantBuffers(this, _shaderProgram); _pixelConstantBuffers.SetConstantBuffers(this, _shaderProgram); Textures.SetTextures(this); SamplerStates.PlatformSetSamplers(this); }
internal void Activate(GraphicsDevice device, TextureTarget target, bool useMipmaps = false) { if (GraphicsDevice == null) { // We're now bound to a device... no one should // be changing the state of this object now! GraphicsDevice = device; } Debug.Assert(GraphicsDevice == device, "The state was created for a different device!"); switch (Filter) { case TextureFilter.Point: if (GraphicsDevice.GraphicsCapabilities.SupportsTextureFilterAnisotropic) { GL.TexParameter(target, TextureParameterNameTextureMaxAnisotropy, 1.0f); GraphicsExtensions.CheckGLError(); } GL.TexParameter(target, TextureParameterName.TextureMinFilter, (int)(useMipmaps ? TextureMinFilter.NearestMipmapNearest : TextureMinFilter.Nearest)); GraphicsExtensions.CheckGLError(); GL.TexParameter(target, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest); GraphicsExtensions.CheckGLError(); break; case TextureFilter.Linear: if (GraphicsDevice.GraphicsCapabilities.SupportsTextureFilterAnisotropic) { GL.TexParameter(target, TextureParameterNameTextureMaxAnisotropy, 1.0f); GraphicsExtensions.CheckGLError(); } GL.TexParameter(target, TextureParameterName.TextureMinFilter, (int)(useMipmaps ? TextureMinFilter.LinearMipmapLinear : TextureMinFilter.Linear)); GraphicsExtensions.CheckGLError(); GL.TexParameter(target, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); GraphicsExtensions.CheckGLError(); break; case TextureFilter.Anisotropic: if (GraphicsDevice.GraphicsCapabilities.SupportsTextureFilterAnisotropic) { GL.TexParameter(target, TextureParameterNameTextureMaxAnisotropy, MathHelper.Clamp(this.MaxAnisotropy, 1.0f, GraphicsDevice.GraphicsCapabilities.MaxTextureAnisotropy)); GraphicsExtensions.CheckGLError(); } GL.TexParameter(target, TextureParameterName.TextureMinFilter, (int)(useMipmaps ? TextureMinFilter.LinearMipmapLinear : TextureMinFilter.Linear)); GraphicsExtensions.CheckGLError(); GL.TexParameter(target, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); GraphicsExtensions.CheckGLError(); break; case TextureFilter.PointMipLinear: if (GraphicsDevice.GraphicsCapabilities.SupportsTextureFilterAnisotropic) { GL.TexParameter(target, TextureParameterNameTextureMaxAnisotropy, 1.0f); GraphicsExtensions.CheckGLError(); } GL.TexParameter(target, TextureParameterName.TextureMinFilter, (int)(useMipmaps ? TextureMinFilter.NearestMipmapLinear : TextureMinFilter.Nearest)); GraphicsExtensions.CheckGLError(); GL.TexParameter(target, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest); GraphicsExtensions.CheckGLError(); break; case TextureFilter.LinearMipPoint: if (GraphicsDevice.GraphicsCapabilities.SupportsTextureFilterAnisotropic) { GL.TexParameter(target, TextureParameterNameTextureMaxAnisotropy, 1.0f); GraphicsExtensions.CheckGLError(); } GL.TexParameter(target, TextureParameterName.TextureMinFilter, (int)(useMipmaps ? TextureMinFilter.LinearMipmapNearest : TextureMinFilter.Linear)); GraphicsExtensions.CheckGLError(); GL.TexParameter(target, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); GraphicsExtensions.CheckGLError(); break; case TextureFilter.MinLinearMagPointMipLinear: if (GraphicsDevice.GraphicsCapabilities.SupportsTextureFilterAnisotropic) { GL.TexParameter(target, TextureParameterNameTextureMaxAnisotropy, 1.0f); GraphicsExtensions.CheckGLError(); } GL.TexParameter(target, TextureParameterName.TextureMinFilter, (int)(useMipmaps ? TextureMinFilter.LinearMipmapLinear : TextureMinFilter.Linear)); GraphicsExtensions.CheckGLError(); GL.TexParameter(target, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest); GraphicsExtensions.CheckGLError(); break; case TextureFilter.MinLinearMagPointMipPoint: if (GraphicsDevice.GraphicsCapabilities.SupportsTextureFilterAnisotropic) { GL.TexParameter(target, TextureParameterNameTextureMaxAnisotropy, 1.0f); GraphicsExtensions.CheckGLError(); } GL.TexParameter(target, TextureParameterName.TextureMinFilter, (int)(useMipmaps ? TextureMinFilter.LinearMipmapNearest: TextureMinFilter.Linear)); GraphicsExtensions.CheckGLError(); GL.TexParameter(target, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest); GraphicsExtensions.CheckGLError(); break; case TextureFilter.MinPointMagLinearMipLinear: if (GraphicsDevice.GraphicsCapabilities.SupportsTextureFilterAnisotropic) { GL.TexParameter(target, TextureParameterNameTextureMaxAnisotropy, 1.0f); GraphicsExtensions.CheckGLError(); } GL.TexParameter(target, TextureParameterName.TextureMinFilter, (int)(useMipmaps ? TextureMinFilter.NearestMipmapLinear: TextureMinFilter.Nearest)); GraphicsExtensions.CheckGLError(); GL.TexParameter(target, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); GraphicsExtensions.CheckGLError(); break; case TextureFilter.MinPointMagLinearMipPoint: if (GraphicsDevice.GraphicsCapabilities.SupportsTextureFilterAnisotropic) { GL.TexParameter(target, TextureParameterNameTextureMaxAnisotropy, 1.0f); GraphicsExtensions.CheckGLError(); } GL.TexParameter(target, TextureParameterName.TextureMinFilter, (int)(useMipmaps ? TextureMinFilter.NearestMipmapNearest: TextureMinFilter.Nearest)); GraphicsExtensions.CheckGLError(); GL.TexParameter(target, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); GraphicsExtensions.CheckGLError(); break; default: throw new NotSupportedException(); } // Set up texture addressing. GL.TexParameter(target, TextureParameterName.TextureWrapS, (int)GetWrapMode(AddressU)); GraphicsExtensions.CheckGLError(); GL.TexParameter(target, TextureParameterName.TextureWrapT, (int)GetWrapMode(AddressV)); GraphicsExtensions.CheckGLError(); #if !GLES // Border color is not supported by glTexParameter in OpenGL ES 2.0 _openGLBorderColor[0] = BorderColor.R / 255.0f; _openGLBorderColor[1] = BorderColor.G / 255.0f; _openGLBorderColor[2] = BorderColor.B / 255.0f; _openGLBorderColor[3] = BorderColor.A / 255.0f; GL.TexParameter(target, TextureParameterName.TextureBorderColor, _openGLBorderColor); GraphicsExtensions.CheckGLError(); // LOD bias is not supported by glTexParameter in OpenGL ES 2.0 GL.TexParameter(target, TextureParameterName.TextureLodBias, MipMapLevelOfDetailBias); GraphicsExtensions.CheckGLError(); // Comparison samplers are not supported in OpenGL ES 2.0 (without an extension, anyway) if (ComparisonFunction != CompareFunction.Never) { GL.TexParameter(target, TextureParameterName.TextureCompareMode, (int)TextureCompareMode.CompareRefToTexture); GraphicsExtensions.CheckGLError(); GL.TexParameter(target, TextureParameterName.TextureCompareFunc, (int)ComparisonFunction.GetDepthFunction()); GraphicsExtensions.CheckGLError(); } else { GL.TexParameter(target, TextureParameterName.TextureCompareMode, (int)TextureCompareMode.None); GraphicsExtensions.CheckGLError(); } #endif if (GraphicsDevice.GraphicsCapabilities.SupportsTextureMaxLevel) { if (this.MaxMipLevel > 0) { GL.TexParameter(TextureTarget.Texture2D, TextureParameterNameTextureMaxLevel, this.MaxMipLevel); } else { GL.TexParameter(TextureTarget.Texture2D, TextureParameterNameTextureMaxLevel, 1000); } } }