diff --git a/code/nel/src/3d/driver/opengl3/driver_opengl.h b/code/nel/src/3d/driver/opengl3/driver_opengl.h index c988497da..7b4d1cfb8 100644 --- a/code/nel/src/3d/driver/opengl3/driver_opengl.h +++ b/code/nel/src/3d/driver/opengl3/driver_opengl.h @@ -689,7 +689,7 @@ public: #endif private: - virtual class IVertexBufferGL3 *createVertexBufferGL(uint size, uint numVertices, CVertexBuffer::TPreferredMemory vbType, CVertexBuffer *vb); + virtual class IVertexBufferGL3 *createVertexBufferGL(uint size, uint numVertices, CVertexBuffer::TPreferredMemory preferred, CVertexBuffer *vb); friend class CTextureDrvInfosGL3; friend class CVertexProgamDrvInfosGL3; @@ -1126,6 +1126,7 @@ private: // @{ CPtrSet _VertexBufferGLSet; friend class CVertexBufferGL3; + friend class CVertexBufferAMDPinned; friend class CVBDrvInfosGL3; // The VertexBufferHardGL activated. diff --git a/code/nel/src/3d/driver/opengl3/driver_opengl_extension.cpp b/code/nel/src/3d/driver/opengl3/driver_opengl_extension.cpp index 60685ca3f..5c2ee8e73 100644 --- a/code/nel/src/3d/driver/opengl3/driver_opengl_extension.cpp +++ b/code/nel/src/3d/driver/opengl3/driver_opengl_extension.cpp @@ -539,6 +539,13 @@ static bool setupARBSeparateShaderObjects(std::vector &glext) return true; } +static bool setupAMDPinnedMemory(std::vector &glext) +{ + CHECK_EXT_2("GL_AMD_pinned_memory"); + + return true; +} + // *************************************************************************** // Extension Check. bool registerGlExtensions(CGlExtensions &ext) @@ -611,6 +618,9 @@ bool registerGlExtensions(CGlExtensions &ext) glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &ext.EXTTextureFilterAnisotropicMaximum); } + // Check GL_AMD_pinned_memory + ext.AMDPinnedMemory = setupAMDPinnedMemory(glext); + // Get the maximum fragment texture unites glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &ext.MaxFragmentTextureImageUnits); if (ext.MaxFragmentTextureImageUnits < 8) diff --git a/code/nel/src/3d/driver/opengl3/driver_opengl_extension.h b/code/nel/src/3d/driver/opengl3/driver_opengl_extension.h index 8578c7a12..147b123f8 100644 --- a/code/nel/src/3d/driver/opengl3/driver_opengl_extension.h +++ b/code/nel/src/3d/driver/opengl3/driver_opengl_extension.h @@ -44,6 +44,7 @@ struct CGlExtensions bool EXTTextureCompressionS3TC; bool EXTTextureFilterAnisotropic; float EXTTextureFilterAnisotropicMaximum; + bool AMDPinnedMemory; // Required Extensions. (old) bool ARBMultiTexture; @@ -70,6 +71,7 @@ public: EXTTextureCompressionS3TC = false; EXTTextureFilterAnisotropic = false; EXTTextureFilterAnisotropicMaximum = 0.f; + AMDPinnedMemory = false; ARBMultiTexture= false; @@ -102,6 +104,9 @@ public: result += "fragment texture units(*) = "; result += NLMISC::toString(MaxFragmentTextureImageUnits); + result += "\n Buffers: "; + result += AMDPinnedMemory ? "AMDPinnedMemory " : ""; + #ifdef NL_OS_WINDOWS result += "\n WindowsGL: "; result += WGLARBPBuffer ? "WGLARBPBuffer " : ""; diff --git a/code/nel/src/3d/driver/opengl3/driver_opengl_vertex.cpp b/code/nel/src/3d/driver/opengl3/driver_opengl_vertex.cpp index c32797a91..6e9487eea 100644 --- a/code/nel/src/3d/driver/opengl3/driver_opengl_vertex.cpp +++ b/code/nel/src/3d/driver/opengl3/driver_opengl_vertex.cpp @@ -221,7 +221,7 @@ bool CDriverGL3::activeIndexBuffer(CIndexBuffer& IB) bool CDriverGL3::supportVolatileVertexBuffer() const { H_AUTO_OGL(CDriverGL3_supportVolatileVertexBuffer) - return true; // TODO VERTEXBUFFER PINNED + return true; // Supported by GL_MAP_INVALIDATE_BUFFER_BIT } @@ -230,7 +230,7 @@ bool CDriverGL3::supportVolatileVertexBuffer() const bool CDriverGL3::slowUnlockVertexBufferHard() const { H_AUTO_OGL(CDriverGL3_slowUnlockVertexBufferHard) - return false; + return false; // Always false gives slightly better performance on AMD. Might make difference with _Extensions.AMDPinnedMemory } @@ -241,6 +241,7 @@ uint CDriverGL3::getMaxVerticesByVertexBufferHard() const return std::numeric_limits::max(); } +// TODO: Move this to CVertexBufferGL3 GLenum CDriverGL3::vertexBufferUsageGL3(CVertexBuffer::TPreferredMemory usage) { switch (usage) @@ -260,19 +261,25 @@ GLenum CDriverGL3::vertexBufferUsageGL3(CVertexBuffer::TPreferredMemory usage) } // *************************************************************************** -IVertexBufferGL3 *CDriverGL3::createVertexBufferGL(uint size, uint numVertices, CVertexBuffer::TPreferredMemory vbType, CVertexBuffer *vb) +IVertexBufferGL3 *CDriverGL3::createVertexBufferGL(uint size, uint numVertices, CVertexBuffer::TPreferredMemory preferred, CVertexBuffer *vb) { H_AUTO_OGL(CDriverGL3_createVertexBufferGL) - // Create a Vertex Buffer - GLuint vertexBufferID; - nglGenBuffers(1, &vertexBufferID); - _DriverGLStates.forceBindARBVertexBuffer(vertexBufferID); - nglBufferData(GL_ARRAY_BUFFER, size, NULL, vertexBufferUsageGL3(vbType)); - CVertexBufferGL3 *newVbHard = new CVertexBufferGL3(this, vb); - newVbHard->initGL(vertexBufferID, vbType); - _DriverGLStates.forceBindARBVertexBuffer(0); - return _VertexBufferGLSet.insert(newVbHard); + IVertexBufferGL3 *result; + + if (_Extensions.AMDPinnedMemory && ( + preferred == CVertexBuffer::RAMPreferred + // || preferred == CVertexBuffer::AGPPreferred + )) + { + result = new CVertexBufferAMDPinned(this, size, numVertices, preferred, vb); + } + else + { + result = new CVertexBufferGL3(this, size, numVertices, preferred, vb); + } + + return _VertexBufferGLSet.insert(result); } // ******************************************************************** diff --git a/code/nel/src/3d/driver/opengl3/driver_opengl_vertex_buffer.cpp b/code/nel/src/3d/driver/opengl3/driver_opengl_vertex_buffer.cpp index cb6c7f43a..6630f5a69 100644 --- a/code/nel/src/3d/driver/opengl3/driver_opengl_vertex_buffer.cpp +++ b/code/nel/src/3d/driver/opengl3/driver_opengl_vertex_buffer.cpp @@ -31,6 +31,9 @@ namespace NLDRIVERGL3 { #endif // *************************************************************************** +// *************************************************************************** +// *************************************************************************** + IVertexBufferGL3::IVertexBufferGL3(CDriverGL3 *drv, CVertexBuffer *vb, TVBType vbType) : VB(vb), VBType(vbType), m_Driver(drv), m_Invalid(false) { @@ -38,21 +41,39 @@ IVertexBufferGL3::IVertexBufferGL3(CDriverGL3 *drv, CVertexBuffer *vb, TVBType v } // *************************************************************************** + IVertexBufferGL3::~IVertexBufferGL3() { H_AUTO_OGL(IVertexBufferGL_IVertexBufferGLDtor) } // *************************************************************************** -CVertexBufferGL3::CVertexBufferGL3(CDriverGL3 *drv, CVertexBuffer *vb) +// *************************************************************************** +// *************************************************************************** + +CVertexBufferGL3::CVertexBufferGL3(CDriverGL3 *drv, uint size, uint numVertices, CVertexBuffer::TPreferredMemory preferred, CVertexBuffer *vb) : IVertexBufferGL3(drv, vb, IVertexBufferGL3::GL3), m_VertexPtr(NULL), m_VertexObjectId(0) { H_AUTO_OGL(CVertexBufferGLARB_CVertexBufferGLARB) + + // Create id and bind + GLuint vertexBufferID; + nglGenBuffers(1, &vertexBufferID); + drv->_DriverGLStates.forceBindARBVertexBuffer(vertexBufferID); + + // Initialize + nglBufferData(GL_ARRAY_BUFFER, size, NULL, drv->vertexBufferUsageGL3(preferred)); + m_VertexObjectId = vertexBufferID; + m_MemType = preferred; + + // Unbind + drv->_DriverGLStates.forceBindARBVertexBuffer(0); } // *************************************************************************** + CVertexBufferGL3::~CVertexBufferGL3() { H_AUTO_OGL(CVertexBufferGLARB_CVertexBufferGLARBDtor) @@ -83,6 +104,7 @@ CVertexBufferGL3::~CVertexBufferGL3() } // *************************************************************************** + void *CVertexBufferGL3::lock() { H_AUTO_OGL(CVertexBufferGLARB_lock); @@ -184,6 +206,7 @@ void *CVertexBufferGL3::lock() } // *************************************************************************** + void CVertexBufferGL3::unlock() { H_AUTO_OGL(CVertexBufferGLARB_unlock); @@ -228,6 +251,7 @@ void CVertexBufferGL3::unlock() } // *************************************************************************** + void *CVertexBufferGL3::getPointer() { H_AUTO_OGL(CVertexBufferGLARB_getPointer) @@ -235,6 +259,7 @@ void *CVertexBufferGL3::getPointer() } // *************************************************************************** + void CVertexBufferGL3::unlock(uint /* startVert */,uint /* endVert */) { H_AUTO_OGL(CVertexBufferGLARB_unlock) @@ -242,38 +267,29 @@ void CVertexBufferGL3::unlock(uint /* startVert */,uint /* endVert */) } // *************************************************************************** + void CVertexBufferGL3::enable() { H_AUTO_OGL(CVertexBufferGLARB_enable) if (m_Driver->_CurrentVertexBufferGL != this) { - /* nlassert(_VertexArrayRange); - _VertexArrayRange->enable(); */ m_Driver->_CurrentVertexBufferGL= this; } } // *************************************************************************** + void CVertexBufferGL3::disable() { H_AUTO_OGL(CVertexBufferGLARB_disable) if (m_Driver->_CurrentVertexBufferGL != NULL) { - /* nlassert(_VertexArrayRange); - _VertexArrayRange->disable(); */ m_Driver->_CurrentVertexBufferGL= NULL; } } // *************************************************************************** -void CVertexBufferGL3::initGL(uint vertexObjectID, CVertexBuffer::TPreferredMemory memType) -{ - H_AUTO_OGL(CVertexBufferGLARB_initGL) - m_VertexObjectId = vertexObjectID; - m_MemType = memType; -} -// *************************************************************************** void CVertexBufferGL3::setupVBInfos(CVertexBufferInfo &vb) { H_AUTO_OGL(CVertexBufferGLARB_setupVBInfos) @@ -281,6 +297,7 @@ void CVertexBufferGL3::setupVBInfos(CVertexBufferInfo &vb) } // *************************************************************************** + void CVertexBufferGL3::invalidate() { H_AUTO_OGL(CVertexBufferGLARB_invalidate) @@ -295,6 +312,201 @@ void CVertexBufferGL3::invalidate() m_IteratorInLostVBList = m_Driver->_LostVBList.begin(); } +// *************************************************************************** +// *************************************************************************** +// *************************************************************************** + +CVertexBufferAMDPinned::CVertexBufferAMDPinned(CDriverGL3 *drv, uint size, uint numVertices, CVertexBuffer::TPreferredMemory preferred, CVertexBuffer *vb) + : IVertexBufferGL3(drv, vb, IVertexBufferGL3::AMDPinned), + m_MemType(preferred), + m_VertexPtr(NULL), + m_VertexObjectId(0) +{ + H_AUTO_OGL(CVertexBufferAMDPinned_CVertexBufferAMDPinned) + + // Create id and bind + GLuint vertexBufferID; + nglGenBuffers(1, &vertexBufferID); + nglBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, vertexBufferID); + + // Initialize + // Align allocated to page size, which is assumed to be 4K + m_VertexPtrAllocated = new char[size + 4096]; + uintptr_t addr = (uintptr_t)m_VertexPtrAllocated; + addr = (addr + 4095) & (~0xfff); + m_VertexPtrAligned = (void *)addr; + nglBufferData(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, size, m_VertexPtrAligned, drv->vertexBufferUsageGL3(preferred)); + if (glGetError() == GL_INVALID_OPERATION) + { + nlerror("Failed to pin memory"); + nglDeleteBuffers(1, &vertexBufferID); + vertexBufferID = 0; + } + m_VertexObjectId = vertexBufferID; + + // Unbind + nglBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, 0); +} + +// *************************************************************************** + +CVertexBufferAMDPinned::~CVertexBufferAMDPinned() +{ + H_AUTO_OGL(CVertexBufferAMDPinned_CVertexBufferAMDPinnedDtor) + if (m_Driver && m_VertexObjectId) + { + if (m_Driver->_DriverGLStates.getCurrBoundARBVertexBuffer() == m_VertexObjectId) + { + m_Driver->_DriverGLStates.forceBindARBVertexBuffer(0); + } + } + if (m_VertexObjectId) + { + GLuint id = (GLuint)m_VertexObjectId; + nlassert(nglIsBuffer(id)); + nglDeleteBuffers(1, &id); + } + delete m_VertexPtrAllocated; + m_VertexPtrAllocated = NULL; + m_VertexPtrAligned = NULL; + nlassert(m_VertexPtr == NULL); +} + +// *************************************************************************** + +void *CVertexBufferAMDPinned::lock() +{ + H_AUTO_OGL(CVertexBufferAMDPinned_lock); + + if (m_VertexPtr) // Already locked... + return m_VertexPtr; + + if (!m_VertexObjectId) // Failed to pin + return m_VertexPtrAligned; + + // Profiling + TTicks beforeLock = 0; + if (m_Driver->_VBHardProfiling) + { + beforeLock= CTime::getPerformanceTime(); + } + + // Lock + m_Driver->_DriverGLStates.bindARBVertexBuffer(m_VertexObjectId); + switch (m_MemType) + { + case CVertexBuffer::AGPVolatile: + case CVertexBuffer::RAMVolatile: + nlerror("Volatile currently not supported by pinned memory, this would require a re-allocating RAM, and thus require a fast allocation mechanism"); + m_VertexPtr = NULL; + break; + case CVertexBuffer::RAMPreferred: + m_VertexPtr = nglMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE); + break; + default: + m_VertexPtr = nglMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); + break; + } + m_Driver->_DriverGLStates.forceBindARBVertexBuffer(0); + nlassert(m_VertexPtr); + nlassert(m_VertexPtr == m_VertexPtrAligned); + + // Profiling + if (m_Driver->_VBHardProfiling) + { + TTicks afterLock; + afterLock = CTime::getPerformanceTime(); + m_Driver->appendVBHardLockProfile(afterLock - beforeLock, VB); + } + + return m_VertexPtr; +} + +// *************************************************************************** + +void CVertexBufferAMDPinned::unlock() +{ + H_AUTO_OGL(CVertexBufferAMDPinned_unlock); + + m_VertexPtr = NULL; + + if (!m_VertexObjectId) + return; + + // Profiling + TTicks beforeLock = 0; + if (m_Driver->_VBHardProfiling) + { + beforeLock = CTime::getPerformanceTime(); + } + + // Unlock + m_Driver->_DriverGLStates.bindARBVertexBuffer(m_VertexObjectId); + nglUnmapBuffer(GL_ARRAY_BUFFER); + m_Driver->_DriverGLStates.forceBindARBVertexBuffer(0); + + // Profiling + if (m_Driver->_VBHardProfiling) + { + TTicks afterLock; + afterLock= CTime::getPerformanceTime(); + m_Driver->appendVBHardLockProfile(afterLock-beforeLock, VB); + } +} + +// *************************************************************************** + +void *CVertexBufferAMDPinned::getPointer() +{ + H_AUTO_OGL(CVertexBufferAMDPinned_getPointer) + + return m_VertexPtr; +} + +// *************************************************************************** + +void CVertexBufferAMDPinned::unlock(uint /* startVert */,uint /* endVert */) +{ + H_AUTO_OGL(CVertexBufferAMDPinned_unlock) + + unlock(); +} + +// *************************************************************************** + +void CVertexBufferAMDPinned::enable() +{ + H_AUTO_OGL(CVertexBufferAMDPinned_enable) + if (m_Driver->_CurrentVertexBufferGL != this) + { + m_Driver->_CurrentVertexBufferGL = this; + } +} + +// *************************************************************************** + +void CVertexBufferAMDPinned::disable() +{ + H_AUTO_OGL(CVertexBufferAMDPinned_disable) + if (m_Driver->_CurrentVertexBufferGL != NULL) + { + m_Driver->_CurrentVertexBufferGL = NULL; + } +} + +// *************************************************************************** + +void CVertexBufferAMDPinned::setupVBInfos(CVertexBufferInfo &vb) +{ + H_AUTO_OGL(CVertexBufferAMDPinned_setupVBInfos) + + vb.VertexObjectId = m_VertexObjectId; +} + +// *************************************************************************** +// *************************************************************************** +// *************************************************************************** + #ifdef NL_STATIC } // NLDRIVERGL3 #endif diff --git a/code/nel/src/3d/driver/opengl3/driver_opengl_vertex_buffer.h b/code/nel/src/3d/driver/opengl3/driver_opengl_vertex_buffer.h index 38275f534..523f47909 100644 --- a/code/nel/src/3d/driver/opengl3/driver_opengl_vertex_buffer.h +++ b/code/nel/src/3d/driver/opengl3/driver_opengl_vertex_buffer.h @@ -33,7 +33,7 @@ class CVertexBufferGL3; class IVertexBufferGL3 { public: - enum TVBType { GL3 }; + enum TVBType { GL3, AMDPinned }; IVertexBufferGL3(CDriverGL3 *drv, CVertexBuffer *vb, TVBType vbType); virtual ~IVertexBufferGL3(); @@ -62,7 +62,7 @@ protected: class CVertexBufferGL3 : public IVertexBufferGL3 { public: - CVertexBufferGL3(CDriverGL3 *drv, CVertexBuffer *vb); + CVertexBufferGL3(CDriverGL3 *drv, uint size, uint numVertices, CVertexBuffer::TPreferredMemory preferred, CVertexBuffer *vb); virtual ~CVertexBufferGL3(); /// \name Implementation @@ -76,9 +76,6 @@ public: virtual void setupVBInfos(CVertexBufferInfo &vb); // @} - /// Setup ptrs allocated by createVBHard() - void initGL(uint vertexObjectID, CVertexBuffer::TPreferredMemory memType); - /// Invalidate the buffer (when it is lost, or when a lock fails) void invalidate(); @@ -96,6 +93,31 @@ private: uint m_VertexObjectId; }; +class CVertexBufferAMDPinned : public IVertexBufferGL3 +{ +public: + CVertexBufferAMDPinned(CDriverGL3 *drv, uint size, uint numVertices, CVertexBuffer::TPreferredMemory preferred, CVertexBuffer *vb); + virtual ~CVertexBufferAMDPinned(); + + /// \name Implementation + // @{ + virtual void *lock(); + virtual void unlock(); + virtual void unlock(uint startVert, uint endVert); + virtual void *getPointer(); + virtual void enable(); + virtual void disable(); + virtual void setupVBInfos(CVertexBufferInfo &vb); + // @} + +private: + CVertexBuffer::TPreferredMemory m_MemType; + void *m_VertexPtrAllocated; + void *m_VertexPtrAligned; + void *m_VertexPtr; + uint m_VertexObjectId; +}; + #ifdef NL_STATIC } // NLDRIVERGL3 #endif