/// <inheritdoc/>
        protected override void Destroy()
        {
            using (GraphicsDevice.UseOpenGLCreationContext())
            {
                GL.DeleteProgram(ProgramId);
            }

            ProgramId = 0;

            base.Destroy();
        }
예제 #2
0
        /// <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();
        }
예제 #3
0
        /// <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();
        }
예제 #4
0
        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));
            }
        }
예제 #6
0
        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);
        }