/// <inheritdoc/> protected override void Destroy() { using (GraphicsDevice.UseOpenGLCreationContext()) { GL.DeleteProgram(ProgramId); } ProgramId = 0; base.Destroy(); }
/// <inheritdoc/> protected internal override void OnDestroyed() { using (GraphicsDevice.UseOpenGLCreationContext()) { GL.DeleteTextures(1, ref TextureId); GL.DeleteBuffers(1, ref BufferId); } BufferId = 0; if (GraphicsDevice != null) { GraphicsDevice.RegisterBufferMemoryUsage(-SizeInBytes); } base.OnDestroyed(); }
/// <inheritdoc/> protected internal override void OnDestroyed() { using (GraphicsDevice.UseOpenGLCreationContext()) { if (TextureId != 0 && ParentTexture == null) { if (IsRenderbuffer) { GL.DeleteRenderbuffers(1, ref TextureId); } else { GL.DeleteTextures(1, ref TextureId); } GraphicsDevice.RegisterTextureMemoryUsage(-SizeInBytes); } if (stencilId != 0) { GL.DeleteRenderbuffers(1, ref stencilId); } if (pixelBufferObjectId != 0) { GL.DeleteBuffers(1, ref pixelBufferObjectId); } } TextureTotalSize = 0; TextureId = 0; stencilId = 0; pixelBufferObjectId = 0; base.OnDestroyed(); }
protected void Init(IntPtr dataPointer) { switch (Description.Usage) { case GraphicsResourceUsage.Default: case GraphicsResourceUsage.Immutable: BufferUsageHint = BufferUsageHint.StaticDraw; break; case GraphicsResourceUsage.Dynamic: case GraphicsResourceUsage.Staging: BufferUsageHint = BufferUsageHint.DynamicDraw; break; default: throw new ArgumentOutOfRangeException("description.Usage"); } using (var openglContext = GraphicsDevice.UseOpenGLCreationContext()) { if ((Flags & BufferFlags.ShaderResource) != 0 && !GraphicsDevice.HasTextureBuffers) { // Create a texture instead of a buffer on platforms where it's not supported elementCount = SizeInBytes / bufferTextureElementSize; TextureTarget = TextureTarget.Texture2D; GL.GenTextures(1, out TextureId); GL.BindTexture(TextureTarget, TextureId); 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); UpdateTextureSubresource(dataPointer, 0, 0, SizeInBytes); 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; } } else { // If we're on main context, unbind VAO before binding context. // It will be bound again on next draw. //if (!creationContext.UseDeviceCreationContext) // GraphicsDevice.UnbindVertexArrayObject(); GL.GenBuffers(1, out BufferId); GL.BindBuffer(BufferTarget, BufferId); GL.BufferData(BufferTarget, (IntPtr)Description.SizeInBytes, dataPointer, BufferUsageHint); GL.BindBuffer(BufferTarget, 0); if ((Flags & BufferFlags.ShaderResource) != 0) { #if STRIDE_GRAPHICS_API_OPENGLES Internal.Refactor.ThrowNotImplementedException(); #else TextureTarget = TextureTarget.TextureBuffer; GL.GenTextures(1, out TextureId); GL.BindTexture(TextureTarget, TextureId); // TODO: Check if this is really valid to cast PixelInternalFormat to SizedInternalFormat in all cases? GL.TexBuffer(TextureBufferTarget.TextureBuffer, (SizedInternalFormat)TextureInternalFormat, BufferId); #endif } } } }
private void CreateShaders() { using (GraphicsDevice.UseOpenGLCreationContext()) { ProgramId = GL.CreateProgram(); // Attach shaders foreach (var shader in effectBytecode.Stages) { ShaderType shaderStage; switch (shader.Stage) { case ShaderStage.Vertex: shaderStage = ShaderType.VertexShader; break; case ShaderStage.Pixel: shaderStage = ShaderType.FragmentShader; break; default: throw new Exception("Unsupported shader stage"); } var shaderSource = shader.GetDataAsString(); //edit the source a little to emulateDepthClamp if (emulateDepthClamp) { var mainPattern = new Regex(@"void\s+main\s*\(\)"); if (shaderStage == ShaderType.VertexShader) { //bypass our regular main shaderSource = mainPattern.Replace(shaderSource, @"void _edc_main()"); shaderSource += VertexShaderDepthClamp; } else if (shaderStage == ShaderType.FragmentShader) { //bypass our regular main shaderSource = mainPattern.Replace(shaderSource, @"void _edc_main()"); shaderSource += FragmentShaderDepthClamp; } } // On OpenGL ES 3.1 and before, texture buffers are likely not supported so we have a fallback using textures shaderSource = shaderSource.Replace("#define texelFetchBufferPlaceholder", GraphicsDevice.HasTextureBuffers ? "#define texelFetchBuffer(sampler, P) texelFetch(sampler, P)" : ("#define samplerBuffer sampler2D\n" + "#define isamplerBuffer isampler2D\n" + "#define usamplerBuffer usampler2D\n" + "#define texelFetchBuffer(sampler, P) texelFetch(sampler, ivec2((P) & 0xFFF, (P) >> 12), 0)\n")); var shaderId = GL.CreateShader(shaderStage); GL.ShaderSource(shaderId, shaderSource); GL.CompileShader(shaderId); int compileStatus; GL.GetShader(shaderId, ShaderParameter.CompileStatus, out compileStatus); if (compileStatus != 1) { var glErrorMessage = GL.GetShaderInfoLog(shaderId); throw new InvalidOperationException("Error while compiling GLSL shader. [{0}]".ToFormat(glErrorMessage)); } GL.AttachShader(ProgramId, shaderId); } #if !STRIDE_GRAPHICS_API_OPENGLES // Mark program as retrievable (necessary for later GL.GetProgramBinary). GL.ProgramParameter(ProgramId, ProgramParameterName.ProgramBinaryRetrievableHint, 1); #endif // Link OpenGL program GL.LinkProgram(ProgramId); // Check link results int linkStatus; GL.GetProgram(ProgramId, GetProgramParameterName.LinkStatus, out linkStatus); if (linkStatus != 1) { var infoLog = GL.GetProgramInfoLog(ProgramId); throw new InvalidOperationException("Error while linking GLSL shaders.\n" + infoLog); } if (Attributes.Count == 0) // the shader wasn't analyzed yet // TODO Is it possible? { // Build attributes list for shader signature int activeAttribCount; GL.GetProgram(ProgramId, GetProgramParameterName.ActiveAttributes, out activeAttribCount); for (int activeAttribIndex = 0; activeAttribIndex < activeAttribCount; ++activeAttribIndex) { int size; ActiveAttribType type; var attribName = GL.GetActiveAttrib(ProgramId, activeAttribIndex, out size, out type); var attribIndex = GL.GetAttribLocation(ProgramId, attribName); Attributes.Add(attribName, attribIndex); } } CreateReflection(Reflection, effectBytecode.Stages[0].Stage); // need to regenerate the Uniforms on OpenGL ES } // output the gathered errors foreach (var message in reflectionResult.Messages) { Console.WriteLine(message); } if (reflectionResult.HasErrors) { throw new Exception(reflectionResult.Messages.Select(x => x.ToString()).Aggregate((x, y) => x + "\n" + y)); } }
private void InitializeFromImpl(DataBox[] dataBoxes = null) { if (ParentTexture != null) { CopyParentAttributes(); } if (TextureId == 0) { TextureTarget = GetTextureTarget(Dimension); 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; IsDepthBuffer = ((Description.Flags & TextureFlags.DepthStencil) != 0); if (IsDepthBuffer) { HasStencil = InternalHasStencil(Format); } else { HasStencil = false; } if ((Description.Flags & TextureFlagsCustomResourceId) != 0) { return; } using (var openglContext = GraphicsDevice.UseOpenGLCreationContext()) { TextureTotalSize = ComputeBufferTotalSize(); if (Description.Usage == GraphicsResourceUsage.Staging) { InitializeStagingPixelBufferObject(dataBoxes); return; // TODO: This return causes "GraphicsDevice.RegisterTextureMemoryUsage(SizeInBytes);" not to get entered. Is that okay? } // Depth textures are renderbuffers for now // TODO: PERFORMANCE: Why? I think we should change that so we can sample them directly. // TODO: enable switch // TODO: What does this comment even mean? IsRenderbuffer = !Description.IsShaderResource; // Force to renderbuffer if MSAA is on because we don't support MSAA textures ATM (and they don't exist on OpenGL ES). if (Description.IsMultisample) { // TODO: Ideally the caller of this method should be aware of this "force to renderbuffer", // because the caller won't be able to bind it as a texture. IsRenderbuffer = true; } if (IsRenderbuffer) { CreateRenderbuffer(); return; // TODO: This return causes "GraphicsDevice.RegisterTextureMemoryUsage(SizeInBytes);" not to get entered. Is that okay? } GL.GenTextures(1, out TextureId); GL.BindTexture(TextureTarget, TextureId); SetFilterMode(); if (Description.MipLevels == 0) { throw new NotImplementedException(); } var setSize = TextureSetSize(TextureTarget); for (var arrayIndex = 0; arrayIndex < Description.ArraySize; ++arrayIndex) { int offsetArray = arrayIndex * Description.MipLevels; for (int mipLevel = 0; mipLevel < Description.MipLevels; ++mipLevel) { DataBox dataBox; Int3 dimensions = new Int3(CalculateMipSize(Description.Width, mipLevel), CalculateMipSize(Description.Height, mipLevel), CalculateMipSize(Description.Depth, mipLevel)); if (dataBoxes != null && mipLevel < dataBoxes.Length) { if (setSize > 1 && !compressed && dataBoxes[mipLevel].RowPitch != dimensions.X * TexturePixelSize) { throw new NotSupportedException("Can't upload texture with pitch in glTexImage2D/3D."); } // Might be possible, need to check API better. dataBox = dataBoxes[offsetArray + mipLevel]; } else { dataBox = new DataBox(); } switch (TextureTarget) { case TextureTarget.Texture1D: CreateTexture1D(compressed, dimensions.X, mipLevel, dataBox); break; case TextureTarget.Texture2D: case TextureTarget.TextureCubeMap: CreateTexture2D(compressed, dimensions.X, dimensions.Y, mipLevel, arrayIndex, dataBox); break; case TextureTarget.Texture3D: CreateTexture3D(compressed, dimensions.X, dimensions.Y, dimensions.Z, mipLevel, dataBox); break; case TextureTarget.Texture2DArray: CreateTexture2DArray(compressed, dimensions.X, dimensions.Y, mipLevel, arrayIndex, dataBox); break; } } } GL.BindTexture(TextureTarget, 0); // This unbinds the texture. 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.RegisterTextureMemoryUsage(SizeInBytes); } }
internal GraphicsDeviceFeatures(GraphicsDevice deviceRoot) { mapFeaturesPerFormat = new FeaturesPerFormat[256]; HasSRgb = true; using (deviceRoot.UseOpenGLCreationContext()) { Vendor = GL.GetString(StringName.Vendor); Renderer = GL.GetString(StringName.Renderer); #if STRIDE_GRAPHICS_API_OPENGLES SupportedExtensions = GL.GetString(StringName.Extensions).Split(' '); #else int numExtensions; GL.GetInteger(GetPName.NumExtensions, out numExtensions); SupportedExtensions = new string[numExtensions]; for (int extensionIndex = 0; extensionIndex < numExtensions; ++extensionIndex) { SupportedExtensions[extensionIndex] = GL.GetString(StringNameIndexed.Extensions, extensionIndex); } #endif } #if STRIDE_GRAPHICS_API_OPENGLES deviceRoot.HasExtTextureFormatBGRA8888 = SupportedExtensions.Contains("GL_EXT_texture_format_BGRA8888") || SupportedExtensions.Contains("GL_APPLE_texture_format_BGRA8888"); deviceRoot.HasKhronosDebug = deviceRoot.currentVersion >= 320 || SupportedExtensions.Contains("GL_KHR_debug"); deviceRoot.HasTimerQueries = SupportedExtensions.Contains("GL_EXT_disjoint_timer_query"); // Either 3.2+, or 3.1+ with GL_EXT_texture_buffer // TODO: For now we don't have proper ES3 bindings on Android (and possibly iOS) deviceRoot.HasTextureBuffers = false; //deviceRoot.HasTextureBuffers = (deviceRoot.version >= 320) // || (deviceRoot.version >= 310 && SupportedExtensions.Contains("GL_EXT_texture_buffer")); // Compute shaders available in OpenGL ES 3.1 HasComputeShaders = deviceRoot.currentVersion >= 310; HasDoublePrecision = false; HasDepthAsSRV = true; HasDepthAsReadOnlyRT = true; HasMultisampleDepthAsSRV = true; deviceRoot.HasDepthClamp = SupportedExtensions.Contains("GL_ARB_depth_clamp"); // TODO: from 3.1: draw indirect, separate shader object // TODO: check tessellation & geometry shaders: GL_ANDROID_extension_pack_es31a #else deviceRoot.HasDXT = SupportedExtensions.Contains("GL_EXT_texture_compression_s3tc"); deviceRoot.HasTextureBuffers = true; deviceRoot.HasKhronosDebug = deviceRoot.currentVersion >= 430 || SupportedExtensions.Contains("GL_KHR_debug"); deviceRoot.HasTimerQueries = deviceRoot.version >= 320; // Compute shaders available in OpenGL 4.3 HasComputeShaders = deviceRoot.version >= 430; HasDoublePrecision = SupportedExtensions.Contains("GL_ARB_vertex_attrib_64bit"); HasDepthAsSRV = true; HasDepthAsReadOnlyRT = true; HasMultisampleDepthAsSRV = true; deviceRoot.HasDepthClamp = true; // TODO: from 4.0: tessellation, draw indirect // TODO: from 4.1: separate shader object #endif deviceRoot.HasAnisotropicFiltering = SupportedExtensions.Contains("GL_EXT_texture_filter_anisotropic"); HasResourceRenaming = true; HasDriverCommandLists = false; HasMultiThreadingConcurrentResources = false; // Find shader model based on OpenGL version (might need to check extensions more carefully) RequestedProfile = deviceRoot.requestedGraphicsProfile; CurrentProfile = OpenGLUtils.GetFeatureLevel(deviceRoot.currentVersion); EnumerateMSAASupportPerFormat(deviceRoot); }