public GLESHardwareVertexBuffer(HardwareBufferManagerBase manager, VertexDeclaration vertexDeclaration, int numVertices, BufferUsage usage, bool useShadowBuffer) : base(manager, vertexDeclaration, numVertices, usage, false, useShadowBuffer) { if (!useShadowBuffer) { throw new AxiomException("Only supported with shadowBuffer"); } var buffers = new int[1]; GL.GenBuffers(1, buffers); GLESConfig.GlCheckError(this); this._bufferID = buffers[0]; if (this._bufferID == 0) { throw new AxiomException("Cannot create GL ES vertex buffer"); } (Root.Instance.RenderSystem as GLESRenderSystem).BindGLBuffer(GLenum.ArrayBuffer, this._bufferID); GL.BufferData(GLenum.ArrayBuffer, new IntPtr(sizeInBytes), IntPtr.Zero, GLESHardwareBufferManager.GetGLUsage(usage)); GLESConfig.GlCheckError(this); }
public GLESHardwareIndexBuffer(HardwareBufferManagerBase manager, IndexType type, int numIndices, BufferUsage usage, bool useShadowBuffer) : base(manager, type, numIndices, usage, false, useShadowBuffer) { if (type == IndexType.Size32) { throw new AxiomException("32 bit hardware buffers are not allowed in OpenGL ES."); } if (!useShadowBuffer) { throw new AxiomException("Only support with shadowBuffer"); } OpenGL.GenBuffers(1, ref this._bufferId); GLESConfig.GlCheckError(this); if (this._bufferId == 0) { throw new AxiomException("Cannot create GL index buffer"); } OpenGL.BindBuffer(All.ElementArrayBuffer, this._bufferId); GLESConfig.GlCheckError(this); OpenGL.BufferData(All.ElementArrayBuffer, new IntPtr(sizeInBytes), IntPtr.Zero, GLESHardwareBufferManager.GetGLUsage(usage)); GLESConfig.GlCheckError(this); }
/// <summary> /// </summary> protected override void UpdateFromShadow() { if (useShadowBuffer && shadowUpdated && !suppressHardwareUpdate) { var srcData = shadowBuffer.Lock(lockStart, lockSize, BufferLocking.ReadOnly); OpenGL.BindBuffer(All.ElementArrayBuffer, this._bufferId); GLESConfig.GlCheckError(this); var srcPtr = new IntPtr(srcData.Ptr); // Update whole buffer if possible, otherwise normal if (lockStart == 0 && lockSize == sizeInBytes) { OpenGL.BufferData(All.ElementArrayBuffer, new IntPtr(sizeInBytes), srcPtr, GLESHardwareBufferManager.GetGLUsage(usage)); GLESConfig.GlCheckError(this); } else { OpenGL.BufferSubData(All.ElementArrayBuffer, new IntPtr(lockStart), new IntPtr(lockSize), srcPtr); GLESConfig.GlCheckError(this); } shadowBuffer.Unlock(); shadowUpdated = false; } }
/// <summary> /// </summary> /// <param name="offset"> </param> /// <param name="length"> </param> /// <param name="src"> </param> /// <param name="discardWholeBuffer"> </param> public override void WriteData(int offset, int length, BufferBase src, bool discardWholeBuffer) { OpenGL.BindBuffer(All.ElementArrayBuffer, this._bufferId); GLESConfig.GlCheckError(this); // Update the shadow buffer if (useShadowBuffer) { var destData = shadowBuffer.Lock(offset, length, discardWholeBuffer ? BufferLocking.Discard : BufferLocking.Normal); Memory.Copy(src, destData, length); shadowBuffer.Unlock(); } var srcPtr = src.Ptr; if (offset == 0 && length == sizeInBytes) { OpenGL.BufferData(All.ElementArrayBuffer, new IntPtr(sizeInBytes), ref srcPtr, GLESHardwareBufferManager.GetGLUsage(usage)); GLESConfig.GlCheckError(this); } else { if (discardWholeBuffer) { OpenGL.BufferData(All.ElementArrayBuffer, new IntPtr(sizeInBytes), IntPtr.Zero, GLESHardwareBufferManager.GetGLUsage(usage)); GLESConfig.GlCheckError(this); } // Now update the real buffer OpenGL.BufferSubData(All.ElementArrayBuffer, new IntPtr(offset), new IntPtr(length), ref srcPtr); GLESConfig.GlCheckError(this); } if (src.Ptr != srcPtr) { LogManager.Instance.Write("[GLES2] HardwareIndexBuffer.WriteData - buffer pointer modified by GL.BufferData."); } }
/// <summary> /// </summary> /// <param name="offset"> </param> /// <param name="length"> </param> /// <param name="locking"> </param> /// <returns> </returns> protected override BufferBase LockImpl(int offset, int length, BufferLocking locking) { All access = 0; if (isLocked) { throw new AxiomException("Invalid attempt to lock an index buffer that has already been locked"); } BufferBase retPtr = null; if (length < MapBufferThreshold) { retPtr = ((GLESHardwareBufferManager)HardwareBufferManager.Instance).AllocateScratch(length); if (retPtr != null) { this._lockedToScratch = true; this._scratchOffset = offset; this._scratchSize = length; this._scratchPtr = retPtr; this._scratchUploadOnUnlock = (locking != BufferLocking.ReadOnly); if (locking != BufferLocking.Discard) { this.ReadData(offset, length, retPtr); } } } else { throw new AxiomException("Invalid Buffer lockSize"); } if (retPtr == null) { OpenGL.BindBuffer(All.ElementArrayBuffer, this._bufferId); GLESConfig.GlCheckError(this); // Use glMapBuffer if (locking == BufferLocking.Discard) { OpenGL.BufferData(All.ElementArrayBuffer, new IntPtr(sizeInBytes), IntPtr.Zero, GLESHardwareBufferManager.GetGLUsage(usage)); GLESConfig.GlCheckError(this); } if ((usage & BufferUsage.WriteOnly) != 0) { access = All.WriteOnlyOes; } IntPtr pBuffer = OpenGLOES.MapBuffer(All.ElementArrayBuffer, access); GLESConfig.GlCheckError(this); if (pBuffer == IntPtr.Zero) { throw new AxiomException("Index Buffer: Out of memory"); } unsafe { // return offset retPtr = BufferBase.Wrap(pBuffer, sizeInBytes); } this._lockedToScratch = false; } isLocked = true; return(retPtr); }
/// <summary> /// /// </summary> /// <param name="primary"></param> private void CheckCaps( RenderTarget primary ) { _rsCapabilities = new RenderSystemCapabilities(); _rsCapabilities.DeviceName = OpenTK.Graphics.ES11.GL.GetString( All.Renderer ); _rsCapabilities.VendorName = OpenTK.Graphics.ES11.GL.GetString( All.Vendor ); _rsCapabilities.RendersystemName = Name; // GL ES 1.x is fixed function only _rsCapabilities.SetCapability( Capabilities.FixedFunction ); // Multitexturing support and set number of texture units int units = 0; OpenGL.GetInteger( All.MaxTextureUnits, ref units ); _rsCapabilities.TextureUnitCount = units; // Check for hardware stencil support and set bit depth int stencil = 0; OpenGL.GetInteger( All.StencilBits, ref stencil ); GLESConfig.GlCheckError( this ); if ( stencil != 0 ) { _rsCapabilities.SetCapability( Capabilities.StencilBuffer ); _rsCapabilities.StencilBufferBitCount = stencil; } // Scissor test is standard _rsCapabilities.SetCapability( Capabilities.ScissorTest ); // Vertex Buffer Objects are always supported by OpenGL ES _rsCapabilities.SetCapability( Capabilities.VertexBuffer ); // OpenGL ES - Check for these extensions too // For 1.1, http://www.khronos.org/registry/gles/api/1.1/glext.h // For 2.0, http://www.khronos.org/registry/gles/api/2.0/gl2ext.h if ( _glSupport.CheckExtension( "GL_IMG_texture_compression_pvrtc" ) || _glSupport.CheckExtension( "GL_AMD_compressed_3DC_texture" ) || _glSupport.CheckExtension( "GL_AMD_compressed_ATC_texture" ) || _glSupport.CheckExtension( "GL_OES_compressed_ETC1_RGB8_texture" ) || _glSupport.CheckExtension( "GL_OES_compressed_paletted_texture" ) ) { // TODO: Add support for compression types other than pvrtc _rsCapabilities.SetCapability( Capabilities.TextureCompression ); if ( _glSupport.CheckExtension( "GL_IMG_texture_compression_pvrtc" ) ) _rsCapabilities.SetCapability( Capabilities.TextureCompressionPVRTC ); } if ( _glSupport.CheckExtension( "GL_EXT_texture_filter_anisotropic" ) ) _rsCapabilities.SetCapability( Capabilities.AnisotropicFiltering ); if ( _glSupport.CheckExtension( "GL_OES_framebuffer_object" ) ) { LogManager.Instance.Write( "[GLES] Framebuffers are supported." ); _rsCapabilities.SetCapability( Capabilities.FrameBufferObjects ); _rsCapabilities.SetCapability( Capabilities.HardwareRenderToTexture ); } else { _rsCapabilities.SetCapability( Capabilities.PBuffer ); _rsCapabilities.SetCapability( Capabilities.HardwareRenderToTexture ); } // Cube map if ( _glSupport.CheckExtension( "GL_OES_texture_cube_map" ) ) _rsCapabilities.SetCapability( Capabilities.CubeMapping ); if ( _glSupport.CheckExtension( "GL_OES_stencil_wrap" ) ) _rsCapabilities.SetCapability( Capabilities.StencilWrap ); if ( _glSupport.CheckExtension( "GL_OES_blend_subtract" ) ) _rsCapabilities.SetCapability( Capabilities.AdvancedBlendOperations ); if ( _glSupport.CheckExtension( "GL_ANDROID_user_clip_plane" ) ) _rsCapabilities.SetCapability( Capabilities.UserClipPlanes ); if ( _glSupport.CheckExtension( "GL_OES_texture3D" ) ) _rsCapabilities.SetCapability( Capabilities.Texture3D ); // GL always shares vertex and fragment texture units (for now?) _rsCapabilities.VertexTextureUnitsShared = true; // Hardware support mipmapping _rsCapabilities.SetCapability( Capabilities.Automipmap ); if ( _glSupport.CheckExtension( "GL_EXT_texture_lod_bias" ) ) _rsCapabilities.SetCapability( Capabilities.MipmapLODBias ); //blending support _rsCapabilities.SetCapability( Capabilities.TextureBlending ); // DOT3 support is standard _rsCapabilities.SetCapability( Capabilities.Dot3 ); if ( _rsCapabilities.HasCapability( Capabilities.VertexBuffer ) ) { hardwareBufferManager = new GLESHardwareBufferManager(); } else { hardwareBufferManager = new GLESDefaultHardwareBufferManager(); } /// Do this after extension function pointers are initialised as the extension /// is used to probe further capabilities. int rttMode = 0; if ( ConfigOptions.ContainsKey( "RTT Preferred Mode" ) ) { ConfigOption opt = ConfigOptions[ "RTT Preferred Mode" ]; // RTT Mode: 0 use whatever available, 1 use PBuffers, 2 force use copying if ( opt.Value == "PBuffer" ) { rttMode = 1; } else if ( opt.Value == "Copy" ) { rttMode = 2; } } LogManager.Instance.Write( "[GLES] 'RTT Preferred Mode' = {0}", rttMode ); // Check for framebuffer object extension if ( _rsCapabilities.HasCapability( Capabilities.FrameBufferObjects ) && ( rttMode < 1 ) ) { if ( _rsCapabilities.HasCapability( Capabilities.HardwareRenderToTexture ) ) { // Create FBO manager LogManager.Instance.Write( "[GLES] Using GL_OES_framebuffer_object for rendering to textures (best)" ); _rttManager = new GLESFBORTTManager(); } } else { // Check GLSupport for PBuffer support if ( _rsCapabilities.HasCapability( Capabilities.PBuffer ) && rttMode < 2 ) { if ( _rsCapabilities.HasCapability( Capabilities.HardwareRenderToTexture ) ) { // Use PBuffers _rttManager = new GLESPBRTTManager(); LogManager.Instance.Write( "[GLES] Using PBuffers for rendering to textures" ); } } else { // No pbuffer support either -- fallback to simplest copying from framebuffer _rttManager = new GLESCopyingRTTManager(); LogManager.Instance.Write( "[GLES] Using framebuffer copy for rendering to textures (worst)" ); LogManager.Instance.Write( "[GLES] Warning: RenderTexture size is restricted to size of framebuffer." ); } _rsCapabilities.MultiRenderTargetCount = 1; } // Point size float ps = 0; OpenGL.GetFloat( All.PointSizeMax, ref ps ); GLESConfig.GlCheckError( this ); _rsCapabilities.MaxPointSize = ps; // Point sprites if ( _glSupport.CheckExtension( "GL_OES_point_sprite" ) ) _rsCapabilities.SetCapability( Capabilities.PointSprites ); _rsCapabilities.SetCapability( Capabilities.PointExtendedParameters ); // UBYTE4 always supported _rsCapabilities.SetCapability( Capabilities.VertexFormatUByte4 ); // Infinite far plane always supported _rsCapabilities.SetCapability( Capabilities.InfiniteFarPlane ); // hardware occlusion support _rsCapabilities.SetCapability( Capabilities.HardwareOcculusion ); //// Check for Float textures if ( _glSupport.CheckExtension( "GL_OES_texture_half_float" ) ) _rsCapabilities.SetCapability( Capabilities.TextureFloat ); // Alpha to coverage always 'supported' when MSAA is available // although card may ignore it if it doesn't specifically support A2C _rsCapabilities.SetCapability( Capabilities.AlphaToCoverage ); }
/// <summary> /// /// </summary> /// <param name="primary"></param> protected void InitializeContext( RenderTarget primary ) { // Set main and current context _mainContext = (GLESContext)primary[ "GLCONTEXT" ]; LogManager.Instance.Write( _mainContext == null ? "maincontext NULL" : "maincontext NOT NULL" ); _currentContext = _mainContext; // Set primary context as active if ( _currentContext != null ) _currentContext.SetCurrent(); // intialize GL extensions and check capabilites _glSupport.InitializeExtensions(); LogManager.Instance.Write( "***************************" ); LogManager.Instance.Write( "*** GLES Renderer Started ***" ); LogManager.Instance.Write( "***************************" ); // log hardware info LogManager.Instance.Write( "Vendor: {0}", _glSupport.Vendor ); LogManager.Instance.Write( "Video Board: {0}", _glSupport.VideoCard ); LogManager.Instance.Write( "Version: {0}", _glSupport.Version ); LogManager.Instance.Write( "Extensions supported: " ); foreach ( string ext in _glSupport.Extensions ) { LogManager.Instance.Write( ext ); } // create our special program manager this._gpuProgramManager = new GLESGpuProgramManager(); // query hardware capabilites CheckCaps( primary ); // create a specialized instance, which registers itself as the singleton instance of HardwareBufferManager // use software buffers as a fallback, which operate as regular vertex arrays if ( this._rsCapabilities.HasCapability( Capabilities.VertexBuffer ) ) { hardwareBufferManager = new GLESHardwareBufferManager(); } else { hardwareBufferManager = new GLESDefaultHardwareBufferManager(); } // by creating our texture manager, singleton TextureManager will hold our implementation textureManager = new GLESTextureManager( _glSupport ); _polygonMode = GLFill; this._glInitialized = true; }
protected override void UpdateFromShadow() { if (useShadowBuffer && shadowUpdated && !suppressHardwareUpdate) { var srcData = shadowBuffer.Lock(lockStart, lockSize, BufferLocking.ReadOnly); (Root.Instance.RenderSystem as GLESRenderSystem).BindGLBuffer(GLenum.ArrayBuffer, this._bufferID); //Update whole buffer if possible, otherwise normal if (lockStart == 0 && lockSize == sizeInBytes) { GL.BufferData(GLenum.ArrayBuffer, new IntPtr(sizeInBytes), srcData.Pin(), GLESHardwareBufferManager.GetGLUsage(usage)); GLESConfig.GlCheckError(this); } else { //Ogre FIXME: GPU frequently stalls here - DJR GL.BufferSubData(GLenum.ArrayBuffer, new IntPtr(lockStart), new IntPtr(lockSize), srcData.Pin()); GLESConfig.GlCheckError(this); } shadowBuffer.Unlock(); shadowUpdated = false; } }
public override void WriteData(int offset, int length, BufferBase src, bool discardWholeBuffer) { //Update the shadow buffer if (useShadowBuffer) { var destData = shadowBuffer.Lock(offset, length, discardWholeBuffer ? BufferLocking.Discard : BufferLocking.Normal); src = destData; shadowBuffer.Unlock(); } if (offset == 0 && length == sizeInBytes) { GL.BufferData(GLenum.ArrayBuffer, new IntPtr(sizeInBytes), src.Pin(), GLESHardwareBufferManager.GetGLUsage(usage)); GLESConfig.GlCheckError(this); } else { if (discardWholeBuffer) { GL.BufferData(GLenum.ArrayBuffer, new IntPtr(sizeInBytes), IntPtr.Zero, GLESHardwareBufferManager.GetGLUsage(usage)); GLESConfig.GlCheckError(this); } GL.BufferSubData(GLenum.ArrayBuffer, new IntPtr(offset), new IntPtr(length), src.Pin()); GLESConfig.GlCheckError(this); } }
protected override BufferBase LockImpl(int offset, int length, BufferLocking locking) { if (IsLocked) { throw new AxiomException("Invalid attempt to lock an index buffer that has already been locked."); } BufferBase retPtr; var glBufManager = (HardwareBufferManager.Instance as GLESHardwareBufferManager); //Try to use scratch buffers for smaller buffers if (length < glBufManager.MapBufferThreshold) { retPtr = glBufManager.AllocateScratch(length); if (retPtr != null) { this._lockedToScratch = true; this._scratchOffset = offset; this._scratchSize = length; this._scratchPtr = retPtr; this._scratchUploadOnUnlock = (locking != BufferLocking.ReadOnly); if (locking != BufferLocking.Discard) { //have to read back the data before returning the pointer this.ReadData(offset, length, retPtr); } } } else { throw new AxiomException("Invalid Buffer lockSize"); } if (retPtr == null) { GLenum access = GLenum.Zero; (Root.Instance.RenderSystem as GLESRenderSystem).BindGLBuffer(GLenum.ArrayBuffer, this._bufferID); if (locking == BufferLocking.Discard) { //Discard the buffer GL.BufferData(GLenum.ArrayBuffer, new IntPtr(sizeInBytes), IntPtr.Zero, GLESHardwareBufferManager.GetGLUsage(usage)); GLESConfig.GlCheckError(this); } if ((usage & BufferUsage.WriteOnly) == BufferUsage.WriteOnly) { access = GLenum.WriteOnlyOes; } var pbuffer = GL.Oes.MapBuffer(GLenum.ArrayBuffer, access); GLESConfig.GlCheckError(this); if (pbuffer == IntPtr.Zero) { throw new AxiomException("Vertex Buffer: Out of memory"); } //return offsetted retPtr = BufferBase.Wrap(pbuffer, sizeInBytes) + offset; this._lockedToScratch = false; } isLocked = true; return(retPtr); }