HardwareBuffer.cs :  » Game » RealmForge » Axiom » Graphics » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Game » RealmForge 
RealmForge » Axiom » Graphics » HardwareBuffer.cs
#region LGPL License
/*
Axiom Game Engine Library
Copyright (C) 2003  Axiom Project Team

The overall design, and a majority of the core engine and rendering code 
contained within this library is a derivative of the open source Object Oriented 
Graphics Engine OGRE, which can be found at http://ogre.sourceforge.net.  
Many thanks to the OGRE team for maintaining such a high quality project.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#endregion

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Axiom.Core;

namespace Axiom.Graphics{
    /// <summary>
    ///     Abstract class defining common features of hardware buffers.
    /// </summary>
    /// <remarks>
    ///     A 'hardware buffer' is any area of memory held outside of core system ram,
    ///     and in our case refers mostly to video ram, although in theory this class
    ///     could be used with other memory areas such as sound card memory, custom
    ///     coprocessor memory etc.
    ///     <p/>
    ///     This reflects the fact that memory held outside of main system RAM must 
    ///     be interacted with in a more formal fashion in order to promote
    ///     cooperative and optimal usage of the buffers between the various 
    ///     processing units which manipulate them.
    ///     <p/>
    ///     This abstract class defines the core interface which is common to all
    ///     buffers, whether it be vertex buffers, index buffers, texture memory
    ///     or framebuffer memory etc.
    ///     <p/>
    ///     Buffers have the ability to be 'shadowed' in system memory, this is because
    ///     the kinds of access allowed on hardware buffers is not always as flexible as
    ///     that allowed for areas of system memory - for example it is often either 
    ///     impossible, or extremely undesirable from a performance standpoint to read from
    ///     a hardware buffer; when writing to hardware buffers, you should also write every
    ///     byte and do it sequentially. In situations where this is too restrictive, 
    ///     it is possible to create a hardware, write-only buffer (the most efficient kind) 
    ///     and to back it with a system memory 'shadow' copy which can be read and updated arbitrarily.
    ///     Axiom handles synchronizing this buffer with the real hardware buffer (which should still be
    ///     created with the <see cref="BufferUsage.Dynamic"/> flag if you intend to update it very frequently). 
    ///     Whilst this approach does have it's own costs, such as increased memory overhead, these costs can 
    ///     often be outweighed by the performance benefits of using a more hardware efficient buffer.
    ///     You should look for the 'useShadowBuffer' parameter on the creation methods used to create
    ///     the buffer of the type you require (see <see cref="HardwareBufferManager"/>) to enable this feature.
    ///     <seealso cref="HardwareBufferManager"/>
    /// </remarks>
    public abstract class HardwareBuffer : IDisposable {
        #region Fields
    
        /// <summary>
        ///     Total size (in bytes) of the buffer.
        /// </summary>
        protected int sizeInBytes;
        /// <summary>
        ///     Usage type for this buffer.
        /// </summary>
        protected BufferUsage usage;
        /// <summary>
        ///     Is this buffer currently locked?
        /// </summary>
        protected bool isLocked;
        /// <summary>
        ///     Byte offset into the buffer where the current lock is held.
        /// </summary>
        protected int lockStart;
        /// <summary>
        ///     Total size (int bytes) of locked buffer data.
        /// </summary>
        protected int lockSize;
        /// <summary>
        ///     
        /// </summary>
        protected bool useSystemMemory;
        /// <summary>
        ///     Does this buffer have a shadow buffer?
        /// </summary>
        protected bool useShadowBuffer;
        /// <summary>
        ///     Reference to the sys memory shadow buffer tied to this hardware buffer.
        /// </summary>
        protected HardwareBuffer shadowBuffer;
        /// <summary>
        ///     Flag indicating whether the shadow buffer (if it exists) has been updated.
        /// </summary>
        protected bool shadowUpdated;
        /// <summary>
        ///     Flag indicating whether hardware updates from shadow buffer should be supressed.
        /// </summary>
        protected bool suppressHardwareUpdate;
    /// <summary>
    ///    Unique id for this buffer.
    /// </summary>
    public int ID;
    protected static int nextID;
    
        #endregion Fields

        #region Constructors

        /// <summary>
        ///     Constructor.
        /// </summary>
        /// <param name="usage">Usage type.</param>
        /// <param name="useSystemMemory"></param>
        /// <param name="useShadowBuffer">Use a software shadow buffer?</param>
        internal HardwareBuffer(BufferUsage usage, bool useSystemMemory, bool useShadowBuffer) {
            this.usage = usage;
            this.useSystemMemory = useSystemMemory;
            this.useShadowBuffer = useShadowBuffer;
      ID = nextID++;
        }

        #endregion
      
        #region Methods

        public BufferStream LockStream(BufferLocking locking) {
            return new BufferStream(this, Lock(locking));
        }

        /// <summary>
        ///    Convenient overload to allow locking the entire buffer with only having
        ///    to supply the locking type.
        /// </summary>
        /// <param name="locking">Locking options.</param>
        /// <returns>IntPtr to the beginning of the locked region of buffer memory.</returns>
        public IntPtr Lock(BufferLocking locking) {
            return Lock(0, sizeInBytes, locking);
        }

        /// <summary>
        ///    Used to lock a vertex buffer in hardware memory in order to make modifications.
        /// </summary>
        /// <param name="offset">Starting index in the buffer to lock.</param>
        /// <param name="length">Nunber of bytes to lock after the offset.</param>
        /// <param name="locking">Specifies how to lock the buffer.</param>
        /// <returns>An array of the <code>System.Type</code> associated with this VertexBuffer.</returns>
        public virtual IntPtr Lock(int offset, int length, BufferLocking locking) {
            Debug.Assert(!isLocked, "Cannot lock this buffer because it is already locked.");

            IntPtr data = IntPtr.Zero;

            if(useShadowBuffer) {
                if(locking != BufferLocking.ReadOnly) {
                    // we have to assume a read / write lock so we use the shadow buffer
                    // and tag for sync on Unlock()
                    shadowUpdated = true;
                }

                data = shadowBuffer.Lock(offset, length, locking);
            }
            else {
                // lock the real deal and flag it as locked
                data = this.LockImpl(offset, length, locking);
                isLocked = true;
            }

            lockStart = offset;
            lockSize = length;

            return data;
        }

        /// <summary>
        ///     Internal implementation of Lock, which will be overridden by subclasses to provide
        ///     the core locking functionality.
        /// </summary>
        /// <param name="offset">Offset into the buffer (in bytes) to lock.</param>
        /// <param name="length">Length of the portion of the buffer (int bytes) to lock.</param>
        /// <param name="locking">Locking type.</param>
        /// <returns>IntPtr to the beginning of the locked portion of the buffer.</returns>
        protected abstract IntPtr LockImpl(int offset, int length, BufferLocking locking);

        /// <summary>
        ///    Must be called after a call to <code>Lock</code>.  Unlocks the vertex buffer in the hardware
        ///    memory.
        /// </summary>
        public virtual void Unlock() {
            Debug.Assert(this.IsLocked, "Cannot unlock this buffer if it isn't locked to begin with.");

            if(useShadowBuffer && shadowBuffer.IsLocked) {
                shadowBuffer.Unlock();

                // potentially update the real buffer from the shadow buffer
                UpdateFromShadow();
            }
            else {
                // unlock the real deal
                this.UnlockImpl();

                isLocked = false;
            }
        }

        /// <summary>
        ///     Abstract implementation of <see cref="Unlock"/>.
        /// </summary>
        public abstract void UnlockImpl();

        /// <summary>
        ///     Updates the real buffer from the shadow buffer, if required.
        /// </summary>
        protected void UpdateFromShadow() {
            if(useShadowBuffer && shadowUpdated && !suppressHardwareUpdate) {
                // do this manually to avoid locking problems
                IntPtr src = shadowBuffer.LockImpl(lockStart, lockSize, BufferLocking.ReadOnly);

                // Lock with discard if the whole buffer was locked, otherwise normal
                BufferLocking locking = 
                    (lockStart == 0 && lockSize == sizeInBytes) ? BufferLocking.Discard : BufferLocking.Normal;

                IntPtr dest = this.LockImpl(lockStart, lockSize, locking);

                // copy the data in directly
                Memory.Copy(src, dest, lockSize);

                // unlock both buffers to commit the write
                this.UnlockImpl();
                shadowBuffer.UnlockImpl();

                shadowUpdated = false;
            }
        }

        /// <summary>
        ///     Reads data from the buffer and places it in the memory pointed to by 'dest'.
        /// </summary>
        /// <param name="offset">The byte offset from the start of the buffer to read.</param>
        /// <param name="length">The size of the area to read, in bytes.</param>
        /// <param name="dest">
        ///     The area of memory in which to place the data, must be large enough to 
        ///     accommodate the data!
        /// </param>
        public abstract void ReadData(int offset, int length, IntPtr dest);

        /// <summary>
        ///     Writes data to the buffer from an area of system memory; note that you must
        ///     ensure that your buffer is big enough.
        /// </summary>
        /// <param name="offset">The byte offset from the start of the buffer to start writing.</param>
        /// <param name="length">The size of the data to write to, in bytes.</param>
        /// <param name="src">The source of the data to be written.</param>
        public void WriteData(int offset, int length, IntPtr src) {
            WriteData(offset, length, src, false);
        }

        /// <summary>
        ///     Writes data to the buffer from an area of system memory; note that you must
        ///     ensure that your buffer is big enough.
        /// </summary>
        /// <param name="offset">The byte offset from the start of the buffer to start writing.</param>
        /// <param name="length">The size of the data to write to, in bytes.</param>
        /// <param name="src">The source of the data to be written.</param>
        /// <param name="discardWholeBuffer">
        ///     If true, this allows the driver to discard the entire buffer when writing,
        ///     such that DMA stalls can be avoided; use if you can.
        /// </param>
        public abstract void WriteData(int offset, int length, IntPtr src, bool discardWholeBuffer);

        /// <summary>
        ///    Allows passing in a managed array of data to fill the vertex buffer.
        /// </summary>
        /// <param name="offset">The byte offset from the start of the buffer to start writing.</param>
        /// <param name="length">The size of the data to write to, in bytes.</param>
        /// <param name="data">
        ///     Array of data to blast into the buffer.  This can be an array of custom structs, that hold
        ///     position, normal, etc data.  The size of the struct *must* match the vertex size of the buffer,
        ///     so use with care.
        /// </param>
        public void WriteData(int offset, int length, System.Array data) {
            IntPtr dataPtr = Marshal.UnsafeAddrOfPinnedArrayElement(data, 0);

            WriteData(offset, length, dataPtr);
        }

        /// <summary>
        ///    Allows passing in a managed array of data to fill the vertex buffer.
        /// </summary>
        /// <param name="offset">The byte offset from the start of the buffer to start writing.</param>
        /// <param name="length">The size of the data to write to, in bytes.</param>
        /// <param name="data">
        ///     Array of data to blast into the buffer.  This can be an array of custom structs, that hold
        ///     position, normal, etc data.  The size of the struct *must* match the vertex size of the buffer,
        ///     so use with care.
        /// </param>
        /// <param name="discardWholeBuffer">
        ///     If true, this allows the driver to discard the entire buffer when writing,
        ///     such that DMA stalls can be avoided; use if you can.
        /// </param>
        public void WriteData(int offset, int length, System.Array data, bool discardWholeBuffer) {
            IntPtr dataPtr = Marshal.UnsafeAddrOfPinnedArrayElement(data, 0);

            WriteData(offset, length, dataPtr, discardWholeBuffer);
        }

        /// <summary>
        ///     Copy data from another buffer into this one.
        /// </summary>
        /// <param name="srcBuffer">The buffer from which to read the copied data.</param>
        /// <param name="srcOffset">Offset in the source buffer at which to start reading.</param>
        /// <param name="destOffset">Offset in the destination buffer to start writing.</param>
        /// <param name="length">Length of the data to copy, in bytes.</param>
        public virtual void CopyData(HardwareBuffer srcBuffer, int srcOffset, int destOffset, int length) {
            // call the overloaded method
            CopyData(srcBuffer, srcOffset, destOffset, length, false);
        }

        /// <summary>
        ///     Copy data from another buffer into this one.
        /// </summary>
        /// <param name="srcBuffer">The buffer from which to read the copied data.</param>
        /// <param name="srcOffset">Offset in the source buffer at which to start reading.</param>
        /// <param name="destOffset">Offset in the destination buffer to start writing.</param>
        /// <param name="length">Length of the data to copy, in bytes.</param>
        /// <param name="discardWholeBuffer">If true, will discard the entire contents of this buffer before copying.</param>
        public virtual void CopyData(HardwareBuffer srcBuffer, int srcOffset, int destOffset, int length, bool discardWholeBuffer) {
            // lock the source buffer
            IntPtr srcData = srcBuffer.Lock(srcOffset, length, BufferLocking.ReadOnly);

            // write the data to this buffer
            this.WriteData(destOffset, length, srcData, discardWholeBuffer);

            // unlock the source buffer
            srcBuffer.Unlock();
        }

        /// <summary>
        ///     Pass true to suppress hardware upload of shadow buffer changes.
        /// </summary>
        /// <param name="suppress">If true, shadow buffer updates won't be uploaded to hardware.</param>
        public void SuppressHardwareUpdate(bool suppress) {
            suppressHardwareUpdate = suppress;

      // if disabling future shadow updates, then update from what is current in the buffer now
      // this is needed for shadow volumes
      if(!suppress) {
        UpdateFromShadow();
      }
        }

        #endregion

        #region Properties

        /// <summary>
        ///    Gets whether or not this buffer is currently locked.
        /// </summary>
        public bool IsLocked { 
            get { 
                return isLocked || (useShadowBuffer && shadowBuffer.IsLocked); 
            } 
        }

        /// <summary>
        ///    Gets whether this buffer is held in system memory.
        /// </summary>
        public bool IsSystemMemory {
            get { 
                return useSystemMemory; 
            }
        }

        /// <summary>
        ///    Gets the size (in bytes) for this buffer.
        /// </summary>
        public int Size { 
            get { 
                return sizeInBytes; 
            } 
        }

        /// <summary>
        ///    Gets the usage of this buffer.
        /// </summary>
        public BufferUsage Usage { 
            get { 
                return usage; 
            } 
        }

        /// <summary>
        ///     Gets a bool that specifies whether this buffer has a software shadow buffer.
        /// </summary>
        public bool HasShadowBuffer {
            get {
                return useShadowBuffer;
            }
        }

        #endregion

        #region IDisposable Implementation

        /// <summary>
        ///     Called to destroy resources used by this hardware buffer.
        /// </summary>
        public virtual void Dispose() {
            // do nothing by default
        }

        #endregion IDisposable Implementation
    }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.