From dd08fd2e7d8ffb10a4d72e2c777815bc2eae7d35 Mon Sep 17 00:00:00 2001 From: LuisAntonRebollo Date: Sat, 8 Nov 2014 17:41:17 +0100 Subject: [PATCH] Add OpenGL support. --- Engine/source/gfx/gfxDevice.cpp | 2 + Engine/source/gfx/gfxStateBlock.h | 5 + Engine/source/gfx/gl/gfxGLAppleFence.h | 2 +- Engine/source/gfx/gl/gfxGLCardProfiler.cpp | 14 +- .../gfx/gl/gfxGLCircularVolatileBuffer.h | 289 +++++++++++ Engine/source/gfx/gl/gfxGLCubemap.cpp | 21 +- Engine/source/gfx/gl/gfxGLDevice.cpp | 489 ++++++++++++------ Engine/source/gfx/gl/gfxGLDevice.h | 57 +- Engine/source/gfx/gl/gfxGLDevice.mac.mm | 16 +- Engine/source/gfx/gl/gfxGLDeviceProfiler.cpp | 133 +++++ Engine/source/gfx/gl/gfxGLEnumTranslate.cpp | 157 ++++-- Engine/source/gfx/gl/gfxGLEnumTranslate.h | 1 + Engine/source/gfx/gl/gfxGLOcclusionQuery.cpp | 12 +- Engine/source/gfx/gl/gfxGLPrimitiveBuffer.cpp | 123 ++++- Engine/source/gfx/gl/gfxGLPrimitiveBuffer.h | 11 +- Engine/source/gfx/gl/gfxGLShader.cpp | 185 ++++++- Engine/source/gfx/gl/gfxGLShader.h | 3 +- Engine/source/gfx/gl/gfxGLStateBlock.cpp | 103 ++-- Engine/source/gfx/gl/gfxGLStateBlock.h | 6 + Engine/source/gfx/gl/gfxGLStateCache.h | 133 +++++ Engine/source/gfx/gl/gfxGLTextureManager.cpp | 145 ++++-- Engine/source/gfx/gl/gfxGLTextureManager.h | 2 +- Engine/source/gfx/gl/gfxGLTextureObject.cpp | 177 +++++-- Engine/source/gfx/gl/gfxGLTextureObject.h | 20 +- Engine/source/gfx/gl/gfxGLTextureTarget.cpp | 225 ++++---- Engine/source/gfx/gl/gfxGLTextureTarget.h | 6 +- Engine/source/gfx/gl/gfxGLUtils.h | 155 +++++- .../source/gfx/gl/gfxGLVertexAttribLocation.h | 30 ++ Engine/source/gfx/gl/gfxGLVertexBuffer.cpp | 180 ++++--- Engine/source/gfx/gl/gfxGLVertexBuffer.h | 27 +- Engine/source/gfx/gl/gfxGLVertexDecl.cpp | 212 ++++++++ Engine/source/gfx/gl/gfxGLVertexDecl.h | 39 ++ Engine/source/gfx/gl/gfxGLWindowTarget.cpp | 98 +++- Engine/source/gfx/gl/gfxGLWindowTarget.h | 5 + Engine/source/gfx/gl/sdl/gfxGLDevice.sdl.cpp | 225 ++++++++ Engine/source/gfx/gl/tGL/tGL.cpp | 41 ++ Engine/source/gfx/gl/tGL/tGL.h | 30 ++ Engine/source/gfx/gl/tGL/tWGL.h | 38 ++ Engine/source/gfx/gl/tGL/tXGL.h | 38 ++ .../gl/util/glFrameAllocatorLockableHelper.h | 53 ++ .../gfx/gl/{ => win32}/gfxGLDevice.win.cpp | 133 ++--- .../advancedLightBufferConditioner.cpp | 2 +- .../advanced/advancedLightManager.cpp | 5 + Engine/source/materials/materialManager.cpp | 11 +- Engine/source/platform/platformGL.h | 17 + Engine/source/platformWin32/WinPlatformGL.cpp | 11 + .../renderInstance/renderPrePassMgr.cpp | 4 +- Engine/source/shaderGen/GLSL/bumpGLSL.cpp | 1 + .../shaderGen/GLSL/shaderFeatureGLSL.cpp | 5 +- Engine/source/shaderGen/langElement.cpp | 5 +- .../source/terrain/hlsl/terrFeatureHLSL.cpp | 24 +- .../source/windowManager/win32/win32Window.h | 2 + Templates/Empty/game/core/main.cs | 4 +- Templates/Full/game/core/main.cs | 4 +- Tools/CMake/torque3d.cmake | 23 + 55 files changed, 2957 insertions(+), 802 deletions(-) create mode 100644 Engine/source/gfx/gl/gfxGLCircularVolatileBuffer.h create mode 100644 Engine/source/gfx/gl/gfxGLDeviceProfiler.cpp create mode 100644 Engine/source/gfx/gl/gfxGLStateCache.h create mode 100644 Engine/source/gfx/gl/gfxGLVertexAttribLocation.h create mode 100644 Engine/source/gfx/gl/gfxGLVertexDecl.cpp create mode 100644 Engine/source/gfx/gl/gfxGLVertexDecl.h create mode 100644 Engine/source/gfx/gl/sdl/gfxGLDevice.sdl.cpp create mode 100644 Engine/source/gfx/gl/tGL/tGL.cpp create mode 100644 Engine/source/gfx/gl/tGL/tGL.h create mode 100644 Engine/source/gfx/gl/tGL/tWGL.h create mode 100644 Engine/source/gfx/gl/tGL/tXGL.h create mode 100644 Engine/source/gfx/gl/util/glFrameAllocatorLockableHelper.h rename Engine/source/gfx/gl/{ => win32}/gfxGLDevice.win.cpp (77%) create mode 100644 Engine/source/platform/platformGL.h create mode 100644 Engine/source/platformWin32/WinPlatformGL.cpp diff --git a/Engine/source/gfx/gfxDevice.cpp b/Engine/source/gfx/gfxDevice.cpp index d5195d880..47f528d94 100644 --- a/Engine/source/gfx/gfxDevice.cpp +++ b/Engine/source/gfx/gfxDevice.cpp @@ -267,6 +267,8 @@ GFXDevice::~GFXDevice() mNewCubemap[i] = NULL; } + mCurrentRT = NULL; + // Release all the unreferenced textures in the cache. mTextureManager->cleanupCache(); diff --git a/Engine/source/gfx/gfxStateBlock.h b/Engine/source/gfx/gfxStateBlock.h index f807f221f..a083c5cc3 100644 --- a/Engine/source/gfx/gfxStateBlock.h +++ b/Engine/source/gfx/gfxStateBlock.h @@ -89,6 +89,11 @@ struct GFXSamplerStateDesc /// Returns an modulate, clamp, and point sampled state. static GFXSamplerStateDesc getClampPoint(); + + bool operator==(const GFXSamplerStateDesc &b) const + { + return !dMemcmp(this, &b, sizeof(GFXSamplerStateDesc)); + } }; /// GFXStateBlockDesc defines a render state, which is then used to create a GFXStateBlock instance. diff --git a/Engine/source/gfx/gl/gfxGLAppleFence.h b/Engine/source/gfx/gl/gfxGLAppleFence.h index 5a2029197..6968e7fc6 100644 --- a/Engine/source/gfx/gl/gfxGLAppleFence.h +++ b/Engine/source/gfx/gl/gfxGLAppleFence.h @@ -24,7 +24,7 @@ #define _GFXGLAPPLEFENCE_H_ #include "gfx/gfxFence.h" -#include "gfx/gl/ggl/ggl.h" +#include "gfx/gl/tGL/tGL.h" class GFXGLAppleFence : public GFXFence { diff --git a/Engine/source/gfx/gl/gfxGLCardProfiler.cpp b/Engine/source/gfx/gl/gfxGLCardProfiler.cpp index 900737b19..b4b968b85 100644 --- a/Engine/source/gfx/gl/gfxGLCardProfiler.cpp +++ b/Engine/source/gfx/gl/gfxGLCardProfiler.cpp @@ -76,30 +76,30 @@ void GFXGLCardProfiler::setupCardCapabilities() setCapability("maxTextureSize", maxTexSize); // If extensions haven't been inited, we're in trouble here. - bool suppVBO = (gglHasExtension(GL_ARB_vertex_buffer_object) || glVersion >= 1.499f); + bool suppVBO = (gglHasExtension(ARB_vertex_buffer_object) || glVersion >= 1.499f); setCapability("GL::suppVertexBufferObject", suppVBO); // check if render to texture supported is available - bool suppRTT = gglHasExtension(GL_EXT_framebuffer_object); + bool suppRTT = gglHasExtension(EXT_framebuffer_object); setCapability("GL::suppRenderTexture", suppRTT); - bool suppBlit = gglHasExtension(GL_EXT_framebuffer_blit); + bool suppBlit = gglHasExtension(EXT_framebuffer_blit); setCapability("GL::suppRTBlit", suppBlit); - bool suppFloatTex = gglHasExtension(GL_ATI_texture_float); + bool suppFloatTex = gglHasExtension(ARB_texture_float); setCapability("GL::suppFloatTexture", suppFloatTex); // Check for anisotropic filtering support. - bool suppAnisotropic = gglHasExtension( GL_EXT_texture_filter_anisotropic ); + bool suppAnisotropic = gglHasExtension( EXT_texture_filter_anisotropic ); setCapability( "GL::suppAnisotropic", suppAnisotropic ); // check to see if we have the fragment shader extension or the gl version is high enough for glsl to be core // also check to see if the language version is high enough F32 glslVersion = dAtof(reinterpret_cast(glGetString( GL_SHADING_LANGUAGE_VERSION))); - bool suppSPU = (gglHasExtension(GL_ARB_fragment_shader) || glVersion >= 1.999f) && glslVersion >= 1.0999; + bool suppSPU = (gglHasExtension(ARB_fragment_shader) || glVersion >= 1.999f) && glslVersion >= 1.0999; setCapability("GL::suppFragmentShader", suppSPU); - bool suppAppleFence = gglHasExtension(GL_APPLE_fence); + bool suppAppleFence = gglHasExtension(APPLE_fence); setCapability("GL::APPLE::suppFence", suppAppleFence); // When enabled, call glGenerateMipmapEXT() to generate mipmaps instead of relying on GL_GENERATE_MIPMAP diff --git a/Engine/source/gfx/gl/gfxGLCircularVolatileBuffer.h b/Engine/source/gfx/gl/gfxGLCircularVolatileBuffer.h new file mode 100644 index 000000000..b2749fe2e --- /dev/null +++ b/Engine/source/gfx/gl/gfxGLCircularVolatileBuffer.h @@ -0,0 +1,289 @@ +#ifndef GL_CIRCULAR_VOLATILE_BUFFER_H +#define GL_CIRCULAR_VOLATILE_BUFFER_H + +#include "gfx/gl/gfxGLDevice.h" +#include "gfx/gl/gfxGLUtils.h" + +class GLFenceRange +{ +public: + GLFenceRange() : mStart(0), mEnd(0), mSync(0) + { + + } + + ~GLFenceRange() + { + AssertFatal( mSync == 0, ""); + } + + void init(U32 start, U32 end) + { + mStart = start; + mEnd = end; + mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + } + + bool checkOverlap(U32 start, U32 end) + { + if( mStart < end && start < mEnd ) + return true; + + return false; + } + + void wait() + { + GLbitfield waitFlags = 0; + GLuint64 waitDuration = 0; + while( 1 ) + { + GLenum waitRet = glClientWaitSync( mSync, waitFlags, waitDuration ); + if( waitRet == GL_ALREADY_SIGNALED || waitRet == GL_CONDITION_SATISFIED ) + { + break; + } + + if( waitRet == GL_WAIT_FAILED ) + { + AssertFatal(0, "GLSync failed."); + break; + } + + waitFlags = GL_SYNC_FLUSH_COMMANDS_BIT; + waitDuration = scOneSecondInNanoSeconds; + } + + glDeleteSync(mSync); + mSync = 0; + } + + void swap( GLFenceRange &r ) + { + GLFenceRange temp; + temp = *this; + *this = r; + r = temp; + } + +protected: + U32 mStart, mEnd; + GLsync mSync; + static const GLuint64 scOneSecondInNanoSeconds = 1000000000; + + GLFenceRange( const GLFenceRange &); + GLFenceRange& operator=(const GLFenceRange &r) + { + mStart = r.mStart; + mEnd = r.mEnd; + mSync = r.mSync; + return *this; + } +}; + +class GLOrderedFenceRangeManager +{ +public: + + ~GLOrderedFenceRangeManager( ) + { + waitAllRanges( ); + } + + void protectOrderedRange( U32 start, U32 end ) + { + mFenceRanges.increment(); + GLFenceRange &range = mFenceRanges.last(); + range.init( start, end ); + } + + void waitFirstRange( U32 start, U32 end ) + { + if( !mFenceRanges.size() || !mFenceRanges[0].checkOverlap( start, end ) ) + return; + + mFenceRanges[0].wait(); + mFenceRanges.pop_front(); + } + + void waitOverlapRanges( U32 start, U32 end ) + { + for( U32 i = 0; i < mFenceRanges.size(); ++i ) + { + if( !mFenceRanges[i].checkOverlap( start, end ) ) + continue; + + mFenceRanges[i].wait(); + mFenceRanges.erase(i); + } + } + + void waitAllRanges() + { + for( int i = 0; i < mFenceRanges.size(); ++i ) + mFenceRanges[i].wait(); + + mFenceRanges.clear(); + } + +protected: + Vector mFenceRanges; +}; + +class GLCircularVolatileBuffer +{ +public: + GLCircularVolatileBuffer(GLuint binding) + : mBinding(binding), mBufferName(0), mBufferPtr(NULL), mBufferSize(0), mBufferFreePos(0), mCurrectUsedRangeStart(0) + { + init(); + } + + void init() + { + glGenBuffers(1, &mBufferName); + + PRESERVE_VERTEX_BUFFER(); + glBindBuffer(mBinding, mBufferName); + + const U32 cSizeInMB = 10; + mBufferSize = (cSizeInMB << 20); + + if( gglHasExtension(ARB_buffer_storage) ) + { + const GLbitfield flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT; + glBufferStorage(mBinding, mBufferSize, NULL, flags); + mBufferPtr = glMapBufferRange(mBinding, 0, mBufferSize, flags); + } + else + { + glBufferData(mBinding, mBufferSize, NULL, GL_DYNAMIC_DRAW); + } + } + + struct + { + U32 mOffset, mSize; + }_getBufferData; + + void lock(const U32 size, U32 offsetAlign, U32 &outOffset, void* &outPtr) + { + if( !size ) + { + AssertFatal(0, ""); + outOffset = 0; + outPtr = NULL; + } + + mLockManager.waitFirstRange( mBufferFreePos, (mBufferFreePos + size)-1 ); + + if( mBufferFreePos + size > mBufferSize ) + { + mUsedRanges.push_back( UsedRange( mBufferFreePos, mBufferSize-1 ) ); + mBufferFreePos = 0; + } + + // force offset buffer align + if( offsetAlign ) + mBufferFreePos = ( (mBufferFreePos/offsetAlign) + 1 ) * offsetAlign; + + outOffset = mBufferFreePos; + + if( gglHasExtension(ARB_buffer_storage) ) + { + outPtr = (U8*)(mBufferPtr) + mBufferFreePos; + } + else if( GFXGL->glUseMap() ) + { + PRESERVE_VERTEX_BUFFER(); + glBindBuffer(GL_ARRAY_BUFFER, mBufferName); + + const GLbitfield access = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT; + outPtr = glMapBufferRange(GL_ARRAY_BUFFER, outOffset, size, access); + } + else + { + _getBufferData.mOffset = outOffset; + _getBufferData.mSize = size; + + outPtr = mFrameAllocator.lock( size ); + } + + //set new buffer pos + mBufferFreePos = mBufferFreePos + size; + + //align 4bytes + mBufferFreePos = ( (mBufferFreePos/4) + 1 ) * 4; + } + + void unlock() + { + if( gglHasExtension(ARB_buffer_storage) ) + { + return; + } + else if( GFXGL->glUseMap() ) + { + PRESERVE_VERTEX_BUFFER(); + glBindBuffer(GL_ARRAY_BUFFER, mBufferName); + + glUnmapBuffer(GL_ARRAY_BUFFER); + } + else + { + PRESERVE_VERTEX_BUFFER(); + glBindBuffer(GL_ARRAY_BUFFER, mBufferName); + + glBufferSubData( mBinding, _getBufferData.mOffset, _getBufferData.mSize, mFrameAllocator.getlockedPtr() ); + + _getBufferData.mOffset = 0; + _getBufferData.mSize = 0; + + mFrameAllocator.unlock(); + } + + } + + U32 getHandle() const { return mBufferName; } + + void protectUsedRange() + { + for( int i = 0; i < mUsedRanges.size(); ++i ) + { + mLockManager.protectOrderedRange( mUsedRanges[i].start, mUsedRanges[i].end ); + } + mUsedRanges.clear(); + + if( mCurrectUsedRangeStart < mBufferFreePos ) + { + mLockManager.protectOrderedRange( mCurrectUsedRangeStart, mBufferFreePos-1 ); + mCurrectUsedRangeStart = mBufferFreePos; + } + } + +protected: + + GLuint mBinding; + GLuint mBufferName; + void *mBufferPtr; + U32 mBufferSize; + U32 mBufferFreePos; + U32 mCurrectUsedRangeStart; + + GLOrderedFenceRangeManager mLockManager; + FrameAllocatorLockableHelper mFrameAllocator; + + struct UsedRange + { + UsedRange(U32 _start = 0, U32 _end = 0) + : start(_start), end(_end) + { + + } + U32 start, end; + }; + Vector mUsedRanges; +}; + + +#endif \ No newline at end of file diff --git a/Engine/source/gfx/gl/gfxGLCubemap.cpp b/Engine/source/gfx/gl/gfxGLCubemap.cpp index d5afbc4a8..cdc41641e 100644 --- a/Engine/source/gfx/gl/gfxGLCubemap.cpp +++ b/Engine/source/gfx/gl/gfxGLCubemap.cpp @@ -27,7 +27,7 @@ #include "gfx/gl/gfxGLCubemap.h" #include "gfx/gfxTextureManager.h" #include "gfx/gfxCardProfile.h" -#include "gfx/bitmap/DDSFile.h" +#include "gfx/bitmap/ddsFile.h" GLenum GFXGLCubemap::faceList[6] = @@ -56,9 +56,9 @@ GFXGLCubemap::~GFXGLCubemap() void GFXGLCubemap::fillCubeTextures(GFXTexHandle* faces) { - glActiveTexture(GL_TEXTURE0); + PRESERVE_CUBEMAP_TEXTURE(); glBindTexture(GL_TEXTURE_CUBE_MAP, mCubemap); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP, GL_TRUE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0 ); // TODO OPENGL GFXGLCubemap mipmaps glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -89,9 +89,6 @@ void GFXGLCubemap::fillCubeTextures(GFXTexHandle* faces) 0, GFXGLTextureFormat[faceFormat], GFXGLTextureType[faceFormat], buf); delete[] buf; } - - glBindTexture(GL_TEXTURE_CUBE_MAP, 0); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); } void GFXGLCubemap::initStatic(GFXTexHandle* faces) @@ -128,9 +125,9 @@ void GFXGLCubemap::initStatic( DDSFile *dds ) glGenTextures(1, &mCubemap); - glActiveTexture(GL_TEXTURE0); + PRESERVE_CUBEMAP_TEXTURE(); glBindTexture(GL_TEXTURE_CUBE_MAP, mCubemap); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP, GL_TRUE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0 ); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -162,9 +159,6 @@ void GFXGLCubemap::initStatic( DDSFile *dds ) glCompressedTexImage2D( faceList[i], 0, GFXGLTextureInternalFormat[mFaceFormat], mWidth, mHeight, 0, surfaceSize, buffer ); } - - glBindTexture(GL_TEXTURE_CUBE_MAP, 0); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); } void GFXGLCubemap::initDynamic(U32 texSize, GFXFormat faceFormat) @@ -173,6 +167,7 @@ void GFXGLCubemap::initDynamic(U32 texSize, GFXFormat faceFormat) mFaceFormat = faceFormat; glGenTextures(1, &mCubemap); + PRESERVE_CUBEMAP_TEXTURE(); glBindTexture(GL_TEXTURE_CUBE_MAP, mCubemap); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -187,7 +182,6 @@ void GFXGLCubemap::initDynamic(U32 texSize, GFXFormat faceFormat) glTexImage2D( faceList[i], 0, GFXGLTextureInternalFormat[faceFormat], texSize, texSize, 0, GFXGLTextureFormat[faceFormat], GFXGLTextureType[faceFormat], NULL); } - glBindTexture(GL_TEXTURE_CUBE_MAP, 0); } void GFXGLCubemap::zombify() @@ -223,6 +217,7 @@ void GFXGLCubemap::bind(U32 textureUnit) const { glActiveTexture(GL_TEXTURE0 + textureUnit); glBindTexture(GL_TEXTURE_CUBE_MAP, mCubemap); + static_cast(getOwningDevice())->getOpenglCache()->setCacheBindedTex(textureUnit, GL_TEXTURE_CUBE_MAP, mCubemap); GFXGLStateBlockRef sb = static_cast(GFX)->getCurrentStateBlock(); AssertFatal(sb, "GFXGLCubemap::bind - No active stateblock!"); @@ -235,8 +230,6 @@ void GFXGLCubemap::bind(U32 textureUnit) const glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GFXGLTextureAddress[ssd.addressModeU]); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GFXGLTextureAddress[ssd.addressModeV]); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GFXGLTextureAddress[ssd.addressModeW]); - - glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, ssd.mipLODBias); } void GFXGLCubemap::_onTextureEvent( GFXTexCallbackCode code ) diff --git a/Engine/source/gfx/gl/gfxGLDevice.cpp b/Engine/source/gfx/gl/gfxGLDevice.cpp index 8e9acd20c..2e22530ed 100644 --- a/Engine/source/gfx/gl/gfxGLDevice.cpp +++ b/Engine/source/gfx/gl/gfxGLDevice.cpp @@ -22,6 +22,7 @@ #include "platform/platform.h" #include "gfx/gl/gfxGLDevice.h" +#include "platform/platformGL.h" #include "gfx/gfxCubemap.h" #include "gfx/screenshot.h" @@ -36,12 +37,15 @@ #include "gfx/gl/gfxGLCubemap.h" #include "gfx/gl/gfxGLCardProfiler.h" #include "gfx/gl/gfxGLWindowTarget.h" -#include "gfx/gl/ggl/ggl.h" #include "platform/platformDlibrary.h" #include "gfx/gl/gfxGLShader.h" #include "gfx/primBuilder.h" #include "console/console.h" #include "gfx/gl/gfxGLOcclusionQuery.h" +#include "materials/shaderData.h" +#include "gfx/gl/gfxGLStateCache.h" +#include "gfx/gl/gfxGLVertexAttribLocation.h" +#include "gfx/gl/gfxGLVertexDecl.h" GFXAdapter::CreateDeviceInstanceDelegate GFXGLDevice::mCreateDeviceInstance(GFXGLDevice::createInstance); @@ -77,6 +81,23 @@ void loadGLExtensions(void *context) GL::gglPerformExtensionBinds(context); } +void STDCALL glDebugCallback(GLenum source, GLenum type, GLuint id, + GLenum severity, GLsizei length, const GLchar* message, void* userParam) +{ +#if defined(TORQUE_DEBUG) && !defined(TORQUE_DEBUG_GFX) + if( type == GL_DEBUG_TYPE_OTHER_ARB ) + return; +#endif + + Con::errorf("OPENGL: %s", message); +} + +void STDCALL glAmdDebugCallback(GLuint id, GLenum category, GLenum severity, GLsizei length, + const GLchar* message,GLvoid* userParam) +{ + Con::errorf("OPENGL: %s",message); +} + void GFXGLDevice::initGLState() { // We don't currently need to sync device state with a known good place because we are @@ -88,29 +109,56 @@ void GFXGLDevice::initGLState() mCardProfiler->init(); glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, (GLint*)&mMaxShaderTextures); glGetIntegerv(GL_MAX_TEXTURE_UNITS, (GLint*)&mMaxFFTextures); + glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, (GLint*)&mMaxTRColors); + mMaxTRColors = getMin( mMaxTRColors, (U32)(GFXTextureTarget::MaxRenderSlotId-1) ); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - // Apple's drivers lie and claim that everything supports fragment shaders. Conveniently they don't lie about the number - // of supported image units. Checking for 16 or more image units ensures that we don't try and use pixel shaders on - // cards which don't support them. - if(mCardProfiler->queryProfile("GL::suppFragmentShader") && mMaxShaderTextures >= 16) - mPixelShaderVersion = 2.0f; - else - mPixelShaderVersion = 0.0f; - - // MACHAX - Setting mPixelShaderVersion to 3.0 will allow Advanced Lighting - // to run. At the time of writing (6/18) it doesn't quite work yet. - if(Con::getBoolVariable("$pref::machax::enableAdvancedLighting", false)) - mPixelShaderVersion = 3.0f; - + // Setting mPixelShaderVersion to 3.0 will allow Advanced Lighting to run. + mPixelShaderVersion = 3.0; + mSupportsAnisotropic = mCardProfiler->queryProfile( "GL::suppAnisotropic" ); + + String vendorStr = (const char*)glGetString( GL_VENDOR ); + if( vendorStr.find("NVIDIA") != String::NPos) + mUseGlMap = false; + +#if TORQUE_DEBUG + if( gglHasExtension(ARB_debug_output) ) + { + glEnable(GL_DEBUG_OUTPUT); + glDebugMessageCallbackARB(glDebugCallback, NULL); + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); + GLuint unusedIds = 0; + glDebugMessageControlARB(GL_DONT_CARE, + GL_DONT_CARE, + GL_DONT_CARE, + 0, + &unusedIds, + GL_TRUE); + } + else if(gglHasExtension(AMD_debug_output)) + { + glEnable(GL_DEBUG_OUTPUT); + glDebugMessageCallbackAMD(glAmdDebugCallback, NULL); + //glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); + GLuint unusedIds = 0; + glDebugMessageEnableAMD(GL_DONT_CARE, GL_DONT_CARE, 0,&unusedIds, GL_TRUE); + } +#endif + + PlatformGL::setVSync(0); + + //OpenGL 3 need a binded VAO for render + GLuint vao; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); } GFXGLDevice::GFXGLDevice(U32 adapterIndex) : mAdapterIndex(adapterIndex), - mCurrentVB(NULL), mCurrentPB(NULL), + mDrawInstancesCount(0), m_mCurrentWorld(true), m_mCurrentView(true), mContext(NULL), @@ -118,33 +166,74 @@ GFXGLDevice::GFXGLDevice(U32 adapterIndex) : mPixelShaderVersion(0.0f), mMaxShaderTextures(2), mMaxFFTextures(2), - mClip(0, 0, 0, 0) + mMaxTRColors(1), + mClip(0, 0, 0, 0), + mCurrentShader( NULL ), + mNeedUpdateVertexAttrib(false), + mWindowRT(NULL), + mUseGlMap(true) { + for(int i = 0; i < VERTEX_STREAM_COUNT; ++i) + { + mCurrentVB[i] = NULL; + mCurrentVB_Divisor[i] = 0; + } + loadGLCore(); GFXGLEnumTranslate::init(); GFXVertexColor::setSwizzle( &Swizzles::rgba ); - mDeviceSwizzle32 = &Swizzles::bgra; - mDeviceSwizzle24 = &Swizzles::bgr; + + // OpenGL have native RGB, no need swizzle + mDeviceSwizzle32 = &Swizzles::rgba; + mDeviceSwizzle24 = &Swizzles::rgb; mTextureManager = new GFXGLTextureManager(); gScreenShot = new ScreenShot(); for(U32 i = 0; i < TEXTURE_STAGE_COUNT; i++) mActiveTextureType[i] = GL_ZERO; + + mNumVertexStream = 2; + + for(int i = 0; i < GS_COUNT; ++i) + mModelViewProjSC[i] = NULL; + + mOpenglStateCache = new GFXGLStateCache; } GFXGLDevice::~GFXGLDevice() { mCurrentStateBlock = NULL; + + for(int i = 0; i < VERTEX_STREAM_COUNT; ++i) + mCurrentVB[i] = NULL; mCurrentPB = NULL; - mCurrentVB = NULL; + for(U32 i = 0; i < mVolatileVBs.size(); i++) mVolatileVBs[i] = NULL; for(U32 i = 0; i < mVolatilePBs.size(); i++) mVolatilePBs[i] = NULL; + // Clear out our current texture references + for (U32 i = 0; i < TEXTURE_STAGE_COUNT; i++) + { + mCurrentTexture[i] = NULL; + mNewTexture[i] = NULL; + mCurrentCubemap[i] = NULL; + mNewCubemap[i] = NULL; + } + + mRTStack.clear(); + mCurrentRT = NULL; + + if( mTextureManager ) + { + mTextureManager->zombify(); + mTextureManager->kill(); + } + GFXResource* walk = mResourceListHead; while(walk) { @@ -156,15 +245,20 @@ GFXGLDevice::~GFXGLDevice() SAFE_DELETE( mCardProfiler ); SAFE_DELETE( gScreenShot ); + + SAFE_DELETE( mOpenglStateCache ); } void GFXGLDevice::zombify() { mTextureManager->zombify(); - if(mCurrentVB) - mCurrentVB->finish(); + + for(int i = 0; i < VERTEX_STREAM_COUNT; ++i) + if(mCurrentVB[i]) + mCurrentVB[i]->finish(); if(mCurrentPB) - mCurrentPB->finish(); + mCurrentPB->finish(); + //mVolatileVBs.clear(); //mVolatilePBs.clear(); GFXResource* walk = mResourceListHead; @@ -183,10 +277,12 @@ void GFXGLDevice::resurrect() walk->resurrect(); walk = walk->getNextResource(); } - if(mCurrentVB) - mCurrentVB->prepare(); + for(int i = 0; i < VERTEX_STREAM_COUNT; ++i) + if(mCurrentVB[i]) + mCurrentVB[i]->prepare(); if(mCurrentPB) mCurrentPB->prepare(); + mTextureManager->resurrect(); } @@ -244,20 +340,39 @@ GFXPrimitiveBuffer *GFXGLDevice::allocPrimitiveBuffer( U32 numIndices, U32 numPr void GFXGLDevice::setVertexStream( U32 stream, GFXVertexBuffer *buffer ) { - AssertFatal( stream == 0, "GFXGLDevice::setVertexStream - We don't support multiple vertex streams!" ); + AssertFatal(stream <= 1, "GFXGLDevice::setVertexStream only support 2 stream (0: data, 1: instancing)"); - // Reset the state the old VB required, then set the state the new VB requires. - if ( mCurrentVB ) - mCurrentVB->finish(); + //if(mCurrentVB[stream] != buffer) + { + // Reset the state the old VB required, then set the state the new VB requires. + if( mCurrentVB[stream] ) + { + mCurrentVB[stream]->finish(); + } - mCurrentVB = static_cast( buffer ); - if ( mCurrentVB ) - mCurrentVB->prepare(); + mCurrentVB[stream] = static_cast( buffer ); + + mNeedUpdateVertexAttrib = true; + } } void GFXGLDevice::setVertexStreamFrequency( U32 stream, U32 frequency ) { - // We don't support vertex stream frequency or mesh instancing in OGL yet. + if( stream == 0 ) + { + mCurrentVB_Divisor[stream] = 0; // non instanced, is vertex buffer + mDrawInstancesCount = frequency; // instances count + } + else + { + AssertFatal(frequency <= 1, "GFXGLDevice::setVertexStreamFrequency only support 0/1 for this stream" ); + if( stream == 1 && frequency == 1 ) + mCurrentVB_Divisor[stream] = 1; // instances data need a frequency of 1 + else + mCurrentVB_Divisor[stream] = 0; + } + + mNeedUpdateVertexAttrib = true; } GFXCubemap* GFXGLDevice::createCubemap() @@ -278,14 +393,24 @@ void GFXGLDevice::clear(U32 flags, ColorI color, F32 z, U32 stencil) // Make sure we have flushed our render target state. _updateRenderTargets(); - bool zwrite = true; + bool writeAllColors = true; + bool zwrite = true; + bool writeAllStencil = true; + const GFXStateBlockDesc *desc = NULL; if (mCurrentGLStateBlock) { - zwrite = mCurrentGLStateBlock->getDesc().zWriteEnable; - } + desc = &mCurrentGLStateBlock->getDesc(); + zwrite = desc->zWriteEnable; + writeAllColors = desc->colorWriteRed && desc->colorWriteGreen && desc->colorWriteBlue && desc->colorWriteAlpha; + writeAllStencil = desc->stencilWriteMask == 0xFFFFFFFF; + } + glColorMask(true, true, true, true); glDepthMask(true); - ColorF c = color; + glStencilMask(0xFFFFFFFF); + + + ColorF c = color; glClearColor(c.red, c.green, c.blue, c.alpha); glClearDepth(z); glClearStencil(stencil); @@ -296,13 +421,19 @@ void GFXGLDevice::clear(U32 flags, ColorI color, F32 z, U32 stencil) clearflags |= (flags & GFXClearStencil) ? GL_STENCIL_BUFFER_BIT : 0; glClear(clearflags); + + if(!writeAllColors) + glColorMask(desc->colorWriteRed, desc->colorWriteGreen, desc->colorWriteBlue, desc->colorWriteAlpha); if(!zwrite) glDepthMask(false); + + if(!writeAllStencil) + glStencilMask(desc->stencilWriteMask); } // Given a primitive type and a number of primitives, return the number of indexes/vertexes used. -GLsizei GFXGLDevice::primCountToIndexCount(GFXPrimitiveType primType, U32 primitiveCount) +inline GLsizei GFXGLDevice::primCountToIndexCount(GFXPrimitiveType primType, U32 primitiveCount) { switch (primType) { @@ -332,6 +463,24 @@ GLsizei GFXGLDevice::primCountToIndexCount(GFXPrimitiveType primType, U32 primit return 0; } +GFXVertexDecl* GFXGLDevice::allocVertexDecl( const GFXVertexFormat *vertexFormat ) +{ + typedef Map GFXGLVertexDeclMap; + static GFXGLVertexDeclMap declMap; + GFXGLVertexDeclMap::Iterator itr = declMap.find( (void*)vertexFormat->getDescription().c_str() ); // description string are interned, safe to use c_str() + if(itr != declMap.end()) + return &itr->value; + + GFXGLVertexDecl &decl = declMap[(void*)vertexFormat->getDescription().c_str()]; + decl.init(vertexFormat); + return &decl; +} + +void GFXGLDevice::setVertexDecl( const GFXVertexDecl *decl ) +{ + static_cast(decl)->prepareVertexFormat(); +} + inline void GFXGLDevice::preDrawPrimitive() { if( mStateDirty ) @@ -341,6 +490,25 @@ inline void GFXGLDevice::preDrawPrimitive() if(mCurrentShaderConstBuffer) setShaderConstBufferInternal(mCurrentShaderConstBuffer); + + if( mNeedUpdateVertexAttrib ) + { + AssertFatal(mCurrVertexDecl, ""); + const GFXGLVertexDecl* decl = static_cast(mCurrVertexDecl); + + for(int i = 0; i < getNumVertexStreams(); ++i) + { + if(mCurrentVB[i]) + { + mCurrentVB[i]->prepare(i, mCurrentVB_Divisor[i]); // GL_ARB_vertex_attrib_binding + decl->prepareBuffer_old( i, mCurrentVB[i]->mBuffer, mCurrentVB_Divisor[i] ); // old vertex buffer/format + } + } + + decl->updateActiveVertexAttrib( GFXGL->getOpenglCache()->getCacheVertexAttribActive() ); + } + + mNeedUpdateVertexAttrib = false; } inline void GFXGLDevice::postDrawPrimitive(U32 primitiveCount) @@ -352,16 +520,13 @@ inline void GFXGLDevice::postDrawPrimitive(U32 primitiveCount) void GFXGLDevice::drawPrimitive( GFXPrimitiveType primType, U32 vertexStart, U32 primitiveCount ) { preDrawPrimitive(); - - // There are some odd performance issues if a buffer is bound to GL_ELEMENT_ARRAY_BUFFER when glDrawArrays is called. Unbinding the buffer - // improves performance by 10%. - if(mCurrentPB) - mCurrentPB->finish(); + + vertexStart += mCurrentVB[0]->mBufferVertexOffset; - glDrawArrays(GFXGLPrimType[primType], vertexStart, primCountToIndexCount(primType, primitiveCount)); - - if(mCurrentPB) - mCurrentPB->prepare(); + if(mDrawInstancesCount) + glDrawArraysInstanced(GFXGLPrimType[primType], vertexStart, primCountToIndexCount(primType, primitiveCount), mDrawInstancesCount); + else + glDrawArrays(GFXGLPrimType[primType], vertexStart, primCountToIndexCount(primType, primitiveCount)); postDrawPrimitive(primitiveCount); } @@ -379,7 +544,12 @@ void GFXGLDevice::drawIndexedPrimitive( GFXPrimitiveType primType, U16* buf = (U16*)static_cast(mCurrentPrimitiveBuffer.getPointer())->getBuffer() + startIndex; - glDrawElements(GFXGLPrimType[primType], primCountToIndexCount(primType, primitiveCount), GL_UNSIGNED_SHORT, buf); + const U32 baseVertex = mCurrentVB[0]->mBufferVertexOffset; + + if(mDrawInstancesCount) + glDrawElementsInstancedBaseVertex(GFXGLPrimType[primType], primCountToIndexCount(primType, primitiveCount), GL_UNSIGNED_SHORT, buf, mDrawInstancesCount, baseVertex); + else + glDrawElementsBaseVertex(GFXGLPrimType[primType], primCountToIndexCount(primType, primitiveCount), GL_UNSIGNED_SHORT, buf, baseVertex); postDrawPrimitive(primitiveCount); } @@ -393,53 +563,12 @@ void GFXGLDevice::setPB(GFXGLPrimitiveBuffer* pb) void GFXGLDevice::setLightInternal(U32 lightStage, const GFXLightInfo light, bool lightEnable) { - if(!lightEnable) - { - glDisable(GL_LIGHT0 + lightStage); - return; - } - - if(light.mType == GFXLightInfo::Ambient) - { - AssertFatal(false, "Instead of setting an ambient light you should set the global ambient color."); - return; - } - - GLenum lightEnum = GL_LIGHT0 + lightStage; - glLightfv(lightEnum, GL_AMBIENT, (GLfloat*)&light.mAmbient); - glLightfv(lightEnum, GL_DIFFUSE, (GLfloat*)&light.mColor); - glLightfv(lightEnum, GL_SPECULAR, (GLfloat*)&light.mColor); - - F32 pos[4]; - - if(light.mType != GFXLightInfo::Vector) - { - dMemcpy(pos, &light.mPos, sizeof(light.mPos)); - pos[3] = 1.0; - } - else - { - dMemcpy(pos, &light.mDirection, sizeof(light.mDirection)); - pos[3] = 0.0; - } - // Harcoded attenuation - glLightf(lightEnum, GL_CONSTANT_ATTENUATION, 1.0f); - glLightf(lightEnum, GL_LINEAR_ATTENUATION, 0.1f); - glLightf(lightEnum, GL_QUADRATIC_ATTENUATION, 0.0f); - - glLightfv(lightEnum, GL_POSITION, (GLfloat*)&pos); - glEnable(lightEnum); + // ONLY NEEDED ON FFP } void GFXGLDevice::setLightMaterialInternal(const GFXLightMaterial mat) { - // CodeReview - Setting these for front and back is unnecessary. We should consider - // checking what faces we're culling and setting this only for the unculled faces. - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (GLfloat*)&mat.ambient); - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (GLfloat*)&mat.diffuse); - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (GLfloat*)&mat.specular); - glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (GLfloat*)&mat.emissive); - glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, mat.shininess); + // ONLY NEEDED ON FFP } void GFXGLDevice::setGlobalAmbientInternal(ColorF color) @@ -449,91 +578,40 @@ void GFXGLDevice::setGlobalAmbientInternal(ColorF color) void GFXGLDevice::setTextureInternal(U32 textureUnit, const GFXTextureObject*texture) { - const GFXGLTextureObject *tex = static_cast(texture); - glActiveTexture(GL_TEXTURE0 + textureUnit); + GFXGLTextureObject *tex = static_cast(const_cast(texture)); if (tex) { - // GFXGLTextureObject::bind also handles applying the current sampler state. - if(mActiveTextureType[textureUnit] != tex->getBinding() && mActiveTextureType[textureUnit] != GL_ZERO) - { - glBindTexture(mActiveTextureType[textureUnit], 0); - glDisable(mActiveTextureType[textureUnit]); - } mActiveTextureType[textureUnit] = tex->getBinding(); tex->bind(textureUnit); } else if(mActiveTextureType[textureUnit] != GL_ZERO) { + glActiveTexture(GL_TEXTURE0 + textureUnit); glBindTexture(mActiveTextureType[textureUnit], 0); - glDisable(mActiveTextureType[textureUnit]); + getOpenglCache()->setCacheBindedTex(textureUnit, mActiveTextureType[textureUnit], 0); mActiveTextureType[textureUnit] = GL_ZERO; } - - glActiveTexture(GL_TEXTURE0); } void GFXGLDevice::setCubemapInternal(U32 textureUnit, const GFXGLCubemap* texture) { - glActiveTexture(GL_TEXTURE0 + textureUnit); if(texture) { - if(mActiveTextureType[textureUnit] != GL_TEXTURE_CUBE_MAP && mActiveTextureType[textureUnit] != GL_ZERO) - { - glBindTexture(mActiveTextureType[textureUnit], 0); - glDisable(mActiveTextureType[textureUnit]); - } mActiveTextureType[textureUnit] = GL_TEXTURE_CUBE_MAP; texture->bind(textureUnit); } else if(mActiveTextureType[textureUnit] != GL_ZERO) { + glActiveTexture(GL_TEXTURE0 + textureUnit); glBindTexture(mActiveTextureType[textureUnit], 0); - glDisable(mActiveTextureType[textureUnit]); + getOpenglCache()->setCacheBindedTex(textureUnit, mActiveTextureType[textureUnit], 0); mActiveTextureType[textureUnit] = GL_ZERO; } - - glActiveTexture(GL_TEXTURE0); } void GFXGLDevice::setMatrix( GFXMatrixType mtype, const MatrixF &mat ) { - MatrixF modelview; - switch (mtype) - { - case GFXMatrixWorld : - { - glMatrixMode(GL_MODELVIEW); - m_mCurrentWorld = mat; - modelview = m_mCurrentWorld; - modelview *= m_mCurrentView; - modelview.transpose(); - glLoadMatrixf((F32*) modelview); - } - break; - case GFXMatrixView : - { - glMatrixMode(GL_MODELVIEW); - m_mCurrentView = mat; - modelview = m_mCurrentView; - modelview *= m_mCurrentWorld; - modelview.transpose(); - glLoadMatrixf((F32*) modelview); - } - break; - case GFXMatrixProjection : - { - glMatrixMode(GL_PROJECTION); - MatrixF t(mat); - t.transpose(); - glLoadMatrixf((F32*) t); - glMatrixMode(GL_MODELVIEW); - } - break; - // CodeReview - Add support for texture transform matrix types - default: - AssertFatal(false, "GFXGLDevice::setMatrix - Unknown matrix mode!"); - return; - } + // ONLY NEEDED ON FFP } void GFXGLDevice::setClipRect( const RectI &inRect ) @@ -584,8 +662,8 @@ void GFXGLDevice::setClipRect( const RectI &inRect ) setViewMatrix( mTempMatrix ); setWorldMatrix( mTempMatrix ); - // Set the viewport to the clip rect (with y flip) - RectI viewport(mClip.point.x, size.y - (mClip.point.y + mClip.extent.y), mClip.extent.x, mClip.extent.y); + // Set the viewport to the clip rect + RectI viewport(mClip.point.x, mClip.point.y, mClip.extent.x, mClip.extent.y); setViewport(viewport); } @@ -637,11 +715,58 @@ GFXOcclusionQuery* GFXGLDevice::createOcclusionQuery() void GFXGLDevice::setupGenericShaders( GenericShaderType type ) { - TORQUE_UNUSED(type); - // We have FF support, use that. - disableShaders(); -} + AssertFatal(type != GSTargetRestore, ""); + if( mGenericShader[GSColor] == NULL ) + { + ShaderData *shaderData; + + shaderData = new ShaderData(); + shaderData->setField("OGLVertexShaderFile", "shaders/common/fixedFunction/gl/colorV.glsl"); + shaderData->setField("OGLPixelShaderFile", "shaders/common/fixedFunction/gl/colorP.glsl"); + shaderData->setField("pixVersion", "2.0"); + shaderData->registerObject(); + mGenericShader[GSColor] = shaderData->getShader(); + mGenericShaderBuffer[GSColor] = mGenericShader[GSColor]->allocConstBuffer(); + mModelViewProjSC[GSColor] = mGenericShader[GSColor]->getShaderConstHandle( "$modelView" ); + + shaderData = new ShaderData(); + shaderData->setField("OGLVertexShaderFile", "shaders/common/fixedFunction/gl/modColorTextureV.glsl"); + shaderData->setField("OGLPixelShaderFile", "shaders/common/fixedFunction/gl/modColorTextureP.glsl"); + shaderData->setSamplerName("$diffuseMap", 0); + shaderData->setField("pixVersion", "2.0"); + shaderData->registerObject(); + mGenericShader[GSModColorTexture] = shaderData->getShader(); + mGenericShaderBuffer[GSModColorTexture] = mGenericShader[GSModColorTexture]->allocConstBuffer(); + mModelViewProjSC[GSModColorTexture] = mGenericShader[GSModColorTexture]->getShaderConstHandle( "$modelView" ); + + shaderData = new ShaderData(); + shaderData->setField("OGLVertexShaderFile", "shaders/common/fixedFunction/gl/addColorTextureV.glsl"); + shaderData->setField("OGLPixelShaderFile", "shaders/common/fixedFunction/gl/addColorTextureP.glsl"); + shaderData->setSamplerName("$diffuseMap", 0); + shaderData->setField("pixVersion", "2.0"); + shaderData->registerObject(); + mGenericShader[GSAddColorTexture] = shaderData->getShader(); + mGenericShaderBuffer[GSAddColorTexture] = mGenericShader[GSAddColorTexture]->allocConstBuffer(); + mModelViewProjSC[GSAddColorTexture] = mGenericShader[GSAddColorTexture]->getShaderConstHandle( "$modelView" ); + + shaderData = new ShaderData(); + shaderData->setField("OGLVertexShaderFile", "shaders/common/fixedFunction/gl/textureV.glsl"); + shaderData->setField("OGLPixelShaderFile", "shaders/common/fixedFunction/gl/textureP.glsl"); + shaderData->setSamplerName("$diffuseMap", 0); + shaderData->setField("pixVersion", "2.0"); + shaderData->registerObject(); + mGenericShader[GSTexture] = shaderData->getShader(); + mGenericShaderBuffer[GSTexture] = mGenericShader[GSTexture]->allocConstBuffer(); + mModelViewProjSC[GSTexture] = mGenericShader[GSTexture]->getShaderConstHandle( "$modelView" ); + } + + MatrixF tempMatrix = mProjectionMatrix * mViewMatrix * mWorldMatrix[mWorldStackSize]; + mGenericShaderBuffer[type]->setSafe(mModelViewProjSC[type], tempMatrix); + + setShader( mGenericShader[type] ); + setShaderConstBuffer( mGenericShaderBuffer[type] ); +} GFXShader* GFXGLDevice::createShader() { GFXGLShader* shader = new GFXGLShader(); @@ -651,19 +776,19 @@ GFXShader* GFXGLDevice::createShader() void GFXGLDevice::setShader( GFXShader *shader ) { + if(mCurrentShader == shader) + return; + if ( shader ) { GFXGLShader *glShader = static_cast( shader ); glShader->useProgram(); + mCurrentShader = shader; } else - glUseProgram(0); -} - -void GFXGLDevice::disableShaders() -{ - setShader(NULL); - setShaderConstBuffer( NULL ); + { + setupGenericShaders(); + } } void GFXGLDevice::setShaderConstBufferInternal(GFXShaderConstBuffer* buffer) @@ -673,12 +798,20 @@ void GFXGLDevice::setShaderConstBufferInternal(GFXShaderConstBuffer* buffer) U32 GFXGLDevice::getNumSamplers() const { - return mPixelShaderVersion > 0.001f ? mMaxShaderTextures : mMaxFFTextures; + return getMin((U32)TEXTURE_STAGE_COUNT,mPixelShaderVersion > 0.001f ? mMaxShaderTextures : mMaxFFTextures); +} + +GFXTextureObject* GFXGLDevice::getDefaultDepthTex() const +{ + if(mWindowRT && mWindowRT->getPointer()) + return static_cast( mWindowRT->getPointer() )->mBackBufferDepthTex.getPointer(); + + return NULL; } U32 GFXGLDevice::getNumRenderTargets() const { - return 1; + return mMaxTRColors; } void GFXGLDevice::_updateRenderTargets() @@ -748,6 +881,38 @@ GFXFormat GFXGLDevice::selectSupportedFormat( GFXTextureProfile* profile, return GFXFormatR8G8B8A8; } +U32 GFXGLDevice::getTotalVideoMemory_GL_EXT() +{ + // Source: http://www.opengl.org/registry/specs/ATI/meminfo.txt + if( gglHasExtension(ATI_meminfo) ) + { + GLint mem[4] = {0}; + glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, mem); // Retrieve the texture pool + + /* With mem[0] i get only the total memory free in the pool in KB + * + * mem[0] - total memory free in the pool + * mem[1] - largest available free block in the pool + * mem[2] - total auxiliary memory free + * mem[3] - largest auxiliary free block + */ + + return mem[0] / 1024; + } + + //source http://www.opengl.org/registry/specs/NVX/gpu_memory_info.txt + else if( gglHasExtension(NVX_gpu_memory_info) ) + { + GLint mem = 0; + glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &mem); + return mem / 1024; + } + + // TODO OPENGL, add supprt for INTEL cards. + + return 0; +} + // // Register this device with GFXInit // diff --git a/Engine/source/gfx/gl/gfxGLDevice.h b/Engine/source/gfx/gl/gfxGLDevice.h index d7b473cf4..6f1853dbb 100644 --- a/Engine/source/gfx/gl/gfxGLDevice.h +++ b/Engine/source/gfx/gl/gfxGLDevice.h @@ -28,9 +28,7 @@ #include "gfx/gfxDevice.h" #include "gfx/gfxInit.h" -#ifndef GL_GGL_H -#include "gfx/gl/ggl/ggl.h" -#endif +#include "gfx/gl/tGL/tGL.h" #include "windowManager/platformWindow.h" #include "gfx/gfxFence.h" @@ -41,6 +39,8 @@ class GFXGLVertexBuffer; class GFXGLPrimitiveBuffer; class GFXGLTextureTarget; class GFXGLCubemap; +class GFXGLStateCache; +class GFXGLVertexDecl; class GFXGLDevice : public GFXDevice { @@ -59,12 +59,13 @@ public: virtual void deactivate() { } virtual GFXAdapterType getAdapterType() { return OpenGL; } - virtual void enterDebugEvent(ColorI color, const char *name) { } - virtual void leaveDebugEvent() { } - virtual void setDebugMarker(ColorI color, const char *name) { } + virtual void enterDebugEvent(ColorI color, const char *name); + virtual void leaveDebugEvent(); + virtual void setDebugMarker(ColorI color, const char *name); virtual void enumerateVideoModes(); + virtual U32 getTotalVideoMemory_GL_EXT(); virtual U32 getTotalVideoMemory(); virtual GFXCubemap * createCubemap(); @@ -135,7 +136,16 @@ public: /// bool supportsAnisotropic() const { return mSupportsAnisotropic; } - + + GFXGLStateCache* getOpenglCache() { return mOpenglStateCache; } + + GFXTextureObject* getDefaultDepthTex() const; + + /// Returns the number of vertex streams supported by the device. + const U32 getNumVertexStreams() const { return mNumVertexStream; } + + bool glUseMap() const { return mUseGlMap; } + protected: /// Called by GFXDevice to create a device specific stateblock virtual GFXStateBlockRef createStateBlockInternal(const GFXStateBlockDesc& desc); @@ -170,16 +180,12 @@ protected: // NOTE: The GL device doesn't need a vertex declaration at // this time, but we need to return something to keep the system // from retrying to allocate one on every call. - virtual GFXVertexDecl* allocVertexDecl( const GFXVertexFormat *vertexFormat ) - { - static GFXVertexDecl decl; - return &decl; - } + virtual GFXVertexDecl* allocVertexDecl( const GFXVertexFormat *vertexFormat ); - virtual void setVertexDecl( const GFXVertexDecl *decl ) { } + virtual void setVertexDecl( const GFXVertexDecl *decl ); virtual void setVertexStream( U32 stream, GFXVertexBuffer *buffer ); - virtual void setVertexStreamFrequency( U32 stream, U32 frequency ); + virtual void setVertexStreamFrequency( U32 stream, U32 frequency ); private: typedef GFXDevice Parent; @@ -194,8 +200,16 @@ private: U32 mAdapterIndex; - StrongRefPtr mCurrentVB; + StrongRefPtr mCurrentVB[VERTEX_STREAM_COUNT]; + U32 mCurrentVB_Divisor[VERTEX_STREAM_COUNT]; + bool mNeedUpdateVertexAttrib; StrongRefPtr mCurrentPB; + U32 mDrawInstancesCount; + + GFXShader* mCurrentShader; + GFXShaderRef mGenericShader[GS_COUNT]; + GFXShaderConstBufferRef mGenericShaderBuffer[GS_COUNT]; + GFXShaderConstHandle *mModelViewProjSC[GS_COUNT]; /// Since GL does not have separate world and view matrices we need to track them MatrixF m_mCurrentWorld; @@ -206,11 +220,15 @@ private: F32 mPixelShaderVersion; - bool mSupportsAnisotropic; + bool mSupportsAnisotropic; + + U32 mNumVertexStream; U32 mMaxShaderTextures; U32 mMaxFFTextures; + U32 mMaxTRColors; + RectI mClip; GFXGLStateBlockRef mCurrentGLStateBlock; @@ -232,6 +250,13 @@ private: GFXFence* _createPlatformSpecificFence(); ///< If our platform (e.g. OS X) supports a fence extenstion (e.g. GL_APPLE_fence) this will create one, otherwise returns NULL void setPB(GFXGLPrimitiveBuffer* pb); ///< Sets mCurrentPB + + GFXGLStateCache *mOpenglStateCache; + + GFXWindowTargetRef *mWindowRT; + + bool mUseGlMap; }; +#define GFXGL static_cast(GFXDevice::get()) #endif diff --git a/Engine/source/gfx/gl/gfxGLDevice.mac.mm b/Engine/source/gfx/gl/gfxGLDevice.mac.mm index f0d12f08a..2d9da6d9b 100644 --- a/Engine/source/gfx/gl/gfxGLDevice.mac.mm +++ b/Engine/source/gfx/gl/gfxGLDevice.mac.mm @@ -294,21 +294,7 @@ GFXFence* GFXGLDevice::_createPlatformSpecificFence() return new GFXGLAppleFence(this); } -void GFXGLWindowTarget::makeActive() -{ - // If we're supposed to be running fullscreen, but haven't yet set up for it, - // do it now. - - if( !mFullscreenContext && mWindow->getVideoMode().fullScreen ) - { - static_cast< GFXGLDevice* >( mDevice )->zombify(); - _setupNewMode(); - } - - mFullscreenContext ? [(NSOpenGLContext*)mFullscreenContext makeCurrentContext] : [(NSOpenGLContext*)mContext makeCurrentContext]; -} - -bool GFXGLWindowTarget::present() +void GFXGLWindowTarget::_WindowPresent() { GFX->updateStates(); mFullscreenContext ? [(NSOpenGLContext*)mFullscreenContext flushBuffer] : [(NSOpenGLContext*)mContext flushBuffer]; diff --git a/Engine/source/gfx/gl/gfxGLDeviceProfiler.cpp b/Engine/source/gfx/gl/gfxGLDeviceProfiler.cpp new file mode 100644 index 000000000..22d9bb826 --- /dev/null +++ b/Engine/source/gfx/gl/gfxGLDeviceProfiler.cpp @@ -0,0 +1,133 @@ +#include "gui/core/guiCanvas.h" +#include "console/engineAPI.h" +#include "gfx/gfxDebugEvent.h" + +#include "gfx/gl/gfxGLDevice.h" + +#ifndef TORQUE_BASIC_GPU_PROFILER + //#define TORQUE_BASIC_GPU_PROFILER +#endif + +class GLTimer +{ +public: + + void begin() + { + glBeginQuery(GL_TIME_ELAPSED, mQueryId); + } + + void end() + { + glEndQuery(GL_TIME_ELAPSED); + } + + F64 getTime() + { + GLuint64 time; + glGetQueryObjectui64v(mQueryId, GL_QUERY_RESULT, &time); + return static_cast(time)/1000000.0f; + } + + class Data + { + public: + + Data() {} + + void init() + { + + } + + void onBeginFrame() + { + + } + + void onEndFrame() + { + + } + }; + + typedef Data DataType; + + GLTimer(GFXDevice *device, Data &data) : mData(&data) + { + glGenQueries(1, &mQueryId); + } + + GLTimer() : mName(NULL), mQueryId(0), mData(NULL) + { + + } + + GLTimer& operator=(const GLTimer &b) + { + mName = b.mName; + mQueryId = b.mQueryId; + return *this; + } + + StringTableEntry mName; + +protected: + Data *mData; + GLuint mQueryId; + +}; + + +#ifdef TORQUE_BASIC_GPU_PROFILER + +#include "gfx/gfxProfiler.h" + + +GFXProfiler gfxProfiler; + +DefineConsoleFunction(printGFXGLTimers, void,(), ,"") +{ + gfxProfiler.printTimes(); +} + +#endif + +bool initGLProfiler(GFXDevice::GFXDeviceEventType ev) +{ + if(ev != GFXDevice::deInit || GFX->getAdapterType() != OpenGL) + return true; + + Con::evaluatef("GlobalActionMap.bindCmd(keyboard, \"alt F4\", \"printGFXGLTimers();\");"); + return true; +} + +void GFXGLDevice::enterDebugEvent(ColorI color, const char *name) +{ +#ifdef TORQUE_BASIC_GPU_PROFILER + gfxProfiler.enterDebugEvent(color, name); +#endif +} + +void GFXGLDevice::leaveDebugEvent() +{ +#ifdef TORQUE_BASIC_GPU_PROFILER + gfxProfiler.leaveDebugEvent(); +#endif +} + +void GFXGLDevice::setDebugMarker(ColorI color, const char *name) +{ + +} + +#ifdef TORQUE_BASIC_GPU_PROFILER + +AFTER_MODULE_INIT(Sim) +{ + // GFXGLDevice Profiler + GuiCanvas::getGuiCanvasFrameSignal().notify(&gfxProfiler, &GFXProfiler::onEndFrame); + GFXDevice::getDeviceEventSignal().notify( &initGLProfiler ); +} + +#endif diff --git a/Engine/source/gfx/gl/gfxGLEnumTranslate.cpp b/Engine/source/gfx/gl/gfxGLEnumTranslate.cpp index 7692b775b..19f6e1c69 100644 --- a/Engine/source/gfx/gl/gfxGLEnumTranslate.cpp +++ b/Engine/source/gfx/gl/gfxGLEnumTranslate.cpp @@ -34,6 +34,7 @@ GLenum GFXGLStencilOp[GFXStencilOp_COUNT]; GLenum GFXGLTextureInternalFormat[GFXFormat_COUNT]; GLenum GFXGLTextureFormat[GFXFormat_COUNT]; GLenum GFXGLTextureType[GFXFormat_COUNT]; +GLint* GFXGLTextureSwizzle[GFXFormat_COUNT]; GLenum GFXGLBufferType[GFXBufferType_COUNT]; GLenum GFXGLCullMode[GFXCull_COUNT]; GLenum GFXGLFillMode[GFXFill_COUNT]; @@ -118,54 +119,50 @@ void GFXGLEnumTranslate::init() // Texture formats - GFXGLTextureInternalFormat[GFXFormatA8] = GL_ALPHA8; - GFXGLTextureInternalFormat[GFXFormatL8] = GL_LUMINANCE8; - GFXGLTextureInternalFormat[GFXFormatR5G6B5] = GL_RGB5_A1; // OpenGL has no R5G6B5 format. + for(int i = 0; i < GFXFormat_COUNT; ++i) + { + GFXGLTextureInternalFormat[i] = GL_NONE; + GFXGLTextureFormat[i] = GL_NONE; + GFXGLTextureType[i] = GL_NONE; + GFXGLTextureSwizzle[i] = NULL; + } + + GFXGLTextureInternalFormat[GFXFormatA8] = GL_R8; + GFXGLTextureInternalFormat[GFXFormatL8] = GL_R8; GFXGLTextureInternalFormat[GFXFormatR5G5B5A1] = GL_RGB5_A1; GFXGLTextureInternalFormat[GFXFormatR5G5B5X1] = GL_RGB5_A1; - GFXGLTextureInternalFormat[GFXFormatL16] = GL_LUMINANCE16; - GFXGLTextureInternalFormat[GFXFormatR16F] = GL_ZERO; - GFXGLTextureInternalFormat[GFXFormatD16] = GL_DEPTH_COMPONENT; + GFXGLTextureInternalFormat[GFXFormatL16] = GL_R16; + GFXGLTextureInternalFormat[GFXFormatD16] = GL_DEPTH_COMPONENT16; GFXGLTextureInternalFormat[GFXFormatR8G8B8] = GL_RGB8; GFXGLTextureInternalFormat[GFXFormatR8G8B8A8] = GL_RGBA8; GFXGLTextureInternalFormat[GFXFormatR8G8B8X8] = GL_RGBA8; - GFXGLTextureInternalFormat[GFXFormatR32F] = GL_ZERO; - GFXGLTextureInternalFormat[GFXFormatR16G16] = GL_RGBA16; - GFXGLTextureInternalFormat[GFXFormatR16G16F] = GL_ZERO; - GFXGLTextureInternalFormat[GFXFormatR10G10B10A2] = GL_ZERO; + GFXGLTextureInternalFormat[GFXFormatB8G8R8A8] = GL_RGBA8; + GFXGLTextureInternalFormat[GFXFormatR10G10B10A2] = GL_RGB10_A2; GFXGLTextureInternalFormat[GFXFormatD32] = GL_DEPTH_COMPONENT32; - GFXGLTextureInternalFormat[GFXFormatD24X8] = GL_DEPTH_COMPONENT24; - GFXGLTextureInternalFormat[GFXFormatD24S8] = GL_DEPTH_COMPONENT24; - GFXGLTextureInternalFormat[GFXFormatR16G16B16A16] = GL_ZERO; - GFXGLTextureInternalFormat[GFXFormatR16G16B16A16F] = GL_ZERO; - GFXGLTextureInternalFormat[GFXFormatR32G32B32A32F] = GL_ZERO; + GFXGLTextureInternalFormat[GFXFormatD24X8] = GL_DEPTH24_STENCIL8; + GFXGLTextureInternalFormat[GFXFormatD24S8] = GL_DEPTH24_STENCIL8; + GFXGLTextureInternalFormat[GFXFormatR16G16B16A16] = GL_RGBA16; GFXGLTextureInternalFormat[GFXFormatDXT1] = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; GFXGLTextureInternalFormat[GFXFormatDXT2] = GL_ZERO; GFXGLTextureInternalFormat[GFXFormatDXT3] = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; GFXGLTextureInternalFormat[GFXFormatDXT4] = GL_ZERO; GFXGLTextureInternalFormat[GFXFormatDXT5] = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - GFXGLTextureFormat[GFXFormatA8] = GL_ALPHA; - GFXGLTextureFormat[GFXFormatL8] = GL_LUMINANCE; - GFXGLTextureFormat[GFXFormatR5G6B5] = GL_RGBA; + GFXGLTextureFormat[GFXFormatA8] = GL_RED; + GFXGLTextureFormat[GFXFormatL8] = GL_RED; GFXGLTextureFormat[GFXFormatR5G5B5A1] = GL_RGBA; GFXGLTextureFormat[GFXFormatR5G5B5X1] = GL_RGBA; - GFXGLTextureFormat[GFXFormatL16] = GL_LUMINANCE; - GFXGLTextureFormat[GFXFormatR16F] = GL_ZERO; + GFXGLTextureFormat[GFXFormatL16] = GL_RED; GFXGLTextureFormat[GFXFormatD16] = GL_DEPTH_COMPONENT; GFXGLTextureFormat[GFXFormatR8G8B8] = GL_RGB; - GFXGLTextureFormat[GFXFormatR8G8B8A8] = GL_BGRA; - GFXGLTextureFormat[GFXFormatR8G8B8X8] = GL_BGRA; - GFXGLTextureFormat[GFXFormatR32F] = GL_RGBA; - GFXGLTextureFormat[GFXFormatR16G16] = GL_RGBA; - GFXGLTextureFormat[GFXFormatR16G16F] = GL_ZERO; + GFXGLTextureFormat[GFXFormatR8G8B8A8] = GL_RGBA; + GFXGLTextureFormat[GFXFormatR8G8B8X8] = GL_RGBA; + GFXGLTextureFormat[GFXFormatB8G8R8A8] = GL_BGRA; GFXGLTextureFormat[GFXFormatR10G10B10A2] = GL_RGBA; GFXGLTextureFormat[GFXFormatD32] = GL_DEPTH_COMPONENT; - GFXGLTextureFormat[GFXFormatD24X8] = GL_DEPTH_COMPONENT; - GFXGLTextureFormat[GFXFormatD24S8] = GL_DEPTH_COMPONENT; + GFXGLTextureFormat[GFXFormatD24X8] = GL_DEPTH_STENCIL; + GFXGLTextureFormat[GFXFormatD24S8] = GL_DEPTH_STENCIL; GFXGLTextureFormat[GFXFormatR16G16B16A16] = GL_RGBA; - GFXGLTextureFormat[GFXFormatR16G16B16A16F] = GL_RGBA; - GFXGLTextureFormat[GFXFormatR32G32B32A32F] = GL_RGBA; GFXGLTextureFormat[GFXFormatDXT1] = GL_RGBA; GFXGLTextureFormat[GFXFormatDXT2] = GL_ZERO; GFXGLTextureFormat[GFXFormatDXT3] = GL_RGBA; @@ -174,36 +171,102 @@ void GFXGLEnumTranslate::init() GFXGLTextureType[GFXFormatA8] = GL_UNSIGNED_BYTE; GFXGLTextureType[GFXFormatL8] = GL_UNSIGNED_BYTE; - GFXGLTextureType[GFXFormatR5G6B5] = GL_UNSIGNED_BYTE; - GFXGLTextureType[GFXFormatR5G5B5A1] = GL_UNSIGNED_BYTE; - GFXGLTextureType[GFXFormatR5G5B5X1] = GL_UNSIGNED_BYTE; + GFXGLTextureType[GFXFormatR5G5B5A1] = GL_UNSIGNED_SHORT_5_5_5_1; + GFXGLTextureType[GFXFormatR5G5B5X1] = GL_UNSIGNED_SHORT_5_5_5_1; GFXGLTextureType[GFXFormatL16] = GL_UNSIGNED_SHORT; - GFXGLTextureType[GFXFormatR16F] = GL_ZERO; GFXGLTextureType[GFXFormatD16] = GL_UNSIGNED_SHORT; GFXGLTextureType[GFXFormatR8G8B8] = GL_UNSIGNED_BYTE; GFXGLTextureType[GFXFormatR8G8B8A8] = GL_UNSIGNED_BYTE; GFXGLTextureType[GFXFormatR8G8B8X8] = GL_UNSIGNED_BYTE; - GFXGLTextureType[GFXFormatR32F] = GL_FLOAT; - GFXGLTextureType[GFXFormatR16G16] = GL_UNSIGNED_SHORT; - GFXGLTextureType[GFXFormatR16G16F] = GL_FLOAT; - GFXGLTextureType[GFXFormatR10G10B10A2] = GL_UNSIGNED_SHORT; - GFXGLTextureType[GFXFormatD32] = GL_UNSIGNED_BYTE; - GFXGLTextureType[GFXFormatD24X8] = GL_UNSIGNED_BYTE; - GFXGLTextureType[GFXFormatD24S8] = GL_UNSIGNED_BYTE; + GFXGLTextureType[GFXFormatB8G8R8A8] = GL_UNSIGNED_BYTE;; + GFXGLTextureType[GFXFormatR10G10B10A2] = GL_UNSIGNED_INT_10_10_10_2; + GFXGLTextureType[GFXFormatD32] = GL_UNSIGNED_INT; + GFXGLTextureType[GFXFormatD24X8] = GL_UNSIGNED_INT_24_8; + GFXGLTextureType[GFXFormatD24S8] = GL_UNSIGNED_INT_24_8; GFXGLTextureType[GFXFormatR16G16B16A16] = GL_UNSIGNED_SHORT; - GFXGLTextureType[GFXFormatR16G16B16A16F] = GL_FLOAT; - GFXGLTextureType[GFXFormatR32G32B32A32F] = GL_FLOAT; GFXGLTextureType[GFXFormatDXT1] = GL_UNSIGNED_BYTE; GFXGLTextureType[GFXFormatDXT2] = GL_ZERO; GFXGLTextureType[GFXFormatDXT3] = GL_UNSIGNED_BYTE; GFXGLTextureType[GFXFormatDXT4] = GL_ZERO; GFXGLTextureType[GFXFormatDXT5] = GL_UNSIGNED_BYTE; - // Cull - GFXGLCullMode[GFXCullNone] = GL_BACK; - GFXGLCullMode[GFXCullCW] = GL_BACK; - GFXGLCullMode[GFXCullCCW] = GL_FRONT; - + static GLint Swizzle_GFXFormatA8[] = { GL_NONE, GL_NONE, GL_NONE, GL_RED }; + static GLint Swizzle_GFXFormatL[] = { GL_RED, GL_RED, GL_RED, GL_ALPHA }; + GFXGLTextureSwizzle[GFXFormatA8] = Swizzle_GFXFormatA8; // old GL_ALPHA8 + GFXGLTextureSwizzle[GFXFormatL8] = Swizzle_GFXFormatL; // old GL_LUMINANCE8 + GFXGLTextureSwizzle[GFXFormatL16] = Swizzle_GFXFormatL; // old GL_LUMINANCE16 + + if( gglHasExtension(ARB_texture_float) ) + { + GFXGLTextureInternalFormat[GFXFormatR32F] = GL_R32F; + GFXGLTextureFormat[GFXFormatR32F] = GL_RED; + GFXGLTextureType[GFXFormatR32F] = GL_FLOAT; + + GFXGLTextureInternalFormat[GFXFormatR32G32B32A32F] = GL_RGBA32F_ARB; + GFXGLTextureFormat[GFXFormatR32G32B32A32F] = GL_RGBA; + GFXGLTextureType[GFXFormatR32G32B32A32F] = GL_FLOAT; + + if( gglHasExtension(ARB_half_float_pixel) ) + { + GFXGLTextureInternalFormat[GFXFormatR16F] = GL_R16F; + GFXGLTextureFormat[GFXFormatR16F] = GL_RED; + GFXGLTextureType[GFXFormatR16F] = GL_HALF_FLOAT_ARB; + + GFXGLTextureInternalFormat[GFXFormatR16G16F] = GL_RG16F; + GFXGLTextureFormat[GFXFormatR16G16F] = GL_RG; + GFXGLTextureType[GFXFormatR16G16F] = GL_HALF_FLOAT_ARB; + + GFXGLTextureInternalFormat[GFXFormatR16G16B16A16F] = GL_RGBA16F_ARB; + GFXGLTextureFormat[GFXFormatR16G16B16A16F] = GL_RGBA; + GFXGLTextureType[GFXFormatR16G16B16A16F] = GL_HALF_FLOAT_ARB; + } + else + { + GFXGLTextureInternalFormat[GFXFormatR16F] = GL_R32F; + GFXGLTextureFormat[GFXFormatR16F] = GL_RED; + GFXGLTextureType[GFXFormatR16F] = GL_FLOAT; + + GFXGLTextureInternalFormat[GFXFormatR16G16F] = GL_RG32F; + GFXGLTextureFormat[GFXFormatR16G16F] = GL_RG; + GFXGLTextureType[GFXFormatR16G16F] = GL_FLOAT; + + GFXGLTextureInternalFormat[GFXFormatR16G16B16A16F] = GL_RGBA32F_ARB; + GFXGLTextureFormat[GFXFormatR16G16B16A16F] = GL_RGBA; + GFXGLTextureType[GFXFormatR16G16B16A16F] = GL_FLOAT; + } + } + + if( gglHasExtension(ARB_ES2_compatibility) ) + { + GFXGLTextureInternalFormat[GFXFormatR5G6B5] = GL_RGB5_A1; + GFXGLTextureFormat[GFXFormatR5G6B5] = GL_RGBA; + GFXGLTextureType[GFXFormatR5G6B5] = GL_UNSIGNED_SHORT_5_5_5_1; + } + else + { + GFXGLTextureInternalFormat[GFXFormatR5G6B5] = GL_RGB565; + GFXGLTextureFormat[GFXFormatR5G6B5] = GL_RGB; + GFXGLTextureType[GFXFormatR5G6B5] = GL_UNSIGNED_SHORT_5_6_5; + } + + if( gglHasExtension(ARB_texture_rg) ) + { + GFXGLTextureInternalFormat[GFXFormatR16G16] = GL_RG16; + GFXGLTextureFormat[GFXFormatR16G16] = GL_RG; + GFXGLTextureType[GFXFormatR16G16] = GL_UNSIGNED_SHORT; + } + else + { + GFXGLTextureInternalFormat[GFXFormatR16G16] = GL_RGBA16; + GFXGLTextureFormat[GFXFormatR16G16] = GL_RGBA; + GFXGLTextureType[GFXFormatR16G16] = GL_UNSIGNED_SHORT; + } + + // Cull - Opengl render upside down need to invert cull + GFXGLCullMode[GFXCullNone] = GL_FRONT; + GFXGLCullMode[GFXCullCW] = GL_FRONT; + GFXGLCullMode[GFXCullCCW] = GL_BACK; + // Fill GFXGLFillMode[GFXFillPoint] = GL_POINT; GFXGLFillMode[GFXFillWireframe] = GL_LINE; diff --git a/Engine/source/gfx/gl/gfxGLEnumTranslate.h b/Engine/source/gfx/gl/gfxGLEnumTranslate.h index 2affa463e..000f64093 100644 --- a/Engine/source/gfx/gl/gfxGLEnumTranslate.h +++ b/Engine/source/gfx/gl/gfxGLEnumTranslate.h @@ -43,6 +43,7 @@ extern GLenum GFXGLStencilOp[GFXStencilOp_COUNT]; extern GLenum GFXGLTextureInternalFormat[GFXFormat_COUNT]; extern GLenum GFXGLTextureFormat[GFXFormat_COUNT]; extern GLenum GFXGLTextureType[GFXFormat_COUNT]; +extern GLint* GFXGLTextureSwizzle[GFXFormat_COUNT]; extern GLenum GFXGLBufferType[GFXBufferType_COUNT]; extern GLenum GFXGLCullMode[GFXCull_COUNT]; diff --git a/Engine/source/gfx/gl/gfxGLOcclusionQuery.cpp b/Engine/source/gfx/gl/gfxGLOcclusionQuery.cpp index 6ecfb36cc..411f653d2 100644 --- a/Engine/source/gfx/gl/gfxGLOcclusionQuery.cpp +++ b/Engine/source/gfx/gl/gfxGLOcclusionQuery.cpp @@ -22,12 +22,12 @@ #include "platform/platform.h" #include "gfx/gl/gfxGLOcclusionQuery.h" -#include "gfx/gl/ggl/ggl.h" +#include "gfx/gl/tGL/tGL.h" GFXGLOcclusionQuery::GFXGLOcclusionQuery(GFXDevice* device) : - GFXOcclusionQuery(device), mQuery(0) + GFXOcclusionQuery(device), mQuery(-1) { - glGenQueries(1, &mQuery); + } GFXGLOcclusionQuery::~GFXGLOcclusionQuery() @@ -37,6 +37,9 @@ GFXGLOcclusionQuery::~GFXGLOcclusionQuery() bool GFXGLOcclusionQuery::begin() { + if(mQuery == -1) + glGenQueries(1, &mQuery); + glBeginQuery(GL_SAMPLES_PASSED, mQuery); return true; } @@ -51,6 +54,9 @@ GFXOcclusionQuery::OcclusionQueryStatus GFXGLOcclusionQuery::getStatus(bool bloc // If this ever shows up near the top of a profile // then your system is GPU bound. PROFILE_SCOPE(GFXGLOcclusionQuery_getStatus); + + if(mQuery == -1) + return NotOccluded; GLint numPixels = 0; GLint queryDone = false; diff --git a/Engine/source/gfx/gl/gfxGLPrimitiveBuffer.cpp b/Engine/source/gfx/gl/gfxGLPrimitiveBuffer.cpp index 22ba60fe0..bf5567a16 100644 --- a/Engine/source/gfx/gl/gfxGLPrimitiveBuffer.cpp +++ b/Engine/source/gfx/gl/gfxGLPrimitiveBuffer.cpp @@ -24,23 +24,40 @@ #include "gfx/gl/gfxGLPrimitiveBuffer.h" #include "gfx/gl/gfxGLEnumTranslate.h" -#include "gfx/gl/ggl/ggl.h" +#include "gfx/gl/tGL/tGL.h" #include "gfx/gl/gfxGLUtils.h" -GFXGLPrimitiveBuffer::GFXGLPrimitiveBuffer(GFXDevice *device, U32 indexCount, U32 primitiveCount, GFXBufferType bufferType) : -GFXPrimitiveBuffer(device, indexCount, primitiveCount, bufferType), mZombieCache(NULL) +#include "gfx/gl/gfxGLCircularVolatileBuffer.h" + +GLCircularVolatileBuffer* getCircularVolatileIndexBuffer() { + static GLCircularVolatileBuffer sCircularVolatileIndexBuffer(GL_ELEMENT_ARRAY_BUFFER); + return &sCircularVolatileIndexBuffer; +} + +GFXGLPrimitiveBuffer::GFXGLPrimitiveBuffer(GFXDevice *device, U32 indexCount, U32 primitiveCount, GFXBufferType bufferType) : + GFXPrimitiveBuffer(device, indexCount, primitiveCount, bufferType), mZombieCache(NULL), + mBufferOffset(0) +{ + if( mBufferType == GFXBufferTypeVolatile ) + { + mBuffer = getCircularVolatileIndexBuffer()->getHandle(); + return; + } + + // Generate a buffer and allocate the needed memory + glGenBuffers(1, &mBuffer); + PRESERVE_INDEX_BUFFER(); - // Generate a buffer and allocate the needed memory - glGenBuffers(1, &mBuffer); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mBuffer); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * sizeof(U16), NULL, GFXGLBufferType[bufferType]); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mBuffer); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * sizeof(U16), NULL, GFXGLBufferType[bufferType]); } GFXGLPrimitiveBuffer::~GFXGLPrimitiveBuffer() { // This is heavy handed, but it frees the buffer memory - glDeleteBuffersARB(1, &mBuffer); + if( mBufferType != GFXBufferTypeVolatile ) + glDeleteBuffers(1, &mBuffer); if( mZombieCache ) delete [] mZombieCache; @@ -48,44 +65,72 @@ GFXGLPrimitiveBuffer::~GFXGLPrimitiveBuffer() void GFXGLPrimitiveBuffer::lock(U32 indexStart, U32 indexEnd, void **indexPtr) { - // Preserve previous binding - PRESERVE_INDEX_BUFFER(); - - // Bind ourselves and map - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mBuffer); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, mIndexCount * sizeof(U16), NULL, GFXGLBufferType[mBufferType]); - - // Offset the buffer to indexStart - *indexPtr = (void*)((U8*)glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY) + (indexStart * sizeof(U16))); + if( mBufferType == GFXBufferTypeVolatile ) + { + AssertFatal(indexStart == 0, ""); + getCircularVolatileIndexBuffer()->lock( mIndexCount * sizeof(U16), 0, mBufferOffset, *indexPtr ); + } + else + { + mFrameAllocator.lock( mIndexCount * sizeof(U16) ); + + *indexPtr = (void*)(mFrameAllocator.getlockedPtr() + (indexStart * sizeof(U16)) ); + } + + lockedIndexStart = indexStart; + lockedIndexEnd = indexEnd; } void GFXGLPrimitiveBuffer::unlock() { - // Preserve previous binding - PRESERVE_INDEX_BUFFER(); + PROFILE_SCOPE(GFXGLPrimitiveBuffer_unlock); + + if( mBufferType == GFXBufferTypeVolatile ) + { + getCircularVolatileIndexBuffer()->unlock(); + } + else + { + U32 offset = lockedIndexStart * sizeof(U16); + U32 length = (lockedIndexEnd - lockedIndexStart) * sizeof(U16); - // Bind ourselves and unmap - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mBuffer); - bool res = glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); - AssertFatal(res, "GFXGLPrimitiveBuffer::unlock - shouldn't fail!"); + // Preserve previous binding + PRESERVE_INDEX_BUFFER(); + + // Bind ourselves + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mBuffer); + + if( !lockedIndexStart && lockedIndexEnd == mIndexCount) + glBufferData(GL_ELEMENT_ARRAY_BUFFER, mIndexCount * sizeof(U16), NULL, GFXGLBufferType[mBufferType]); // orphan the buffer + + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, length, mFrameAllocator.getlockedPtr() + offset ); + + mFrameAllocator.unlock(); + } + + lockedIndexStart = 0; + lockedIndexEnd = 0; } void GFXGLPrimitiveBuffer::prepare() { // Bind - static_cast(mDevice)->setPB(this); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mBuffer); + GFXGLDevice* glDevice = static_cast(mDevice); + glDevice->setPB(this); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mBuffer); + glDevice->getOpenglCache()->setCacheBinded(GL_ELEMENT_ARRAY_BUFFER, mBuffer); } void GFXGLPrimitiveBuffer::finish() { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + static_cast(mDevice)->getOpenglCache()->setCacheBinded(GL_ELEMENT_ARRAY_BUFFER, 0); } GLvoid* GFXGLPrimitiveBuffer::getBuffer() { // NULL specifies no offset into the hardware buffer - return (GLvoid*)NULL; + return (GLvoid*)mBufferOffset; } void GFXGLPrimitiveBuffer::zombify() @@ -114,3 +159,29 @@ void GFXGLPrimitiveBuffer::resurrect() delete[] mZombieCache; mZombieCache = NULL; } + +namespace +{ + bool onGFXDeviceSignal( GFXDevice::GFXDeviceEventType type ) + { + if( GFX->getAdapterType() == OpenGL && GFXDevice::deEndOfFrame == type ) + getCircularVolatileIndexBuffer()->protectUsedRange(); + + return true; + } +} + +MODULE_BEGIN( GFX_GL_PrimitiveBuffer ) + MODULE_INIT_AFTER( gfx ) + MODULE_SHUTDOWN_BEFORE( gfx ) + + MODULE_INIT + { + GFXDevice::getDeviceEventSignal( ).notify( &onGFXDeviceSignal ); + } + + MODULE_SHUTDOWN + { + GFXDevice::getDeviceEventSignal( ).remove( &onGFXDeviceSignal ); + } +MODULE_END \ No newline at end of file diff --git a/Engine/source/gfx/gl/gfxGLPrimitiveBuffer.h b/Engine/source/gfx/gl/gfxGLPrimitiveBuffer.h index a1c0af647..ad447804b 100644 --- a/Engine/source/gfx/gl/gfxGLPrimitiveBuffer.h +++ b/Engine/source/gfx/gl/gfxGLPrimitiveBuffer.h @@ -24,6 +24,7 @@ #define _GFXGLPRIMITIVEBUFFER_H_ #include "gfx/gfxPrimitiveBuffer.h" +#include "gfx/gl/util/glFrameAllocatorLockableHelper.h" /// This is a primitive buffer (index buffer to GL users) which uses VBOs. class GFXGLPrimitiveBuffer : public GFXPrimitiveBuffer @@ -32,8 +33,8 @@ public: GFXGLPrimitiveBuffer(GFXDevice *device, U32 indexCount, U32 primitiveCount, GFXBufferType bufferType); ~GFXGLPrimitiveBuffer(); - virtual void lock(U32 indexStart, U32 indexEnd, void **indexPtr); ///< calls glMapBuffer, offets pointer by indexStart - virtual void unlock(); ///< calls glUnmapBuffer, unbinds the buffer + virtual void lock(U32 indexStart, U32 indexEnd, void **indexPtr); ///< only write lock are supported + virtual void unlock(); ///< virtual void prepare(); ///< binds the buffer virtual void finish(); ///< We're done with this buffer @@ -46,8 +47,12 @@ public: private: /// Handle to our GL buffer object GLuint mBuffer; - + U32 mBufferOffset; U8* mZombieCache; + + U32 lockedIndexEnd, lockedIndexStart; + + FrameAllocatorLockableHelper mFrameAllocator; }; #endif \ No newline at end of file diff --git a/Engine/source/gfx/gl/gfxGLShader.cpp b/Engine/source/gfx/gl/gfxGLShader.cpp index 8b60fbd82..9ec77e117 100644 --- a/Engine/source/gfx/gl/gfxGLShader.cpp +++ b/Engine/source/gfx/gl/gfxGLShader.cpp @@ -22,6 +22,7 @@ #include "platform/platform.h" #include "gfx/gl/gfxGLShader.h" +#include "gfx/gl/gfxGLVertexAttribLocation.h" #include "core/frameAllocator.h" #include "core/stream/fileStream.h" @@ -59,10 +60,11 @@ public: U32 mOffset; U32 mSize; S32 mSamplerNum; + bool mInstancingConstant; }; GFXGLShaderConstHandle::GFXGLShaderConstHandle( GFXGLShader *shader ) - : mShader( shader ), mSamplerNum(-1) + : mShader( shader ), mSamplerNum(-1), mInstancingConstant(false) { mValid = false; } @@ -98,7 +100,7 @@ static U32 shaderConstTypeSize(GFXShaderConstType type) } GFXGLShaderConstHandle::GFXGLShaderConstHandle( GFXGLShader *shader, const GFXShaderConstDesc &desc, GLuint loc, S32 samplerNum ) - : mShader(shader) + : mShader(shader), mInstancingConstant(false) { reinit(desc, loc, samplerNum); } @@ -109,6 +111,7 @@ void GFXGLShaderConstHandle::reinit( const GFXShaderConstDesc& desc, GLuint loc, mLocation = loc; mSamplerNum = samplerNum; mOffset = 0; + mInstancingConstant = false; U32 elemSize = shaderConstTypeSize(mDesc.constType); AssertFatal(elemSize, "GFXGLShaderConst::GFXGLShaderConst - elemSize is 0"); @@ -156,8 +159,12 @@ void GFXGLShaderConstBuffer::internalSet(GFXShaderConstHandle* handle, const Con GFXGLShaderConstHandle* _glHandle = static_cast(handle); AssertFatal(mShader == _glHandle->mShader, "GFXGLShaderConstBuffer::set - Should only set handles which are owned by our shader"); - - dMemcpy(mBuffer + _glHandle->mOffset, ¶m, sizeof(ConstType)); + U8 *buf = mBuffer + _glHandle->mOffset; + + if(_glHandle->mInstancingConstant) + buf = mInstPtr + _glHandle->mOffset; + + dMemcpy(buf, ¶m, sizeof(ConstType)); } void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const F32 fv) @@ -219,6 +226,7 @@ void GFXGLShaderConstBuffer::internalSet(GFXShaderConstHandle* handle, const Ali GFXGLShaderConstHandle* _glHandle = static_cast(handle); AssertFatal(mShader == _glHandle->mShader, "GFXGLShaderConstBuffer::set - Should only set handles which are owned by our shader"); + AssertFatal(!_glHandle->mInstancingConstant, "GFXGLShaderConstBuffer::set - Instancing not supported for array"); const U8* fvBuffer = static_cast(fv.getBuffer()); for(U32 i = 0; i < fv.size(); ++i) { @@ -275,6 +283,7 @@ void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF& ma GFXGLShaderConstHandle* _glHandle = static_cast(handle); AssertFatal(mShader == _glHandle->mShader, "GFXGLShaderConstBuffer::set - Should only set handles which are owned by our shader"); + AssertFatal(!_glHandle->mInstancingConstant || matType == GFXSCT_Float4x4, "GFXGLShaderConstBuffer::set - Only support GFXSCT_Float4x4 for instancing"); switch(matType) { @@ -296,8 +305,18 @@ void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF& ma reinterpret_cast(mBuffer + _glHandle->mOffset)[8] = mat[10]; break; case GFXSCT_Float4x4: + { + if(_glHandle->mInstancingConstant) + { + MatrixF transposed; + mat.transposeTo(transposed); + dMemcpy( mInstPtr + _glHandle->mOffset, (const F32*)transposed, sizeof(MatrixF) ); + return; + } + dMemcpy(mBuffer + _glHandle->mOffset, (const F32*)mat, sizeof(MatrixF)); break; + } default: AssertFatal(false, "GFXGLShaderConstBuffer::set - Invalid matrix type"); break; @@ -310,8 +329,9 @@ void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF* ma AssertFatal(handle->isValid(), "GFXGLShaderConstBuffer::set - Handle is not valid!" ); GFXGLShaderConstHandle* _glHandle = static_cast(handle); - AssertFatal(mShader == _glHandle->mShader, "GFXGLShaderConstBuffer::set - Should only set handles which are owned by our shader"); - + AssertFatal(mShader == _glHandle->mShader, "GFXGLShaderConstBuffer::set - Should only set handles which are owned by our shader"); + AssertFatal(!_glHandle->mInstancingConstant, "GFXGLShaderConstBuffer::set - Instancing not supported for matrix arrays"); + switch (matrixType) { case GFXSCT_Float4x4: dMemcpy(mBuffer + _glHandle->mOffset, (F32*)mat, _glHandle->getSize()); @@ -393,6 +413,9 @@ bool GFXGLShader::_init() macros.increment(); macros.last().name = "TORQUE_SM"; macros.last().value = String::ToString( mjVer * 10 + mnVer ); + macros.increment(); + macros.last().name = "TORQUE_VERTEX_SHADER"; + macros.last().value = ""; // Default to true so we're "successful" if a vertex/pixel shader wasn't specified. bool compiledVertexShader = true; @@ -401,6 +424,8 @@ bool GFXGLShader::_init() // Compile the vertex and pixel shaders if specified. if(!mVertexFile.isEmpty()) compiledVertexShader = initShader(mVertexFile, true, macros); + + macros.last().name = "TORQUE_PIXEL_SHADER"; if(!mPixelFile.isEmpty()) compiledPixelShader = initShader(mPixelFile, false, macros); @@ -408,6 +433,24 @@ bool GFXGLShader::_init() if(!compiledVertexShader || !compiledPixelShader) return false; + //bind vertex attributes + glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_Position, "vPosition"); + glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_Normal, "vNormal"); + glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_Color, "vColor"); + glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_Tangent, "vTangent"); + glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TangentW, "vTangentW"); + glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_Binormal, "vBinormal"); + glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord0, "vTexCoord0"); + glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord1, "vTexCoord1"); + glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord2, "vTexCoord2"); + glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord3, "vTexCoord3"); + glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord4, "vTexCoord4"); + glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord5, "vTexCoord5"); + glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord6, "vTexCoord6"); + glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord7, "vTexCoord7"); + glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord8, "vTexCoord8"); + glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord9, "vTexCoord9"); + // Link it! glLinkProgram( mProgram ); @@ -463,6 +506,10 @@ void GFXGLShader::initConstantDescs() glGetProgramiv(mProgram, GL_ACTIVE_UNIFORMS, &numUniforms); GLint maxNameLength; glGetProgramiv(mProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxNameLength); + + if(!maxNameLength) + return; + FrameTemp uniformName(maxNameLength); for(U32 i = 0; i < numUniforms; i++) @@ -546,17 +593,23 @@ void GFXGLShader::initHandles() // Loop through all ConstantDescriptions, // if they aren't in the HandleMap add them, if they are reinitialize them. - S32 assignedSamplerNum = 0; for ( U32 i = 0; i < mConstants.size(); i++ ) { GFXShaderConstDesc &desc = mConstants[i]; // Index element 1 of the name to skip the '$' we inserted earier. - U32 loc = glGetUniformLocation(mProgram, &desc.name.c_str()[1]); + GLint loc = glGetUniformLocation(mProgram, &desc.name.c_str()[1]); + + AssertFatal(loc != -1, ""); HandleMap::Iterator handle = mHandles.find(desc.name); - S32 sampler = (desc.constType == GFXSCT_Sampler || desc.constType == GFXSCT_SamplerCube) ? - assignedSamplerNum++ : -1; + S32 sampler = -1; + if(desc.constType == GFXSCT_Sampler || desc.constType == GFXSCT_SamplerCube) + { + S32 idx = mSamplerNamesOrdered.find_next(desc.name); + AssertFatal(idx != -1, ""); + sampler = idx; //assignedSamplerNum++; + } if ( handle != mHandles.end() ) { handle->value->reinit( desc, loc, sampler ); @@ -599,10 +652,69 @@ void GFXGLShader::initHandles() // Set sampler number on our program. glUniform1i(handle->mLocation, handle->mSamplerNum); // Set sampler in constant buffer so it does not get unset later. - dMemcpy(mConstBuffer + handle->mOffset, &handle->mLocation, handle->getSize()); + dMemcpy(mConstBuffer + handle->mOffset, &handle->mSamplerNum, handle->getSize()); } } glUseProgram(0); + + //instancing + U32 offset = 0; + for ( U32 i=0; i < mInstancingFormat.getElementCount(); i++ ) + { + const GFXVertexElement &element = mInstancingFormat.getElement( i ); + + String constName = String::ToString( "$%s", element.getSemantic().c_str() ); + + HandleMap::Iterator handle = mHandles.find(constName); + if ( handle != mHandles.end() ) + { + AssertFatal(0, ""); + } + else + { + GFXShaderConstDesc desc; + desc.name = constName; + desc.arraySize = 1; + switch(element.getType()) + { + case GFXDeclType_Float4: + desc.constType = GFXSCT_Float4; + break; + + default: + desc.constType = GFXSCT_Float; + break; + } + + GFXGLShaderConstHandle *h = new GFXGLShaderConstHandle( this, desc, -1, -1 ); + h->mInstancingConstant = true; + h->mOffset = offset; + mHandles[constName] = h; + + offset += element.getSizeInBytes(); + ++i; + + // If this is a matrix we will have 2 or 3 more of these + // semantics with the same name after it. + for ( ; i < mInstancingFormat.getElementCount(); i++ ) + { + const GFXVertexElement &nextElement = mInstancingFormat.getElement( i ); + if ( nextElement.getSemantic() != element.getSemantic() ) + { + i--; + break; + } + ++desc.arraySize; + if(desc.arraySize == 4 && desc.constType == GFXSCT_Float4) + { + desc.arraySize = 1; + desc.constType = GFXSCT_Float4x4; + } + offset += nextElement.getSizeInBytes(); + } + } + + } } GFXShaderConstHandle* GFXGLShader::getShaderConstHandle(const String& name) @@ -619,12 +731,26 @@ GFXShaderConstHandle* GFXGLShader::getShaderConstHandle(const String& name) } } +GFXShaderConstHandle* GFXGLShader::findShaderConstHandle(const String& name) +{ + HandleMap::Iterator i = mHandles.find(name); + if(i != mHandles.end()) + return i->value; + else + { + return NULL; + } +} + void GFXGLShader::setConstantsFromBuffer(GFXGLShaderConstBuffer* buffer) { for(Vector::iterator i = mValidHandles.begin(); i != mValidHandles.end(); ++i) { GFXGLShaderConstHandle* handle = *i; AssertFatal(handle, "GFXGLShader::setConstantsFromBuffer - Null handle"); + + if(handle->mInstancingConstant) + continue; // Don't set if the value has not be changed. if(dMemcmp(mConstBuffer + handle->mOffset, buffer->mBuffer + handle->mOffset, handle->getSize()) == 0) @@ -669,6 +795,9 @@ void GFXGLShader::setConstantsFromBuffer(GFXGLShaderConstBuffer* buffer) case GFXSCT_Float4x4: glUniformMatrix4fv(handle->mLocation, handle->mDesc.arraySize, true, (GLfloat*)(mConstBuffer + handle->mOffset)); break; + default: + AssertFatal(0,""); + break; } } } @@ -813,13 +942,34 @@ bool GFXGLShader::_loadShaderFromStream( GLuint shader, Vector lengths; // The GLSL version declaration must go first! - const char *versionDecl = "#version 120\r\n\r\n"; + const char *versionDecl = "#version 150\r\n"; buffers.push_back( dStrdup( versionDecl ) ); lengths.push_back( dStrlen( versionDecl ) ); + if(gglHasExtension(EXT_gpu_shader4)) + { + const char *extension = "#extension GL_EXT_gpu_shader4 : enable\r\n"; + buffers.push_back( dStrdup( extension ) ); + lengths.push_back( dStrlen( extension ) ); + } + + if(gglHasExtension(ARB_gpu_shader5)) + { + const char *extension = "#extension GL_ARB_gpu_shader5 : enable\r\n"; + buffers.push_back( dStrdup( extension ) ); + lengths.push_back( dStrlen( extension ) ); + } + + const char *newLine = "\r\n"; + buffers.push_back( dStrdup( newLine ) ); + lengths.push_back( dStrlen( newLine ) ); + // Now add all the macros. for( U32 i = 0; i < macros.size(); i++ ) { + if(macros[i].name.isEmpty()) // TODO OPENGL + continue; + String define = String::ToString( "#define %s %s\n", macros[i].name.c_str(), macros[i].value.c_str() ); buffers.push_back( dStrdup( define.c_str() ) ); lengths.push_back( define.length() ); @@ -836,6 +986,17 @@ bool GFXGLShader::_loadShaderFromStream( GLuint shader, glShaderSource(shader, buffers.size(), (const GLchar**)const_cast(buffers.address()), NULL); +#if defined(TORQUE_DEBUG) && defined(TORQUE_DEBUG_GFX) + FileStream stream; + if ( !stream.open( path.getFullPath()+"_DEBUG", Torque::FS::File::Write ) ) + { + AssertISV(false, avar("GFXGLShader::initShader - failed to write debug shader '%s'.", path.getFullPath().c_str())); + } + + for(int i = 0; i < buffers.size(); ++i) + stream.writeText(buffers[i]); +#endif + // Cleanup the shader source buffer. for ( U32 i=0; i < buffers.size(); i++ ) dFree( buffers[i] ); diff --git a/Engine/source/gfx/gl/gfxGLShader.h b/Engine/source/gfx/gl/gfxGLShader.h index a8efd4e02..d87f4843e 100644 --- a/Engine/source/gfx/gl/gfxGLShader.h +++ b/Engine/source/gfx/gl/gfxGLShader.h @@ -25,7 +25,7 @@ #include "core/util/refBase.h" #include "gfx/gfxShader.h" -#include "gfx/gl/ggl/ggl.h" +#include "gfx/gl/tGL/tGL.h" #include "core/util/tSignal.h" #include "core/util/tDictionary.h" @@ -43,6 +43,7 @@ public: /// @name GFXShader interface /// @{ virtual GFXShaderConstHandle* getShaderConstHandle(const String& name); + virtual GFXShaderConstHandle* findShaderConstHandle(const String& name); /// Returns our list of shader constants, the material can get this and just set the constants it knows about virtual const Vector& getShaderConstDesc() const; diff --git a/Engine/source/gfx/gl/gfxGLStateBlock.cpp b/Engine/source/gfx/gl/gfxGLStateBlock.cpp index b6fb99f72..a1af2910c 100644 --- a/Engine/source/gfx/gl/gfxGLStateBlock.cpp +++ b/Engine/source/gfx/gl/gfxGLStateBlock.cpp @@ -25,12 +25,47 @@ #include "gfx/gl/gfxGLEnumTranslate.h" #include "gfx/gl/gfxGLUtils.h" #include "gfx/gl/gfxGLTextureObject.h" +#include "core/crc.h" +namespace DictHash +{ + inline U32 hash(const GFXSamplerStateDesc &data) + { + return CRC::calculateCRC(&data, sizeof(GFXSamplerStateDesc));; + } +} GFXGLStateBlock::GFXGLStateBlock(const GFXStateBlockDesc& desc) : mDesc(desc), mCachedHashValue(desc.getHashValue()) { + if( !gglHasExtension(ARB_sampler_objects) ) + return; + + static Map mSamplersMap; + + for(int i = 0; i < TEXTURE_STAGE_COUNT; ++i) + { + GLuint &id = mSamplerObjects[i]; + GFXSamplerStateDesc &ssd = mDesc.samplers[i]; + Map::Iterator itr = mSamplersMap.find(ssd); + if(itr == mSamplersMap.end()) + { + glGenSamplers(1, &id); + + glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, minificationFilter(ssd.minFilter, ssd.mipFilter, 1) ); + glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, GFXGLTextureFilter[ssd.magFilter]); + glSamplerParameteri(id, GL_TEXTURE_WRAP_S, GFXGLTextureAddress[ssd.addressModeU]); + glSamplerParameteri(id, GL_TEXTURE_WRAP_T, GFXGLTextureAddress[ssd.addressModeV]); + glSamplerParameteri(id, GL_TEXTURE_WRAP_R, GFXGLTextureAddress[ssd.addressModeW]); + if(static_cast< GFXGLDevice* >( GFX )->supportsAnisotropic() ) + glSamplerParameterf(id, GL_TEXTURE_MAX_ANISOTROPY_EXT, ssd.maxAnisotropy); + + mSamplersMap[ssd] = id; + } + else + id = itr->value; + } } GFXGLStateBlock::~GFXGLStateBlock() @@ -72,11 +107,6 @@ void GFXGLStateBlock::activate(const GFXGLStateBlock* oldState) if(STATE_CHANGE(blendOp)) glBlendEquation(GFXGLBlendOp[mDesc.blendOp]); - // Alpha testing - CHECK_TOGGLE_STATE(alphaTestEnable, GL_ALPHA_TEST); - if(STATE_CHANGE(alphaTestFunc) || STATE_CHANGE(alphaTestRef)) - glAlphaFunc(GFXGLCmpFunc[mDesc.alphaTestFunc], (F32) mDesc.alphaTestRef * 1.0f/255.0f); - // Color write masks if(STATE_CHANGE(colorWriteRed) || STATE_CHANGE(colorWriteBlue) || STATE_CHANGE(colorWriteGreen) || STATE_CHANGE(colorWriteAlpha)) glColorMask(mDesc.colorWriteRed, mDesc.colorWriteBlue, mDesc.colorWriteGreen, mDesc.colorWriteAlpha); @@ -117,12 +147,7 @@ void GFXGLStateBlock::activate(const GFXGLStateBlock* oldState) glStencilOp(GFXGLStencilOp[mDesc.stencilFailOp], GFXGLStencilOp[mDesc.stencilZFailOp], GFXGLStencilOp[mDesc.stencilPassOp]); if(STATE_CHANGE(stencilWriteMask)) glStencilMask(mDesc.stencilWriteMask); - - // "Misc" - CHECK_TOGGLE_STATE(ffLighting, GL_LIGHTING); - - glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); - CHECK_TOGGLE_STATE(vertexColorEnable, GL_COLOR_MATERIAL); + if(STATE_CHANGE(fillMode)) glPolygonMode(GL_FRONT_AND_BACK, GFXGLFillMode[mDesc.fillMode]); @@ -131,57 +156,15 @@ void GFXGLStateBlock::activate(const GFXGLStateBlock* oldState) #undef TOGGLE_STATE #undef CHECK_TOGGLE_STATE - // TODO: states added for detail blend - - // Non per object texture mode states - for (U32 i = 0; i < getMin(getOwningDevice()->getNumSamplers(), (U32) TEXTURE_STAGE_COUNT); i++) + //sampler objects + if( gglHasExtension(ARB_sampler_objects) ) { - GFXGLTextureObject* tex = static_cast(getOwningDevice()->getCurrentTexture(i)); - const GFXSamplerStateDesc &ssd = mDesc.samplers[i]; - bool updateTexParam = true; - glActiveTexture(GL_TEXTURE0 + i); - switch (ssd.textureColorOp) + for (U32 i = 0; i < getMin(getOwningDevice()->getNumSamplers(), (U32) TEXTURE_STAGE_COUNT); i++) { - case GFXTOPDisable : - if(!tex) - break; - glDisable(GL_TEXTURE_2D); - updateTexParam = false; - break; - case GFXTOPModulate : - glEnable(GL_TEXTURE_2D); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - break; - case GFXTOPAdd : - glEnable(GL_TEXTURE_2D); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD); - break; - default : - glEnable(GL_TEXTURE_2D); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - break; + if(!oldState || oldState->mSamplerObjects[i] != mSamplerObjects[i]) + glBindSampler(i, mSamplerObjects[i] ); } + } -#define SSF(state, enum, value, tex) if(!oldState || oldState->mDesc.samplers[i].state != mDesc.samplers[i].state) glTexParameteri(tex->getBinding(), enum, value) -#define SSW(state, enum, value, tex) if(!oldState || oldState->mDesc.samplers[i].state != mDesc.samplers[i].state) glTexParameteri(tex->getBinding(), enum, !tex->mIsNPoT2 ? value : GL_CLAMP_TO_EDGE) - // Per object texture mode states. - // TODO: Check dirty flag of samplers[i] and don't do this if it's dirty (it'll happen in the texture bind) - if (updateTexParam && tex) - { - SSF(minFilter, GL_TEXTURE_MIN_FILTER, minificationFilter(ssd.minFilter, ssd.mipFilter, tex->mMipLevels), tex); - SSF(mipFilter, GL_TEXTURE_MIN_FILTER, minificationFilter(ssd.minFilter, ssd.mipFilter, tex->mMipLevels), tex); - SSF(magFilter, GL_TEXTURE_MAG_FILTER, GFXGLTextureFilter[ssd.magFilter], tex); - SSW(addressModeU, GL_TEXTURE_WRAP_S, GFXGLTextureAddress[ssd.addressModeU], tex); - SSW(addressModeV, GL_TEXTURE_WRAP_T, GFXGLTextureAddress[ssd.addressModeV], tex); - - if( ( !oldState || oldState->mDesc.samplers[i].maxAnisotropy != ssd.maxAnisotropy ) && - static_cast< GFXGLDevice* >( GFX )->supportsAnisotropic() ) - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, ssd.maxAnisotropy); - - if( ( !oldState || oldState->mDesc.samplers[i].mipLODBias != ssd.mipLODBias ) ) - glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, ssd.mipLODBias); - } - } -#undef SSF -#undef SSW + // TODO: states added for detail blend } diff --git a/Engine/source/gfx/gl/gfxGLStateBlock.h b/Engine/source/gfx/gl/gfxGLStateBlock.h index 2e7e793ae..234b3fd56 100644 --- a/Engine/source/gfx/gl/gfxGLStateBlock.h +++ b/Engine/source/gfx/gl/gfxGLStateBlock.h @@ -25,6 +25,11 @@ #include "gfx/gfxStateBlock.h" +namespace DictHash +{ + U32 hash(const GFXSamplerStateDesc &data); +} + class GFXGLStateBlock : public GFXStateBlock { public: @@ -58,6 +63,7 @@ public: private: GFXStateBlockDesc mDesc; U32 mCachedHashValue; + U32 mSamplerObjects[TEXTURE_STAGE_COUNT]; }; typedef StrongRefPtr GFXGLStateBlockRef; diff --git a/Engine/source/gfx/gl/gfxGLStateCache.h b/Engine/source/gfx/gl/gfxGLStateCache.h new file mode 100644 index 000000000..172072983 --- /dev/null +++ b/Engine/source/gfx/gl/gfxGLStateCache.h @@ -0,0 +1,133 @@ +#ifndef GFX_GL_STATE_CACHE +#define GFX_GL_STATE_CACHE + + +/// GFXGLStateCache store OpenGL state to avoid performance penalities of glGet* calls +/// GL_TEXTURE_1D/2D/3D, GL_FRAMEBUFFER, GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER +class GFXGLStateCache +{ +public: + GFXGLStateCache() + { + mActiveTexture = 0; + mBindedVBO = 0; + mBindedIBO = 0; + mBindedFBO_W = 0; + mBindedFBO_R = 0; + mVertexAttribActive = 0; + } + + class TextureUnit + { + public: + TextureUnit() : mTexture1D(0), mTexture2D(0), mTexture3D(0), mTextureCube(0) + { + + } + GLuint mTexture1D, mTexture2D, mTexture3D, mTextureCube; + }; + + /// after glBindTexture + void setCacheBindedTex(U32 texUnit, GLenum biding, GLuint handle) + { + mActiveTexture = texUnit; + switch (biding) + { + case GL_TEXTURE_2D: + mTextureUnits[mActiveTexture].mTexture2D = handle; + break; + case GL_TEXTURE_3D: + mTextureUnits[mActiveTexture].mTexture3D = handle; + break; + case GL_TEXTURE_1D: + mTextureUnits[mActiveTexture].mTexture1D = handle; + break; + case GL_TEXTURE_CUBE_MAP: + mTextureUnits[mActiveTexture].mTextureCube = handle; + break; + default: + AssertFatal(0, avar("GFXGLStateCache::setCacheBindedTex - binding (%x) not supported.", biding) ); + return; + } + } + + /// after opengl object binded + void setCacheBinded(GLenum biding, GLuint handle) + { + switch (biding) + { + case GL_TEXTURE_2D: + mTextureUnits[mActiveTexture].mTexture2D = handle; + break; + case GL_TEXTURE_3D: + mTextureUnits[mActiveTexture].mTexture3D = handle; + break; + case GL_TEXTURE_1D: + mTextureUnits[mActiveTexture].mTexture1D = handle; + break; + case GL_TEXTURE_CUBE_MAP: + mTextureUnits[mActiveTexture].mTextureCube = handle; + break; + case GL_FRAMEBUFFER: + mBindedFBO_W = mBindedFBO_R = handle; + break; + case GL_DRAW_FRAMEBUFFER: + mBindedFBO_W = handle; + break; + case GL_READ_FRAMEBUFFER: + mBindedFBO_R = handle; + break; + case GL_ARRAY_BUFFER: + mBindedVBO = handle; + break; + case GL_ELEMENT_ARRAY_BUFFER: + mBindedIBO = handle; + break; + default: + AssertFatal(0, avar("GFXGLStateCache::setCacheBinded - binding (%x) not supported.", biding) ); + break; + } + } + + GLuint getCacheBinded(GLenum biding) const + { + switch (biding) + { + case GL_TEXTURE_2D: + return mTextureUnits[mActiveTexture].mTexture2D; + case GL_TEXTURE_3D: + return mTextureUnits[mActiveTexture].mTexture3D; + case GL_TEXTURE_1D: + return mTextureUnits[mActiveTexture].mTexture1D; + case GL_TEXTURE_CUBE_MAP: + return mTextureUnits[mActiveTexture].mTextureCube; + case GL_DRAW_FRAMEBUFFER: + return mBindedFBO_W; + case GL_READ_FRAMEBUFFER: + return mBindedFBO_R; + case GL_ARRAY_BUFFER: + return mBindedVBO; + case GL_ELEMENT_ARRAY_BUFFER: + return mBindedIBO; + default: + AssertFatal(0, avar("GFXGLStateCache::getCacheBinded - binding (%x) not supported.", biding) ); + return 0; + } + } + + /// after glActiveTexture + void setCacheActiveTexture(U32 unit) { mActiveTexture = unit; } + U32 getCacheActiveTexture() const { return mActiveTexture; } + + /// for cache glEnableVertexAttribArray / glDisableVertexAttribArray + void setCacheVertexAttribActive(U32 activeMask) { mVertexAttribActive = activeMask; } + U32 getCacheVertexAttribActive() const { return mVertexAttribActive; } + +protected: + GLuint mActiveTexture, mBindedVBO, mBindedIBO, mBindedFBO_W, mBindedFBO_R; + TextureUnit mTextureUnits[TEXTURE_STAGE_COUNT]; + U32 mVertexAttribActive; +}; + + +#endif \ No newline at end of file diff --git a/Engine/source/gfx/gl/gfxGLTextureManager.cpp b/Engine/source/gfx/gl/gfxGLTextureManager.cpp index f2bc4de0b..70a5e4303 100644 --- a/Engine/source/gfx/gl/gfxGLTextureManager.cpp +++ b/Engine/source/gfx/gl/gfxGLTextureManager.cpp @@ -65,6 +65,7 @@ GFXTextureObject *GFXGLTextureManager::_createTextureObject( U32 height, AssertFatal( dynamic_cast( inTex ), "GFXGLTextureManager::_createTexture() - Bad inTex type!" ); retTex = static_cast( inTex ); retTex->release(); + retTex->reInit(); } else { @@ -98,23 +99,20 @@ void GFXGLTextureManager::innerCreateTexture( GFXGLTextureObject *retTex, retTex->mIsZombie = false; retTex->mIsNPoT2 = false; - GLenum binding = (depth == 0) ? GL_TEXTURE_2D : GL_TEXTURE_3D; + GLenum binding = ( (height == 1 || width == 1) && ( height != width ) ) ? GL_TEXTURE_1D : ( (depth == 0) ? GL_TEXTURE_2D : GL_TEXTURE_3D ); if((profile->testFlag(GFXTextureProfile::RenderTarget) || profile->testFlag(GFXTextureProfile::ZTarget)) && (!isPow2(width) || !isPow2(height)) && !depth) retTex->mIsNPoT2 = true; retTex->mBinding = binding; // Bind it - glActiveTexture(GL_TEXTURE0); - PRESERVE_2D_TEXTURE(); - PRESERVE_3D_TEXTURE(); - glBindTexture(binding, retTex->getHandle()); + PRESERVE_TEXTURE(binding); + glBindTexture(retTex->getBinding(), retTex->getHandle()); // Create it - // TODO: Reenable mipmaps on render targets when Apple fixes their drivers - if(forceMips && !retTex->mIsNPoT2) + // @todo OPENGL - Creating mipmaps for compressed formats. Not supported on OpenGL ES and bugged on AMD. We use mipmaps present on file. + if( forceMips && !retTex->mIsNPoT2 && !isCompressedFormat(format) ) { - glTexParameteri(binding, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); - retTex->mMipLevels = 0; + retTex->mMipLevels = numMipLevels > 1 ? numMipLevels : 0; } else if(profile->testFlag(GFXTextureProfile::NoMipmap) || profile->testFlag(GFXTextureProfile::RenderTarget) || numMipLevels == 1 || retTex->mIsNPoT2) { @@ -122,10 +120,11 @@ void GFXGLTextureManager::innerCreateTexture( GFXGLTextureObject *retTex, } else { - glTexParameteri(binding, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); - retTex->mMipLevels = 0; + retTex->mMipLevels = numMipLevels; } + // @todo OPENGL - OpenGL ES2 not support mipmaps on NPOT textures +#if 0 if(!retTex->mIsNPoT2) { if(!isPow2(width)) @@ -135,23 +134,82 @@ void GFXGLTextureManager::innerCreateTexture( GFXGLTextureObject *retTex, if(depth && !isPow2(depth)) depth = getNextPow2(depth); } +#endif AssertFatal(GFXGLTextureInternalFormat[format] != GL_ZERO, "GFXGLTextureManager::innerCreateTexture - invalid internal format"); AssertFatal(GFXGLTextureFormat[format] != GL_ZERO, "GFXGLTextureManager::innerCreateTexture - invalid format"); AssertFatal(GFXGLTextureType[format] != GL_ZERO, "GFXGLTextureManager::innerCreateTexture - invalid type"); - - if(binding != GL_TEXTURE_3D) - glTexImage2D(binding, 0, GFXGLTextureInternalFormat[format], width, height, 0, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL); - else - glTexImage3D(GL_TEXTURE_3D, 0, GFXGLTextureInternalFormat[format], width, height, depth, 0, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL); + + //calculate num mipmaps + if(retTex->mMipLevels == 0) + retTex->mMipLevels = getMaxMipmaps(width, height, 1); + + glTexParameteri(binding, GL_TEXTURE_MAX_LEVEL, retTex->mMipLevels-1 ); + + if( gglHasExtension(ARB_texture_storage) ) + { + if(binding == GL_TEXTURE_2D) + glTexStorage2D( retTex->getBinding(), retTex->mMipLevels, GFXGLTextureInternalFormat[format], width, height ); + else if(binding == GL_TEXTURE_1D) + glTexStorage1D( retTex->getBinding(), retTex->mMipLevels, GFXGLTextureInternalFormat[format], getMax(width, height) ); + else + glTexStorage3D( retTex->getBinding(), retTex->mMipLevels, GFXGLTextureInternalFormat[format], width, height, depth ); + } + else + { + //If it wasn't for problems on amd drivers this next part could be really simplified and we wouldn't need to go through manually creating our + //mipmap pyramid and instead just use glGenerateMipmap + if(isCompressedFormat(format)) + { + AssertFatal(binding == GL_TEXTURE_2D, + "GFXGLTextureManager::innerCreateTexture - Only compressed 2D textures are supported"); + + U32 tempWidth = width; + U32 tempHeight = height; + U32 size = getCompressedSurfaceSize(format,height,width); + //Fill compressed images with 0's + U8 *pTemp = (U8*)dMalloc(sizeof(U8)*size); + dMemset(pTemp,0,size); + + for(U32 i=0;i< retTex->mMipLevels;i++) + { + tempWidth = getMax( U32(1), width >> i ); + tempHeight = getMax( U32(1), height >> i ); + size = getCompressedSurfaceSize(format,width,height,i); + glCompressedTexImage2D(binding,i,GFXGLTextureInternalFormat[format],tempWidth,tempHeight,0,size,pTemp); + } + + dFree(pTemp); + } + else + { + if(binding == GL_TEXTURE_2D) + glTexImage2D(binding, 0, GFXGLTextureInternalFormat[format], width, height, 0, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL); + else if(binding == GL_TEXTURE_1D) + glTexImage1D(binding, 0, GFXGLTextureInternalFormat[format], (width > 1 ? width : height), 0, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL); + else + glTexImage3D(GL_TEXTURE_3D, 0, GFXGLTextureInternalFormat[format], width, height, depth, 0, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL); + + if(retTex->mMipLevels > 1) + glGenerateMipmap(binding); + } + } // Complete the texture - glTexParameteri(binding, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + // Complete the texture - this does get changed later but we need to complete the texture anyway + + if(retTex->mMipLevels == 1) + glTexParameteri(binding, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + else + glTexParameteri(binding, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(binding, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(binding, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(binding, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); if(binding == GL_TEXTURE_3D) glTexParameteri(binding, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + if(GFXGLTextureSwizzle[format]) + glTexParameteriv(binding, GL_TEXTURE_SWIZZLE_RGBA, GFXGLTextureSwizzle[format]); // Get the size from GL (you never know...) GLint texHeight, texWidth, texDepth = 0; @@ -173,49 +231,60 @@ static void _fastTextureLoad(GFXGLTextureObject* texture, GBitmap* pDL) glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, texture->getBuffer()); U32 bufSize = pDL->getWidth(0) * pDL->getHeight(0) * pDL->getBytesPerPixel(); glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, bufSize, NULL, GL_STREAM_DRAW); - U8* pboMemory = (U8*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY); if(pDL->getFormat() == GFXFormatR8G8B8A8 || pDL->getFormat() == GFXFormatR8G8B8X8) + { + FrameAllocatorMarker mem; + U8* pboMemory = (U8*)mem.alloc(bufSize); GFX->getDeviceSwizzle32()->ToBuffer(pboMemory, pDL->getBits(0), bufSize); + glBufferSubData(GL_PIXEL_UNPACK_BUFFER_ARB, 0, bufSize, pboMemory ); + } else - dMemcpy(pboMemory, pDL->getBits(0), bufSize); + { + glBufferSubData(GL_PIXEL_UNPACK_BUFFER_ARB, 0, bufSize, pDL->getBits(0) ); + } - glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB); - - glTexSubImage2D(texture->getBinding(), 0, 0, 0, pDL->getWidth(0), pDL->getHeight(0), GFXGLTextureFormat[pDL->getFormat()], GFXGLTextureType[pDL->getFormat()], NULL); + if(texture->getBinding() == GL_TEXTURE_2D) + glTexSubImage2D(texture->getBinding(), 0, 0, 0, pDL->getWidth(0), pDL->getHeight(0), GFXGLTextureFormat[pDL->getFormat()], GFXGLTextureType[pDL->getFormat()], NULL); + else + glTexSubImage1D(texture->getBinding(), 0, 0, (pDL->getWidth(0) > 1 ? pDL->getWidth(0) : pDL->getHeight(0)), GFXGLTextureFormat[pDL->getFormat()], GFXGLTextureType[pDL->getFormat()], NULL); glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); } static void _slowTextureLoad(GFXGLTextureObject* texture, GBitmap* pDL) { - glTexSubImage2D(texture->getBinding(), 0, 0, 0, pDL->getWidth(0), pDL->getHeight(0), GFXGLTextureFormat[pDL->getFormat()], GFXGLTextureType[pDL->getFormat()], pDL->getBits(0)); + if(texture->getBinding() == GL_TEXTURE_2D) + glTexSubImage2D(texture->getBinding(), 0, 0, 0, pDL->getWidth(0), pDL->getHeight(0), GFXGLTextureFormat[pDL->getFormat()], GFXGLTextureType[pDL->getFormat()], pDL->getBits(0)); + else + glTexSubImage1D(texture->getBinding(), 0, 0, (pDL->getWidth(0) > 1 ? pDL->getWidth(0) : pDL->getHeight(0)), GFXGLTextureFormat[pDL->getFormat()], GFXGLTextureType[pDL->getFormat()], pDL->getBits(0)); } bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, GBitmap *pDL) { GFXGLTextureObject *texture = static_cast(aTexture); - AssertFatal(texture->getBinding() == GL_TEXTURE_2D, - "GFXGLTextureManager::_loadTexture(GBitmap) - This method can only be used with 2D textures"); + AssertFatal(texture->getBinding() == GL_TEXTURE_1D || texture->getBinding() == GL_TEXTURE_2D, + "GFXGLTextureManager::_loadTexture(GBitmap) - This method can only be used with 1D/2D textures"); - if(texture->getBinding() != GL_TEXTURE_2D) + if(texture->getBinding() == GL_TEXTURE_3D) return false; // No 24bit formats. if(pDL->getFormat() == GFXFormatR8G8B8) pDL->setFormat(GFXFormatR8G8B8A8); // Bind to edit - glActiveTexture(GL_TEXTURE0); - PRESERVE_2D_TEXTURE(); + PRESERVE_TEXTURE(texture->getBinding()); glBindTexture(texture->getBinding(), texture->getHandle()); - + + texture->mFormat = pDL->getFormat(); if(pDL->getFormat() == GFXFormatR8G8B8A8 || pDL->getFormat() == GFXFormatR8G8B8X8) _fastTextureLoad(texture, pDL); else _slowTextureLoad(texture, pDL); - - glBindTexture(texture->getBinding(), 0); + + if(texture->getMipLevels() != 1) + glGenerateMipmap(texture->getBinding()); return true; } @@ -231,15 +300,15 @@ bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, DDSFile *dds) if(texture->getBinding() != GL_TEXTURE_2D) return false; - glActiveTexture(GL_TEXTURE0); - PRESERVE_2D_TEXTURE(); + PRESERVE_TEXTURE(texture->getBinding()); glBindTexture(texture->getBinding(), texture->getHandle()); + texture->mFormat = dds->mFormat; U32 numMips = dds->mSurfaces[0]->mMips.size(); if(GFX->getCardProfiler()->queryProfile("GL::Workaround::noManualMips")) numMips = 1; for(U32 i = 0; i < numMips; i++) { - if(dds->mFormat == GFXFormatDXT1 || dds->mFormat == GFXFormatDXT3 || dds->mFormat == GFXFormatDXT5) + if(isCompressedFormat(dds->mFormat)) { if((!isPow2(dds->getWidth()) || !isPow2(dds->getHeight())) && GFX->getCardProfiler()->queryProfile("GL::Workaround::noCompressedNPoTTextures")) { @@ -266,7 +335,9 @@ bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, DDSFile *dds) else glTexSubImage2D(texture->getBinding(), i, 0, 0, dds->getWidth(i), dds->getHeight(i), GFXGLTextureFormat[dds->mFormat], GFXGLTextureType[dds->mFormat], dds->mSurfaces[0]->mMips[i]); } - glBindTexture(texture->getBinding(), 0); + + if(numMips !=1 && !isCompressedFormat(dds->mFormat)) + glGenerateMipmap(texture->getBinding()); return true; } @@ -278,11 +349,9 @@ bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, void *raw) GFXGLTextureObject* texture = static_cast(aTexture); - glActiveTexture(GL_TEXTURE0); PRESERVE_3D_TEXTURE(); - glBindTexture(GL_TEXTURE_3D, texture->getHandle()); + glBindTexture(texture->getBinding(), texture->getHandle()); glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, texture->getWidth(), texture->getHeight(), texture->getDepth(), GFXGLTextureFormat[texture->mFormat], GFXGLTextureType[texture->mFormat], raw); - glBindTexture(GL_TEXTURE_3D, 0); return true; } diff --git a/Engine/source/gfx/gl/gfxGLTextureManager.h b/Engine/source/gfx/gl/gfxGLTextureManager.h index 5ad7ac29a..30f4ce1c6 100644 --- a/Engine/source/gfx/gl/gfxGLTextureManager.h +++ b/Engine/source/gfx/gl/gfxGLTextureManager.h @@ -26,7 +26,7 @@ #include "gfx/gfxDevice.h" #include "gfx/gfxTextureManager.h" #include "gfx/gl/gfxGLTextureObject.h" -#include "gfx/gl/ggl/ggl.h" +#include "gfx/gl/tGL/tGL.h" class GFXGLTextureManager : public GFXTextureManager { diff --git a/Engine/source/gfx/gl/gfxGLTextureObject.cpp b/Engine/source/gfx/gl/gfxGLTextureObject.cpp index eaf76ba80..423899f70 100644 --- a/Engine/source/gfx/gl/gfxGLTextureObject.cpp +++ b/Engine/source/gfx/gl/gfxGLTextureObject.cpp @@ -21,7 +21,7 @@ //----------------------------------------------------------------------------- #include "console/console.h" -#include "gfx/gl/ggl/ggl.h" +#include "gfx/gl/tGL/tGL.h" #include "math/mRect.h" #include "gfx/gl/gfxGLTextureObject.h" #include "gfx/gfxDevice.h" @@ -37,7 +37,10 @@ GFXGLTextureObject::GFXGLTextureObject(GFXDevice * aDevice, GFXTextureProfile *p mBytesPerTexel(4), mLockedRectRect(0, 0, 0, 0), mGLDevice(static_cast(mDevice)), - mZombieCache(NULL) + mZombieCache(NULL), + mNeedInitSamplerState(true), + mFrameAllocatorMark(0), + mFrameAllocatorPtr(NULL) { AssertFatal(dynamic_cast(mDevice), "GFXGLTextureObject::GFXGLTextureObject - Invalid device type, expected GFXGLDevice!"); glGenTextures(1, &mHandle); @@ -46,6 +49,7 @@ GFXGLTextureObject::GFXGLTextureObject(GFXDevice * aDevice, GFXTextureProfile *p GFXGLTextureObject::~GFXGLTextureObject() { + glDeleteTextures(1, &mHandle); glDeleteBuffers(1, &mBuffer); delete[] mZombieCache; kill(); @@ -70,12 +74,16 @@ GFXLockedRect* GFXGLTextureObject::lock(U32 mipLevel, RectI *inRect) } mLockedRect.pitch = mLockedRectRect.extent.x * mBytesPerTexel; - - glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, mBuffer); + // CodeReview [ags 12/19/07] This one texel boundary is necessary to keep the clipmap code from crashing. Figure out why. - glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, (mLockedRectRect.extent.x + 1) * (mLockedRectRect.extent.y + 1) * mBytesPerTexel, NULL, GL_STREAM_DRAW); - mLockedRect.bits = (U8*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); + U32 size = (mLockedRectRect.extent.x + 1) * (mLockedRectRect.extent.y + 1) * mBytesPerTexel; + AssertFatal(!mFrameAllocatorMark && !mFrameAllocatorPtr, ""); + mFrameAllocatorMark = FrameAllocator::getWaterMark(); + mFrameAllocatorPtr = (U8*)FrameAllocator::alloc( size ); + mLockedRect.bits = mFrameAllocatorPtr; +#if TORQUE_DEBUG + mFrameAllocatorMarkGuard = FrameAllocator::getWaterMark(); +#endif if( !mLockedRect.bits ) return NULL; @@ -88,20 +96,27 @@ void GFXGLTextureObject::unlock(U32 mipLevel) if(!mLockedRect.bits) return; - glActiveTexture(GL_TEXTURE0); - U32 boundTexture; - glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&boundTexture); - - glBindTexture(GL_TEXTURE_2D, mHandle); + PRESERVE_TEXTURE(mBinding); + glBindTexture(mBinding, mHandle); glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, mBuffer); - glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB); - glTexSubImage2D(GL_TEXTURE_2D, mipLevel, mLockedRectRect.point.x, mLockedRectRect.point.y, - mLockedRectRect.extent.x, mLockedRectRect.extent.y, GL_BGRA, GL_UNSIGNED_BYTE, NULL); + glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, (mLockedRectRect.extent.x + 1) * (mLockedRectRect.extent.y + 1) * mBytesPerTexel, mFrameAllocatorPtr, GL_STREAM_DRAW); + + if(mBinding == GL_TEXTURE_2D) + glTexSubImage2D(mBinding, mipLevel, mLockedRectRect.point.x, mLockedRectRect.point.y, + mLockedRectRect.extent.x, mLockedRectRect.extent.y, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], NULL); + else if(mBinding == GL_TEXTURE_1D) + glTexSubImage1D(mBinding, mipLevel, (mLockedRectRect.point.x > 1 ? mLockedRectRect.point.x : mLockedRectRect.point.y), + (mLockedRectRect.extent.x > 1 ? mLockedRectRect.extent.x : mLockedRectRect.extent.y), GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], NULL); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); mLockedRect.bits = NULL; - - glBindTexture(GL_TEXTURE_2D, boundTexture); +#if TORQUE_DEBUG + AssertFatal(mFrameAllocatorMarkGuard == FrameAllocator::getWaterMark(), ""); +#endif + FrameAllocator::setWaterMark(mFrameAllocatorMark); + mFrameAllocatorMark = 0; + mFrameAllocatorPtr = NULL; } void GFXGLTextureObject::release() @@ -113,28 +128,91 @@ void GFXGLTextureObject::release() mBuffer = 0; } +void GFXGLTextureObject::reInit() +{ + AssertFatal(!mHandle && !mBuffer,"Must release before reInit"); + glGenTextures(1, &mHandle); + glGenBuffers(1, &mBuffer); +} + bool GFXGLTextureObject::copyToBmp(GBitmap * bmp) { - GLint oldTex; - glGetIntegerv(0x8069, &oldTex); - glBindTexture(GL_TEXTURE_2D, mHandle); + if (!bmp) + return false; + + // check format limitations + // at the moment we only support RGBA for the source (other 4 byte formats should + // be easy to add though) + AssertFatal(mFormat == GFXFormatR8G8B8A8, "GFXGLTextureObject::copyToBmp - invalid format"); + AssertFatal(bmp->getFormat() == GFXFormatR8G8B8A8 || bmp->getFormat() == GFXFormatR8G8B8, "GFXGLTextureObject::copyToBmp - invalid format"); + if(mFormat != GFXFormatR8G8B8A8) + return false; + + if(bmp->getFormat() != GFXFormatR8G8B8A8 && bmp->getFormat() != GFXFormatR8G8B8) + return false; + + AssertFatal(bmp->getWidth() == getWidth(), "GFXGLTextureObject::copyToBmp - invalid size"); + AssertFatal(bmp->getHeight() == getHeight(), "GFXGLTextureObject::copyToBmp - invalid size"); + + PROFILE_SCOPE(GFXGLTextureObject_copyToBmp); + + PRESERVE_TEXTURE(mBinding); + glBindTexture(mBinding, mHandle); + + U8 dstBytesPerPixel = GFXFormat_getByteSize( bmp->getFormat() ); + U8 srcBytesPerPixel = GFXFormat_getByteSize( mFormat ); + if(dstBytesPerPixel == srcBytesPerPixel) + { + glGetTexImage(mBinding, 0, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], bmp->getWritableBits()); + return true; + } + + FrameAllocatorMarker mem; - GLint textureFormat = GFXGLTextureFormat[bmp->getFormat()]; - // Don't swizzle outgoing textures. - if(textureFormat == GL_BGRA) - textureFormat = GL_RGBA; + U32 srcPixelCount = mTextureSize.x * mTextureSize.y; + U8 *dest = bmp->getWritableBits(); + U8 *orig = (U8*)mem.alloc(srcPixelCount * srcBytesPerPixel); + + glGetTexImage(mBinding, 0, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], orig); - glGetTexImage(GL_TEXTURE_2D, 0, textureFormat, GL_UNSIGNED_BYTE, bmp->getWritableBits()); - - glBindTexture(GL_TEXTURE_2D, oldTex); + for(int i = 0; i < srcPixelCount; ++i) + { + dest[0] = orig[0]; + dest[1] = orig[1]; + dest[2] = orig[2]; + if(dstBytesPerPixel == 4) + dest[3] = orig[3]; + + orig += srcBytesPerPixel; + dest += dstBytesPerPixel; + } + return true; } -void GFXGLTextureObject::bind(U32 textureUnit) const +void GFXGLTextureObject::initSamplerState(const GFXSamplerStateDesc &ssd) +{ + glTexParameteri(mBinding, GL_TEXTURE_MIN_FILTER, minificationFilter(ssd.minFilter, ssd.mipFilter, mMipLevels)); + glTexParameteri(mBinding, GL_TEXTURE_MAG_FILTER, GFXGLTextureFilter[ssd.magFilter]); + glTexParameteri(mBinding, GL_TEXTURE_WRAP_S, !mIsNPoT2 ? GFXGLTextureAddress[ssd.addressModeU] : GL_CLAMP_TO_EDGE); + glTexParameteri(mBinding, GL_TEXTURE_WRAP_T, !mIsNPoT2 ? GFXGLTextureAddress[ssd.addressModeV] : GL_CLAMP_TO_EDGE); + if(mBinding == GL_TEXTURE_3D) + glTexParameteri(mBinding, GL_TEXTURE_WRAP_R, GFXGLTextureAddress[ssd.addressModeW]); + if(static_cast< GFXGLDevice* >( GFX )->supportsAnisotropic() ) + glTexParameterf(mBinding, GL_TEXTURE_MAX_ANISOTROPY_EXT, ssd.maxAnisotropy); + + mNeedInitSamplerState = false; + mSampler = ssd; +} + +void GFXGLTextureObject::bind(U32 textureUnit) { glActiveTexture(GL_TEXTURE0 + textureUnit); glBindTexture(mBinding, mHandle); - glEnable(mBinding); + GFXGL->getOpenglCache()->setCacheBindedTex(textureUnit, mBinding, mHandle); + + if( gglHasExtension(ARB_sampler_objects) ) + return; GFXGLStateBlockRef sb = mGLDevice->getCurrentStateBlock(); AssertFatal(sb, "GFXGLTextureObject::bind - No active stateblock!"); @@ -142,26 +220,41 @@ void GFXGLTextureObject::bind(U32 textureUnit) const return; const GFXSamplerStateDesc ssd = sb->getDesc().samplers[textureUnit]; - glTexParameteri(mBinding, GL_TEXTURE_MIN_FILTER, minificationFilter(ssd.minFilter, ssd.mipFilter, mMipLevels)); - glTexParameteri(mBinding, GL_TEXTURE_MAG_FILTER, GFXGLTextureFilter[ssd.magFilter]); - glTexParameteri(mBinding, GL_TEXTURE_WRAP_S, !mIsNPoT2 ? GFXGLTextureAddress[ssd.addressModeU] : GL_CLAMP_TO_EDGE); - glTexParameteri(mBinding, GL_TEXTURE_WRAP_T, !mIsNPoT2 ? GFXGLTextureAddress[ssd.addressModeV] : GL_CLAMP_TO_EDGE); - if(mBinding == GL_TEXTURE_3D) - glTexParameteri(mBinding, GL_TEXTURE_WRAP_R, GFXGLTextureAddress[ssd.addressModeW]); - glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, ssd.mipLODBias); + if(mNeedInitSamplerState) + { + initSamplerState(ssd); + return; + } + + if(mSampler.minFilter != ssd.minFilter || mSampler.mipFilter != ssd.mipFilter) + glTexParameteri(mBinding, GL_TEXTURE_MIN_FILTER, minificationFilter(ssd.minFilter, ssd.mipFilter, mMipLevels)); + if(mSampler.magFilter != ssd.magFilter) + glTexParameteri(mBinding, GL_TEXTURE_MAG_FILTER, GFXGLTextureFilter[ssd.magFilter]); + if(mSampler.addressModeU != ssd.addressModeU) + glTexParameteri(mBinding, GL_TEXTURE_WRAP_S, !mIsNPoT2 ? GFXGLTextureAddress[ssd.addressModeU] : GL_CLAMP_TO_EDGE); + if(mSampler.addressModeV != ssd.addressModeV) + glTexParameteri(mBinding, GL_TEXTURE_WRAP_T, !mIsNPoT2 ? GFXGLTextureAddress[ssd.addressModeV] : GL_CLAMP_TO_EDGE); + if(mBinding == GL_TEXTURE_3D && mSampler.addressModeW != ssd.addressModeW ) + glTexParameteri(mBinding, GL_TEXTURE_WRAP_R, GFXGLTextureAddress[ssd.addressModeW]); + if(mSampler.maxAnisotropy != ssd.maxAnisotropy && static_cast< GFXGLDevice* >( GFX )->supportsAnisotropic() ) + glTexParameterf(mBinding, GL_TEXTURE_MAX_ANISOTROPY_EXT, ssd.maxAnisotropy); + + mSampler = ssd; } U8* GFXGLTextureObject::getTextureData() { U8* data = new U8[mTextureSize.x * mTextureSize.y * mBytesPerTexel]; - glBindTexture(GL_TEXTURE_2D, mHandle); - glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data); + PRESERVE_TEXTURE(mBinding); + glBindTexture(mBinding, mHandle); + glGetTexImage(mBinding, 0, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], data); return data; } void GFXGLTextureObject::copyIntoCache() { + PRESERVE_TEXTURE(mBinding); glBindTexture(mBinding, mHandle); U32 cacheSize = mTextureSize.x * mTextureSize.y; if(mBinding == GL_TEXTURE_3D) @@ -171,7 +264,6 @@ void GFXGLTextureObject::copyIntoCache() mZombieCache = new U8[cacheSize]; glGetTexImage(mBinding, 0, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], mZombieCache); - glBindTexture(mBinding, 0); } void GFXGLTextureObject::reloadFromCache() @@ -187,8 +279,13 @@ void GFXGLTextureObject::reloadFromCache() return; } + PRESERVE_TEXTURE(mBinding); glBindTexture(mBinding, mHandle); - glTexSubImage2D(mBinding, 0, 0, 0, mTextureSize.x, mTextureSize.y, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], mZombieCache); + + if(mBinding == GL_TEXTURE_2D) + glTexSubImage2D(mBinding, 0, 0, 0, mTextureSize.x, mTextureSize.y, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], mZombieCache); + else if(mBinding == GL_TEXTURE_1D) + glTexSubImage1D(mBinding, 0, 0, (mTextureSize.x > 1 ? mTextureSize.x : mTextureSize.y), GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], mZombieCache); if(GFX->getCardProfiler()->queryProfile("GL::Workaround::needsExplicitGenerateMipmap") && mMipLevels != 1) glGenerateMipmapEXT(mBinding); diff --git a/Engine/source/gfx/gl/gfxGLTextureObject.h b/Engine/source/gfx/gl/gfxGLTextureObject.h index 586dd8a93..c3ebe9e23 100644 --- a/Engine/source/gfx/gl/gfxGLTextureObject.h +++ b/Engine/source/gfx/gl/gfxGLTextureObject.h @@ -24,7 +24,8 @@ #define _GFXGLTEXTUREOBJECT_H #include "gfx/gfxTextureObject.h" -#include "gfx/gl/ggl/ggl.h" +#include "gfx/gl/tGL/tGL.h" +#include "gfx/gfxStateBlock.h" class GFXGLDevice; @@ -32,9 +33,10 @@ class GFXGLTextureObject : public GFXTextureObject { public: GFXGLTextureObject(GFXDevice * aDevice, GFXTextureProfile *profile); - virtual ~GFXGLTextureObject(); + ~GFXGLTextureObject(); void release(); + void reInit(); inline GLuint getHandle() const { return mHandle; } inline GLenum getBinding() const { return mBinding; } @@ -45,7 +47,7 @@ public: /// Binds the texture to the given texture unit /// and applies the current sampler state because GL tracks /// filtering and wrapper per object, while GFX tracks per sampler. - void bind(U32 textureUnit) const; + void bind(U32 textureUnit); /// @return An array containing the texture data /// @note You are responsible for deleting the returned data! (Use delete[]) @@ -73,6 +75,8 @@ public: virtual void zombify(); virtual void resurrect(); virtual const String describeSelf() const; + + void initSamplerState(const GFXSamplerStateDesc &ssd); private: friend class GFXGLTextureManager; @@ -80,7 +84,8 @@ private: /// Internal GL object GLuint mHandle; GLuint mBuffer; - + bool mNeedInitSamplerState; + GFXSamplerStateDesc mSampler; GLenum mBinding; U32 mBytesPerTexel; @@ -94,6 +99,13 @@ private: U8* mZombieCache; void copyIntoCache(); + + //FrameAllocator + U32 mFrameAllocatorMark; +#if TORQUE_DEBUG + U32 mFrameAllocatorMarkGuard; +#endif + U8 *mFrameAllocatorPtr; }; #endif \ No newline at end of file diff --git a/Engine/source/gfx/gl/gfxGLTextureTarget.cpp b/Engine/source/gfx/gl/gfxGLTextureTarget.cpp index 656044d57..30ae8e9a9 100644 --- a/Engine/source/gfx/gl/gfxGLTextureTarget.cpp +++ b/Engine/source/gfx/gl/gfxGLTextureTarget.cpp @@ -47,6 +47,8 @@ public: virtual U32 getDepth() = 0; virtual bool hasMips() = 0; virtual GLenum getBinding() = 0; + virtual GFXFormat getFormat() = 0; + virtual bool isCompatible(const GFXGLTextureObject* tex) = 0; U32 getMipLevel() { return mipLevel; } U32 getZOffset() { return zOffset; } @@ -73,6 +75,14 @@ public: virtual U32 getDepth() { return mTex->getDepth(); } virtual bool hasMips() { return mTex->mMipLevels != 1; } virtual GLenum getBinding() { return mTex->getBinding(); } + virtual GFXFormat getFormat() { return mTex->getFormat(); } + virtual bool isCompatible(const GFXGLTextureObject* tex) + { + return mTex->getFormat() == tex->getFormat() + && mTex->getWidth() == tex->getWidth() + && mTex->getHeight() == tex->getHeight(); + } + GFXGLTextureObject* getTextureObject() const {return mTex; } private: StrongRefPtr mTex; @@ -95,6 +105,13 @@ public: virtual U32 getDepth() { return 0; } virtual bool hasMips() { return mTex->getNumMipLevels() != 1; } virtual GLenum getBinding() { return GFXGLCubemap::getEnumForFaceNumber(mFace); } + virtual GFXFormat getFormat() { return mTex->getFormat(); } + virtual bool isCompatible(const GFXGLTextureObject* tex) + { + return mTex->getFormat() == tex->getFormat() + && mTex->getWidth() == tex->getWidth() + && mTex->getHeight() == tex->getHeight(); + } private: StrongRefPtr mTex; @@ -102,7 +119,7 @@ private: }; // Internal implementations -class _GFXGLTextureTargetImpl +class _GFXGLTextureTargetImpl // TODO OPENGL remove and implement on GFXGLTextureTarget { public: GFXGLTextureTarget* mTarget; @@ -128,149 +145,88 @@ public: virtual void finish(); }; -// Handy macro for checking the status of a framebuffer. Framebuffers can fail in -// all sorts of interesting ways, these are just the most common. Further, no existing GL profiling -// tool catches framebuffer errors when the framebuffer is created, so we actually need this. -#define CHECK_FRAMEBUFFER_STATUS()\ -{\ -GLenum status;\ -status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);\ -switch(status) {\ -case GL_FRAMEBUFFER_COMPLETE_EXT:\ -break;\ -case GL_FRAMEBUFFER_UNSUPPORTED_EXT:\ -AssertFatal(false, "Unsupported FBO");\ -break;\ -case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:\ -AssertFatal(false, "Incomplete FBO Attachment");\ -break;\ -case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:\ -AssertFatal(false, "Incomplete FBO dimensions");\ -break;\ -case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:\ -AssertFatal(false, "Incomplete FBO formats");\ -default:\ -/* programming error; will fail on all hardware */\ -AssertFatal(false, "Something really bad happened with an FBO");\ -}\ -} - _GFXGLTextureTargetFBOImpl::_GFXGLTextureTargetFBOImpl(GFXGLTextureTarget* target) { mTarget = target; - glGenFramebuffersEXT(1, &mFramebuffer); + glGenFramebuffers(1, &mFramebuffer); } _GFXGLTextureTargetFBOImpl::~_GFXGLTextureTargetFBOImpl() { - glDeleteFramebuffersEXT(1, &mFramebuffer); + glDeleteFramebuffers(1, &mFramebuffer); } void _GFXGLTextureTargetFBOImpl::applyState() { // REMINDER: When we implement MRT support, check against GFXGLDevice::getNumRenderTargets() - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFramebuffer); - - _GFXGLTargetDesc* color0 = mTarget->getTargetDesc(GFXTextureTarget::Color0); - if(color0) - { - if(color0->getDepth() == 0) - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, color0->getBinding(), color0->getHandle(), color0->getMipLevel()); + PRESERVE_FRAMEBUFFER(); + glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer); + + bool hasColor = false; + for(int i = 0; i < GFXGL->getNumRenderTargets(); ++i) + { + _GFXGLTargetDesc* color = mTarget->getTargetDesc( static_cast(GFXTextureTarget::Color0+i )); + if(color) + { + hasColor = true; + if( color->getBinding( ) == GL_TEXTURE_2D ) + glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding( ), color->getHandle( ), color->getMipLevel( ) ); + else if( color->getBinding( ) == GL_TEXTURE_1D ) + glFramebufferTexture1D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding( ), color->getHandle( ), color->getMipLevel( ) ); + else if( color->getBinding( ) == GL_TEXTURE_3D ) + glFramebufferTexture3D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding( ), color->getHandle( ), color->getMipLevel( ), color->getZOffset( ) ); + } else - glFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, color0->getBinding(), color0->getHandle(), color0->getMipLevel(), color0->getZOffset()); - } - else - { - // Clears the texture (note that the binding is irrelevent) - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0); + { + // Clears the texture (note that the binding is irrelevent) + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+i, GL_TEXTURE_2D, 0, 0); + } } _GFXGLTargetDesc* depthStecil = mTarget->getTargetDesc(GFXTextureTarget::DepthStencil); if(depthStecil) { // Certain drivers have issues with depth only FBOs. That and the next two asserts assume we have a color target. - AssertFatal(color0, "GFXGLTextureTarget::applyState() - Cannot set DepthStencil target without Color0 target!"); - AssertFatal(depthStecil->getWidth() == color0->getWidth(), "GFXGLTextureTarget::applyState() - DepthStencil and Color0 targets MUST have the same width!"); - AssertFatal(depthStecil->getHeight() == color0->getHeight(), "GFXGLTextureTarget::applyState() - DepthStencil and Color0 targets MUST have the same height!"); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, depthStecil->getBinding(), depthStecil->getHandle(), depthStecil->getMipLevel()); + AssertFatal(hasColor, "GFXGLTextureTarget::applyState() - Cannot set DepthStencil target without Color0 target!"); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthStecil->getBinding(), depthStecil->getHandle(), depthStecil->getMipLevel()); } else { // Clears the texture (note that the binding is irrelevent) - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0); } - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + CHECK_FRAMEBUFFER_STATUS(); } void _GFXGLTextureTargetFBOImpl::makeActive() { - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, mFramebuffer); - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, mFramebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer); + GFXGL->getOpenglCache()->setCacheBinded(GL_FRAMEBUFFER, mFramebuffer); } void _GFXGLTextureTargetFBOImpl::finish() { - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); - - _GFXGLTargetDesc* color0 = mTarget->getTargetDesc(GFXTextureTarget::Color0); - if(!color0 || !(color0->hasMips())) - return; - - // Generate mips if necessary - // Assumes a 2D texture. - glActiveTexture(GL_TEXTURE0); - PRESERVE_2D_TEXTURE(); - glBindTexture(GL_TEXTURE_2D, color0->getHandle()); - glGenerateMipmapEXT(GL_TEXTURE_2D); -} + glBindFramebuffer(GL_FRAMEBUFFER, 0); + GFXGL->getOpenglCache()->setCacheBinded(GL_FRAMEBUFFER, 0); -// This implementations uses AUX buffers (we should always have at least one) to do render to texture. It is currently only used when we need access to the windows depth buffer. -class _GFXGLTextureTargetAUXBufferImpl : public _GFXGLTextureTargetImpl -{ -public: - _GFXGLTextureTargetAUXBufferImpl(GFXGLTextureTarget* target); + for(int i = 0; i < GFXGL->getNumRenderTargets(); ++i) + { + _GFXGLTargetDesc* color = mTarget->getTargetDesc( static_cast(GFXTextureTarget::Color0+i ) ); + if(!color || !(color->hasMips())) + continue; - virtual void applyState(); - virtual void makeActive(); - virtual void finish(); -}; - -_GFXGLTextureTargetAUXBufferImpl::_GFXGLTextureTargetAUXBufferImpl(GFXGLTextureTarget* target) -{ - mTarget = target; -} - -void _GFXGLTextureTargetAUXBufferImpl::applyState() -{ - -} - -void _GFXGLTextureTargetAUXBufferImpl::makeActive() -{ - glDrawBuffer(GL_AUX0); - glReadBuffer(GL_AUX0); -} - -void _GFXGLTextureTargetAUXBufferImpl::finish() -{ - // Bind the Color0 texture - _GFXGLTargetDesc* color0 = mTarget->getTargetDesc(GFXTextureTarget::Color0); - - glActiveTexture(GL_TEXTURE0); - // Assume we're a 2D texture for now. - PRESERVE_2D_TEXTURE(); - glBindTexture(color0->getBinding(), color0->getHandle()); - glCopyTexSubImage2D(color0->getBinding(), 0, 0, 0, 0, 0, color0->getWidth(), color0->getHeight()); - - glDrawBuffer(GL_BACK); - glReadBuffer(GL_BACK); + // Generate mips if necessary + // Assumes a 2D texture. + PRESERVE_TEXTURE(color->getBinding()); + glBindTexture(color->getBinding(), color->getHandle()); + glGenerateMipmapEXT(GL_TEXTURE_2D); + } } // Actual GFXGLTextureTarget interface -GFXGLTextureTarget::GFXGLTextureTarget() +GFXGLTextureTarget::GFXGLTextureTarget() : mCopyFboSrc(0), mCopyFboDst(0) { for(U32 i=0; igetFormat(); + return GFXFormatR8G8B8A8; } void GFXGLTextureTarget::attachTexture( RenderSlot slot, GFXTextureObject *tex, U32 mipLevel/*=0*/, U32 zOffset /*= 0*/ ) { - // GFXTextureTarget::sDefaultDepthStencil is a hint that we want the window's depth buffer. - if(tex == GFXTextureTarget::sDefaultDepthStencil) - _needsAux = true; - - if(slot == DepthStencil && tex != GFXTextureTarget::sDefaultDepthStencil) - _needsAux = false; + if( tex == GFXTextureTarget::sDefaultDepthStencil ) + tex = GFXGL->getDefaultDepthTex(); + + _GFXGLTextureTargetDesc* mTex = static_cast<_GFXGLTextureTargetDesc*>(mTargets[slot].ptr()); + if( (!tex && !mTex) || (mTex && mTex->getTextureObject() == tex) ) + return; // Triggers an update when we next render invalidateState(); @@ -376,10 +336,7 @@ void GFXGLTextureTarget::applyState() // So we don't do this over and over again stateApplied(); - // Ensure we have the proper implementation (consider changing to an enum?) - if(_needsAux && dynamic_cast<_GFXGLTextureTargetAUXBufferImpl*>(_impl.ptr()) == NULL) - _impl = new _GFXGLTextureTargetAUXBufferImpl(this); - else if(!_needsAux && dynamic_cast<_GFXGLTextureTargetFBOImpl*>(_impl.ptr()) == NULL) + if(_impl.isNull()) _impl = new _GFXGLTextureTargetFBOImpl(this); _impl->applyState(); @@ -413,26 +370,24 @@ void GFXGLTextureTarget::resolveTo(GFXTextureObject* obj) AssertFatal(dynamic_cast(obj), "GFXGLTextureTarget::resolveTo - Incorrect type of texture, expected a GFXGLTextureObject"); GFXGLTextureObject* glTexture = static_cast(obj); + if( gglHasExtension(ARB_copy_image) && mTargets[Color0]->isCompatible(glTexture) ) + { + glCopyImageSubData( + mTargets[Color0]->getHandle(), GL_TEXTURE_2D, 0, 0, 0, 0, + glTexture->getHandle(), GL_TEXTURE_2D, 0, 0, 0, 0, + mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight(), 1); + + return; + } + PRESERVE_FRAMEBUFFER(); - GLuint dest; - GLuint src; + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mCopyFboDst); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glTexture->getHandle(), 0); - glGenFramebuffersEXT(1, &dest); - glGenFramebuffersEXT(1, &src); + glBindFramebuffer(GL_READ_FRAMEBUFFER, mCopyFboSrc); + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,mTargets[Color0]->getHandle(), 0); - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, dest); - glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, glTexture->getHandle(), 0); - - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, src); - glFramebufferTexture2DEXT(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,mTargets[Color0]->getHandle(), 0); - - glBlitFramebufferEXT(0, 0, mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight(), + glBlitFramebuffer(0, 0, mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight(), 0, 0, glTexture->getWidth(), glTexture->getHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST); - - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); - - glDeleteFramebuffersEXT(1, &dest); - glDeleteFramebuffersEXT(1, &src); } diff --git a/Engine/source/gfx/gl/gfxGLTextureTarget.h b/Engine/source/gfx/gl/gfxGLTextureTarget.h index d0b34539a..fffcefd70 100644 --- a/Engine/source/gfx/gl/gfxGLTextureTarget.h +++ b/Engine/source/gfx/gl/gfxGLTextureTarget.h @@ -79,9 +79,6 @@ protected: /// @see GFXTextureManager::addEventDelegate void _onTextureEvent( GFXTexCallbackCode code ); - /// If true our implementation should use AUX buffers - bool _needsAux; - /// Pointer to our internal implementation AutoPtr<_GFXGLTextureTargetImpl> _impl; @@ -96,6 +93,9 @@ protected: /// @} + //copy FBO + GLuint mCopyFboSrc, mCopyFboDst; + }; #endif diff --git a/Engine/source/gfx/gl/gfxGLUtils.h b/Engine/source/gfx/gl/gfxGLUtils.h index 5f1ac18c7..881348043 100644 --- a/Engine/source/gfx/gl/gfxGLUtils.h +++ b/Engine/source/gfx/gl/gfxGLUtils.h @@ -25,12 +25,15 @@ #include "core/util/preprocessorHelpers.h" #include "gfx/gl/gfxGLEnumTranslate.h" +#include "gfx/gl/gfxGLStateCache.h" -static inline GLenum minificationFilter(U32 minFilter, U32 mipFilter, U32 mipLevels) +inline U32 getMaxMipmaps(U32 width, U32 height, U32 depth) { - if(mipLevels == 1) - return GFXGLTextureFilter[minFilter]; + return getMax( getBinLog2(depth), getMax(getBinLog2(width), getBinLog2(height))); +} +inline GLenum minificationFilter(U32 minFilter, U32 mipFilter, U32 /*mipLevels*/) +{ // the compiler should interpret this as array lookups switch( minFilter ) { @@ -56,13 +59,49 @@ static inline GLenum minificationFilter(U32 minFilter, U32 mipFilter, U32 mipLev } } +// Check if format is compressed format. +// Even though dxt2/4 are not supported, they are included because they are a compressed format. +// Assert checks on supported formats are done elsewhere. +inline bool isCompressedFormat( GFXFormat format ) +{ + bool compressed = false; + if(format == GFXFormatDXT1 || format == GFXFormatDXT2 + || format == GFXFormatDXT3 + || format == GFXFormatDXT4 + || format == GFXFormatDXT5 ) + { + compressed = true; + } + + return compressed; +} + +//Get the surface size of a compressed mip map level - see ddsLoader.cpp +inline U32 getCompressedSurfaceSize(GFXFormat format,U32 width, U32 height, U32 mipLevel=0 ) +{ + if(!isCompressedFormat(format)) + return 0; + + // Bump by the mip level. + height = getMax(U32(1), height >> mipLevel); + width = getMax(U32(1), width >> mipLevel); + + U32 sizeMultiple = 0; + if(format == GFXFormatDXT1) + sizeMultiple = 8; + else + sizeMultiple = 16; + + return getMax(U32(1), width/4) * getMax(U32(1), height/4) * sizeMultiple; +} + /// Simple class which preserves a given GL integer. /// This class determines the integer to preserve on construction and restores /// it on destruction. class GFXGLPreserveInteger { public: - typedef void(*BindFn)(GLenum, GLuint); + typedef void(STDCALL *BindFn)(GLenum, GLuint); /// Preserve the integer. /// @param binding The binding which should be set on destruction. @@ -73,7 +112,12 @@ public: mBinding(binding), mPreserved(0), mBinder(binder) { AssertFatal(mBinder, "GFXGLPreserveInteger - Need a valid binder function"); - glGetIntegerv(getBinding, &mPreserved); + mPreserved = GFXGL->getOpenglCache()->getCacheBinded(mBinding); +#if defined(TORQUE_DEBUG) && defined(TORQUE_DEBUG_GFX) + GLint bindedOnOpenglDriver; + glGetIntegerv(getBinding, &bindedOnOpenglDriver); + AssertFatal( mPreserved == bindedOnOpenglDriver, "GFXGLPreserveInteger - GFXGLDevice/OpenGL mismatch on cache binded resource."); +#endif } /// Restores the integer. @@ -88,24 +132,113 @@ private: BindFn mBinder; }; +class GFXGLPreserveTexture +{ +public: + typedef void(STDCALL *BindFn)(GLenum, GLuint); + + GFXGLPreserveTexture(GLenum binding, GLint getBinding, BindFn binder) : + mBinding(binding), mPreserved(0), mBinder(binder) + { + AssertFatal(mBinder, "GFXGLPreserveTexture - Need a valid binder function"); + GFXGLDevice *gfx = GFXGL; + mPreserved = gfx->getOpenglCache()->getCacheBinded(mBinding); + mActiveTexture = gfx->getOpenglCache()->getCacheActiveTexture(); +#if defined(TORQUE_DEBUG) && defined(TORQUE_DEBUG_GFX) + GLint activeTextureOnOpenglDriver, bindedTextureOnOpenglDriver; + glGetIntegerv(getBinding, &bindedTextureOnOpenglDriver); + glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTextureOnOpenglDriver); + activeTextureOnOpenglDriver -= GL_TEXTURE0; + AssertFatal( mPreserved == bindedTextureOnOpenglDriver, "GFXGLPreserveTexture - GFXGLDevice/OpenGL mismatch on cache binded resource."); + AssertFatal( activeTextureOnOpenglDriver == mActiveTexture, "GFXGLPreserveTexture - GFXGLDevice/OpenGL mismatch on cache binded resource."); +#endif + } + + /// Restores the texture. + ~GFXGLPreserveTexture() + { +#if defined(TORQUE_DEBUG) && defined(TORQUE_DEBUG_GFX) + GLint activeTextureOnOpenglDriver; + glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTextureOnOpenglDriver); + activeTextureOnOpenglDriver -= GL_TEXTURE0; + GLint cacheActiveTexture = GFXGL->getOpenglCache()->getCacheActiveTexture(); + AssertFatal( cacheActiveTexture == activeTextureOnOpenglDriver, "GFXGLPreserveTexture - GFXGLDevice/OpenGL mismatch on cache ActiveTexture."); +#endif + mBinder(mBinding, mPreserved); + } + +private: + GLenum mBinding; + GLint mPreserved; + BindFn mBinder; + S16 mActiveTexture; +}; + /// Helper macro to preserve the current VBO binding. #define PRESERVE_VERTEX_BUFFER() \ -GFXGLPreserveInteger TORQUE_CONCAT(preserve_, __LINE__) (GL_ARRAY_BUFFER, GL_ARRAY_BUFFER_BINDING, glBindBuffer) +GFXGLPreserveInteger TORQUE_CONCAT(preserve_, __LINE__) (GL_ARRAY_BUFFER, GL_ARRAY_BUFFER_BINDING, (GFXGLPreserveInteger::BindFn)glBindBuffer) /// Helper macro to preserve the current element array binding. #define PRESERVE_INDEX_BUFFER() \ -GFXGLPreserveInteger TORQUE_CONCAT(preserve_, __LINE__) (GL_ELEMENT_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER_BINDING, glBindBuffer) +GFXGLPreserveInteger TORQUE_CONCAT(preserve_, __LINE__) (GL_ELEMENT_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER_BINDING, (GFXGLPreserveInteger::BindFn)glBindBuffer) + +/// ASSERT: Never call glActiveTexture for a "bind to modify" or in a PRESERVER_TEXTURE MACRO scope. + +/// Helper macro to preserve the current 1D texture binding. +#define PRESERVE_1D_TEXTURE() \ +GFXGLPreserveTexture TORQUE_CONCAT(preserve_, __LINE__) (GL_TEXTURE_1D, GL_TEXTURE_BINDING_1D, (GFXGLPreserveInteger::BindFn)glBindTexture) /// Helper macro to preserve the current 2D texture binding. #define PRESERVE_2D_TEXTURE() \ -GFXGLPreserveInteger TORQUE_CONCAT(preserve_, __LINE__) (GL_TEXTURE_2D, GL_TEXTURE_BINDING_2D, glBindTexture) +GFXGLPreserveTexture TORQUE_CONCAT(preserve_, __LINE__) (GL_TEXTURE_2D, GL_TEXTURE_BINDING_2D, (GFXGLPreserveInteger::BindFn)glBindTexture) /// Helper macro to preserve the current 3D texture binding. #define PRESERVE_3D_TEXTURE() \ -GFXGLPreserveInteger TORQUE_CONCAT(preserve_, __LINE__) (GL_TEXTURE_3D, GL_TEXTURE_BINDING_3D, glBindTexture) +GFXGLPreserveTexture TORQUE_CONCAT(preserve_, __LINE__) (GL_TEXTURE_3D, GL_TEXTURE_BINDING_3D, (GFXGLPreserveInteger::BindFn)glBindTexture) + +/// Helper macro to preserve the current 3D texture binding. +#define PRESERVE_CUBEMAP_TEXTURE() \ +GFXGLPreserveTexture TORQUE_CONCAT(preserve_, __LINE__) (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BINDING_CUBE_MAP, (GFXGLPreserveInteger::BindFn)glBindTexture) + +#define _GET_TEXTURE_BINDING(binding) \ +binding == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : (binding == GL_TEXTURE_3D ? GL_TEXTURE_BINDING_3D : GL_TEXTURE_BINDING_1D ) + +#define PRESERVE_TEXTURE(binding) \ +GFXGLPreserveTexture TORQUE_CONCAT(preserve_, __LINE__) (binding, _GET_TEXTURE_BINDING(binding), (GFXGLPreserveInteger::BindFn)glBindTexture) #define PRESERVE_FRAMEBUFFER() \ -GFXGLPreserveInteger TORQUE_CONCAT(preserve_, __LINE__) (GL_READ_FRAMEBUFFER_EXT, GL_READ_FRAMEBUFFER_BINDING_EXT, glBindFramebufferEXT);\ -GFXGLPreserveInteger TORQUE_CONCAT(preserve2_, __LINE__) (GL_DRAW_FRAMEBUFFER_EXT, GL_DRAW_FRAMEBUFFER_BINDING_EXT, glBindFramebufferEXT) +GFXGLPreserveInteger TORQUE_CONCAT(preserve_, __LINE__) (GL_READ_FRAMEBUFFER, GL_READ_FRAMEBUFFER_BINDING, (GFXGLPreserveInteger::BindFn)glBindFramebuffer);\ +GFXGLPreserveInteger TORQUE_CONCAT(preserve2_, __LINE__) (GL_DRAW_FRAMEBUFFER, GL_DRAW_FRAMEBUFFER_BINDING, (GFXGLPreserveInteger::BindFn)glBindFramebuffer) + +// Handy macro for checking the status of a framebuffer. Framebuffers can fail in +// all sorts of interesting ways, these are just the most common. Further, no existing GL profiling +// tool catches framebuffer errors when the framebuffer is created, so we actually need this. +#define CHECK_FRAMEBUFFER_STATUS()\ +{\ +GLenum status;\ +status = glCheckFramebufferStatus(GL_FRAMEBUFFER);\ +switch(status) {\ +case GL_FRAMEBUFFER_COMPLETE:\ +break;\ +case GL_FRAMEBUFFER_UNSUPPORTED:\ +AssertFatal(false, "Unsupported FBO");\ +break;\ +case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:\ +AssertFatal(false, "Incomplete FBO Attachment");\ +break;\ +case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:\ +AssertFatal(false, "Incomplete FBO Missing Attachment");\ +break;\ +case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:\ +AssertFatal(false, "Incomplete FBO Draw buffer");\ +break;\ +case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:\ +AssertFatal(false, "Incomplete FBO Read buffer");\ +break;\ +default:\ +/* programming error; will fail on all hardware */\ +AssertFatal(false, "Something really bad happened with an FBO");\ +}\ +} #endif diff --git a/Engine/source/gfx/gl/gfxGLVertexAttribLocation.h b/Engine/source/gfx/gl/gfxGLVertexAttribLocation.h new file mode 100644 index 000000000..63582ecdf --- /dev/null +++ b/Engine/source/gfx/gl/gfxGLVertexAttribLocation.h @@ -0,0 +1,30 @@ +#ifndef GFX_GL_VERTEX_ATTRIB_LOCATION_H +#define GFX_GL_VERTEX_ATTRIB_LOCATION_H + +namespace Torque +{ + enum GL_AttributeLocation + { + GL_VertexAttrib_Position = 0, + GL_VertexAttrib_Normal, + GL_VertexAttrib_Color, + GL_VertexAttrib_Tangent, + GL_VertexAttrib_TangentW, + GL_VertexAttrib_Binormal, + GL_VertexAttrib_TexCoord0, + GL_VertexAttrib_TexCoord1, + GL_VertexAttrib_TexCoord2, + GL_VertexAttrib_TexCoord3, + GL_VertexAttrib_TexCoord4, + GL_VertexAttrib_TexCoord5, + GL_VertexAttrib_TexCoord6, + GL_VertexAttrib_TexCoord7, + GL_VertexAttrib_TexCoord8, + GL_VertexAttrib_TexCoord9, + GL_VertexAttrib_LAST = GL_VertexAttrib_TexCoord9, + GL_VertexAttrib_COUNT + }; +} + + +#endif //GFX_GL_VERTEX_ATTRIB_LOCATION_H \ No newline at end of file diff --git a/Engine/source/gfx/gl/gfxGLVertexBuffer.cpp b/Engine/source/gfx/gl/gfxGLVertexBuffer.cpp index 11e7e53ea..132172c1a 100644 --- a/Engine/source/gfx/gl/gfxGLVertexBuffer.cpp +++ b/Engine/source/gfx/gl/gfxGLVertexBuffer.cpp @@ -26,7 +26,15 @@ #include "gfx/gl/gfxGLDevice.h" #include "gfx/gl/gfxGLEnumTranslate.h" #include "gfx/gl/gfxGLUtils.h" +#include "gfx/gl/gfxGLVertexAttribLocation.h" +#include "gfx/gl/gfxGLCircularVolatileBuffer.h" + +GLCircularVolatileBuffer* getCircularVolatileVertexBuffer() +{ + static GLCircularVolatileBuffer sCircularVolatileVertexBuffer(GL_ARRAY_BUFFER); + return &sCircularVolatileVertexBuffer; +} GFXGLVertexBuffer::GFXGLVertexBuffer( GFXDevice *device, U32 numVerts, @@ -34,113 +42,111 @@ GFXGLVertexBuffer::GFXGLVertexBuffer( GFXDevice *device, U32 vertexSize, GFXBufferType bufferType ) : GFXVertexBuffer( device, numVerts, vertexFormat, vertexSize, bufferType ), - mZombieCache(NULL) + mZombieCache(NULL), + mBufferOffset(0), + mBufferVertexOffset(0) { + if( mBufferType == GFXBufferTypeVolatile ) + { + mBuffer = getCircularVolatileVertexBuffer()->getHandle(); + return; + } + + // Generate a buffer + glGenBuffers(1, &mBuffer); + + //and allocate the needed memory PRESERVE_VERTEX_BUFFER(); - // Generate a buffer and allocate the needed memory. - glGenBuffers(1, &mBuffer); - glBindBuffer(GL_ARRAY_BUFFER, mBuffer); - glBufferData(GL_ARRAY_BUFFER, numVerts * vertexSize, NULL, GFXGLBufferType[bufferType]); - glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, mBuffer); + glBufferData(GL_ARRAY_BUFFER, numVerts * vertexSize, NULL, GFXGLBufferType[bufferType]); } GFXGLVertexBuffer::~GFXGLVertexBuffer() { // While heavy handed, this does delete the buffer and frees the associated memory. - glDeleteBuffers(1, &mBuffer); - + if( mBufferType != GFXBufferTypeVolatile ) + glDeleteBuffers(1, &mBuffer); + if( mZombieCache ) delete [] mZombieCache; } void GFXGLVertexBuffer::lock( U32 vertexStart, U32 vertexEnd, void **vertexPtr ) { - PRESERVE_VERTEX_BUFFER(); - // Bind us, get a pointer into the buffer, then - // offset it by vertexStart so we act like the D3D layer. - glBindBuffer(GL_ARRAY_BUFFER, mBuffer); - glBufferData(GL_ARRAY_BUFFER, mNumVerts * mVertexSize, NULL, GFXGLBufferType[mBufferType]); - *vertexPtr = (void*)((U8*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY) + (vertexStart * mVertexSize)); + PROFILE_SCOPE(GFXGLVertexBuffer_lock); + + if( mBufferType == GFXBufferTypeVolatile ) + { + AssertFatal(vertexStart == 0, ""); + if( gglHasExtension(ARB_vertex_attrib_binding) ) + { + getCircularVolatileVertexBuffer()->lock( mNumVerts * mVertexSize, 0, mBufferOffset, *vertexPtr ); + } + else + { + getCircularVolatileVertexBuffer()->lock( mNumVerts * mVertexSize, mVertexSize, mBufferOffset, *vertexPtr ); + mBufferVertexOffset = mBufferOffset / mVertexSize; + } + } + else + { + mFrameAllocator.lock( mNumVerts * mVertexSize ); + + lockedVertexPtr = (void*)(mFrameAllocator.getlockedPtr() + (vertexStart * mVertexSize)); + *vertexPtr = lockedVertexPtr; + } + lockedVertexStart = vertexStart; lockedVertexEnd = vertexEnd; } void GFXGLVertexBuffer::unlock() { - PRESERVE_VERTEX_BUFFER(); - // Unmap the buffer and bind 0 to GL_ARRAY_BUFFER - glBindBuffer(GL_ARRAY_BUFFER, mBuffer); - bool res = glUnmapBuffer(GL_ARRAY_BUFFER); - AssertFatal(res, "GFXGLVertexBuffer::unlock - shouldn't fail!"); + PROFILE_SCOPE(GFXGLVertexBuffer_unlock); + + if( mBufferType == GFXBufferTypeVolatile ) + { + getCircularVolatileVertexBuffer()->unlock(); + } + else + { + U32 offset = lockedVertexStart * mVertexSize; + U32 length = (lockedVertexEnd - lockedVertexStart) * mVertexSize; + + PRESERVE_VERTEX_BUFFER(); + glBindBuffer(GL_ARRAY_BUFFER, mBuffer); + + if( !lockedVertexStart && lockedVertexEnd == mNumVerts) + glBufferData(GL_ARRAY_BUFFER, mNumVerts * mVertexSize, NULL, GFXGLBufferType[mBufferType]); // orphan the buffer + + glBufferSubData(GL_ARRAY_BUFFER, offset, length, mFrameAllocator.getlockedPtr() + offset ); + + mFrameAllocator.unlock(); + } lockedVertexStart = 0; lockedVertexEnd = 0; + lockedVertexPtr = NULL; } void GFXGLVertexBuffer::prepare() { - // Bind the buffer... - glBindBuffer(GL_ARRAY_BUFFER, mBuffer); - U8* buffer = (U8*)getBuffer(); + AssertFatal(0, "GFXGLVertexBuffer::prepare - use GFXGLVertexBuffer::prepare(U32 stream, U32 divisor)"); +} - // Loop thru the vertex format elements adding the array state... - U32 texCoordIndex = 0; - for ( U32 i=0; i < mVertexFormat.getElementCount(); i++ ) - { - const GFXVertexElement &element = mVertexFormat.getElement( i ); - - if ( element.isSemantic( GFXSemantic::POSITION ) ) - { - glEnableClientState( GL_VERTEX_ARRAY ); - glVertexPointer( element.getSizeInBytes() / 4, GL_FLOAT, mVertexSize, buffer ); - buffer += element.getSizeInBytes(); - } - else if ( element.isSemantic( GFXSemantic::NORMAL ) ) - { - glEnableClientState( GL_NORMAL_ARRAY ); - glNormalPointer( GL_FLOAT, mVertexSize, buffer ); - buffer += element.getSizeInBytes(); - } - else if ( element.isSemantic( GFXSemantic::COLOR ) ) - { - glEnableClientState( GL_COLOR_ARRAY ); - glColorPointer( element.getSizeInBytes(), GL_UNSIGNED_BYTE, mVertexSize, buffer ); - buffer += element.getSizeInBytes(); - } - else // Everything else is a texture coordinate. - { - glClientActiveTexture( GL_TEXTURE0 + texCoordIndex ); - glEnableClientState( GL_TEXTURE_COORD_ARRAY ); - glTexCoordPointer( element.getSizeInBytes() / 4, GL_FLOAT, mVertexSize, buffer ); - buffer += element.getSizeInBytes(); - ++texCoordIndex; - } - +void GFXGLVertexBuffer::prepare(U32 stream, U32 divisor) +{ + if( gglHasExtension(ARB_vertex_attrib_binding) ) + { + glBindVertexBuffer( stream, mBuffer, mBufferOffset, mVertexSize ); + glVertexBindingDivisor( stream, divisor ); + return; } } void GFXGLVertexBuffer::finish() { - glBindBuffer(GL_ARRAY_BUFFER, 0); - U32 texCoordIndex = 0; - for ( U32 i=0; i < mVertexFormat.getElementCount(); i++ ) - { - const GFXVertexElement &element = mVertexFormat.getElement( i ); - - if ( element.isSemantic( GFXSemantic::POSITION ) ) - glDisableClientState( GL_VERTEX_ARRAY ); - else if ( element.isSemantic( GFXSemantic::NORMAL ) ) - glDisableClientState( GL_NORMAL_ARRAY ); - else if ( element.isSemantic( GFXSemantic::COLOR ) ) - glDisableClientState( GL_COLOR_ARRAY ); - else - { - glClientActiveTexture( GL_TEXTURE0 + texCoordIndex ); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - ++texCoordIndex; - } - } } GLvoid* GFXGLVertexBuffer::getBuffer() @@ -175,3 +181,29 @@ void GFXGLVertexBuffer::resurrect() delete[] mZombieCache; mZombieCache = NULL; } + +namespace +{ + bool onGFXDeviceSignal( GFXDevice::GFXDeviceEventType type ) + { + if( GFX->getAdapterType() == OpenGL && GFXDevice::deEndOfFrame == type ) + getCircularVolatileVertexBuffer()->protectUsedRange(); + + return true; + } +} + +MODULE_BEGIN( GFX_GL_VertexBuffer ) + MODULE_INIT_AFTER( gfx ) + MODULE_SHUTDOWN_BEFORE( gfx ) + + MODULE_INIT + { + GFXDevice::getDeviceEventSignal().notify( &onGFXDeviceSignal ); + } + + MODULE_SHUTDOWN + { + GFXDevice::getDeviceEventSignal( ).remove( &onGFXDeviceSignal ); + } +MODULE_END \ No newline at end of file diff --git a/Engine/source/gfx/gl/gfxGLVertexBuffer.h b/Engine/source/gfx/gl/gfxGLVertexBuffer.h index f7de259a3..571192b3b 100644 --- a/Engine/source/gfx/gl/gfxGLVertexBuffer.h +++ b/Engine/source/gfx/gl/gfxGLVertexBuffer.h @@ -26,14 +26,14 @@ #ifndef _GFXVERTEXBUFFER_H_ #include "gfx/gfxVertexBuffer.h" #endif -#ifndef GL_GGL_H -#include "gfx/gl/ggl/ggl.h" -#endif +#include "gfx/gl/tGL/tGL.h" +#include "gfx/gl/util/glFrameAllocatorLockableHelper.h" /// This is a vertex buffer which uses GL_ARB_vertex_buffer_object. class GFXGLVertexBuffer : public GFXVertexBuffer { public: + GFXGLVertexBuffer( GFXDevice *device, U32 numVerts, const GFXVertexFormat *vertexFormat, @@ -42,23 +42,32 @@ public: ~GFXGLVertexBuffer(); - virtual void lock(U32 vertexStart, U32 vertexEnd, void **vertexPtr); ///< calls glMapBuffer and offsets the pointer by vertex start - virtual void unlock(); ///< calls glUnmapBuffer, unbinds the buffer - virtual void prepare(); ///< Binds the buffer - virtual void finish(); ///< We're done here + virtual void lock(U32 vertexStart, U32 vertexEnd, void **vertexPtr); ///< Only write lock are supported. + virtual void unlock(); ///< + virtual void prepare(); ///< Do nothing. Use void prepare(U32 stream, U32 divisor). + virtual void finish(); ///< Do nothing. + + void prepare(U32 stream, U32 divisor); GLvoid* getBuffer(); ///< returns NULL // GFXResource interface virtual void zombify(); virtual void resurrect(); - + private: friend class GFXGLDevice; /// GL buffer handle GLuint mBuffer; - + + /// bytes offset in buffer + U32 mBufferOffset; + + /// start vertex offset in buffer + U32 mBufferVertexOffset; U8* mZombieCache; + + FrameAllocatorLockableHelper mFrameAllocator; }; #endif diff --git a/Engine/source/gfx/gl/gfxGLVertexDecl.cpp b/Engine/source/gfx/gl/gfxGLVertexDecl.cpp new file mode 100644 index 000000000..882c624b9 --- /dev/null +++ b/Engine/source/gfx/gl/gfxGLVertexDecl.cpp @@ -0,0 +1,212 @@ +#include "gfx/gl/gfxGLDevice.h" +#include "gfx/gl/gfxGLStateCache.h" +#include "gfx/gl/gfxGLVertexAttribLocation.h" +#include "gfx/gl/gfxGLVertexDecl.h" + +void GFXGLVertexDecl::init(const GFXVertexFormat *format) +{ + AssertFatal(!mFormat, ""); + mFormat = format; + + for(int i = 0; i < GFXGL->getNumVertexStreams(); ++i) + _initVerticesFormat(i); +} + +void GFXGLVertexDecl::prepareVertexFormat() const +{ + AssertFatal(mFormat, "GFXGLVertexDecl - Not inited"); + if( gglHasExtension(ARB_vertex_attrib_binding) ) + { + for ( U32 i=0; i < glVerticesFormat.size(); i++ ) + { + const glVertexAttribData &glElement = glVerticesFormat[i]; + + glVertexAttribFormat( glElement.attrIndex, glElement.elementCount, glElement.type, glElement.normalized, (U32)glElement.pointerFirst ); + glVertexAttribBinding( glElement.attrIndex, glElement.stream ); + } + + updateActiveVertexAttrib( GFXGL->getOpenglCache()->getCacheVertexAttribActive() ); + + return; + } +} + +void GFXGLVertexDecl::prepareBuffer_old(U32 stream, GLint mBuffer, GLint mDivisor) const +{ + PROFILE_SCOPE(GFXGLVertexDecl_prepare); + AssertFatal(mFormat, "GFXGLVertexDecl - Not inited"); + + if( gglHasExtension(ARB_vertex_attrib_binding) ) + return; + + // Bind the buffer... + glBindBuffer(GL_ARRAY_BUFFER, mBuffer); + GFXGL->getOpenglCache()->setCacheBinded(GL_ARRAY_BUFFER, mBuffer); + + // Loop thru the vertex format elements adding the array state... + for ( U32 i=0; i < glVerticesFormat.size(); i++ ) + { + // glEnableVertexAttribArray are called and cache in GFXGLDevice::preDrawPrimitive + + const glVertexAttribData &e = glVerticesFormat[i]; + if(e.stream != stream) + continue; + + glVertexAttribPointer( + e.attrIndex, // attribute + e.elementCount, // number of elements per vertex, here (r,g,b) + e.type, // the type of each element + e.normalized, // take our values as-is + e.stride, // stride between each position + e.pointerFirst // offset of first element + ); + glVertexAttribDivisor( e.attrIndex, mDivisor ); + } +} + +void GFXGLVertexDecl::updateActiveVertexAttrib(U32 lastActiveMask) const +{ + AssertFatal(mVertexAttribActiveMask, "GFXGLVertexDecl::updateActiveVertexAttrib - No vertex attribute are active"); + + U32 lastActiveVerxtexAttrib = GFXGL->getOpenglCache()->getCacheVertexAttribActive(); + if(mVertexAttribActiveMask == lastActiveVerxtexAttrib) + return; + + U32 forActiveMask = mVertexAttribActiveMask & ~lastActiveVerxtexAttrib; + U32 forDeactiveMask = ~mVertexAttribActiveMask & lastActiveVerxtexAttrib; + for(int i = 0; i < Torque::GL_VertexAttrib_COUNT; ++i) + { + if( BIT(i) & forActiveMask ) //if is active but not in last mask + glEnableVertexAttribArray(i); + else if( BIT(i) & forDeactiveMask ) // if not active but in last mask + glDisableVertexAttribArray(i); + } + + GFXGL->getOpenglCache()->setCacheVertexAttribActive(mVertexAttribActiveMask); +} + +void GFXGLVertexDecl::_initVerticesFormat2() +{ + for( U32 i=0; i < GFXGL->getNumVertexStreams(); ++i ) + { + _initVerticesFormat(i); + } +} + +void GFXGLVertexDecl::_initVerticesFormat(U32 stream) +{ + U32 buffer = 0; + U32 vertexSize = 0; + + for ( U32 i=0; i < mFormat->getElementCount(); i++ ) + { + const GFXVertexElement &element = mFormat->getElement( i ); + + if(element.getStreamIndex() != stream) + continue; + + vertexSize += element.getSizeInBytes(); + } + + // Loop thru the vertex format elements adding the array state... + U32 texCoordIndex = 0; + for ( U32 i=0; i < mFormat->getElementCount(); i++ ) + { + const GFXVertexElement &element = mFormat->getElement( i ); + + if(element.getStreamIndex() != stream) + continue; + + glVerticesFormat.increment(); + glVertexAttribData &glElement = glVerticesFormat.last(); + glElement.stream = element.getStreamIndex(); + + if ( element.isSemantic( GFXSemantic::POSITION ) ) + { + glElement.attrIndex = Torque::GL_VertexAttrib_Position; + glElement.elementCount = element.getSizeInBytes() / 4; + glElement.normalized = false; + glElement.type = GL_FLOAT; + glElement.stride = vertexSize; + glElement.pointerFirst = (void*)buffer; + + buffer += element.getSizeInBytes(); + } + else if ( element.isSemantic( GFXSemantic::NORMAL ) ) + { + glElement.attrIndex = Torque::GL_VertexAttrib_Normal; + glElement.elementCount = 3; + glElement.normalized = false; + glElement.type = GL_FLOAT; + glElement.stride = vertexSize; + glElement.pointerFirst = (void*)buffer; + + buffer += element.getSizeInBytes(); + } + else if ( element.isSemantic( GFXSemantic::TANGENT ) ) + { + glElement.attrIndex = Torque::GL_VertexAttrib_Tangent; + glElement.elementCount = 3; + glElement.normalized = false; + glElement.type = GL_FLOAT; + glElement.stride = vertexSize; + glElement.pointerFirst = (void*)buffer; + + buffer += element.getSizeInBytes(); + } + else if ( element.isSemantic( GFXSemantic::TANGENTW ) ) + { + glElement.attrIndex = Torque::GL_VertexAttrib_TangentW; + glElement.elementCount = element.getSizeInBytes()/4; + glElement.normalized = false; + glElement.type = GL_FLOAT; + glElement.stride = vertexSize; + glElement.pointerFirst = (void*)buffer; + + buffer += element.getSizeInBytes(); + } + else if ( element.isSemantic( GFXSemantic::BINORMAL ) ) + { + glElement.attrIndex = Torque::GL_VertexAttrib_Binormal; + glElement.elementCount = 3; + glElement.normalized = false; + glElement.type = GL_FLOAT; + glElement.stride = vertexSize; + glElement.pointerFirst = (void*)buffer; + + buffer += element.getSizeInBytes(); + } + else if ( element.isSemantic( GFXSemantic::COLOR ) ) + { + glElement.attrIndex = Torque::GL_VertexAttrib_Color; + glElement.elementCount = element.getSizeInBytes(); + glElement.normalized = true; + glElement.type = GL_UNSIGNED_BYTE; + glElement.stride = vertexSize; + glElement.pointerFirst = (void*)buffer; + + buffer += element.getSizeInBytes(); + } + else // Everything else is a texture coordinate. + { + String name = element.getSemantic(); + glElement.elementCount = element.getSizeInBytes() / 4; + texCoordIndex = getMax(texCoordIndex, element.getSemanticIndex()); + glElement.attrIndex = Torque::GL_VertexAttrib_TexCoord0 + texCoordIndex; + + glElement.normalized = false; + glElement.type = GL_FLOAT; + glElement.stride = vertexSize; + glElement.pointerFirst = (void*)buffer; + + buffer += element.getSizeInBytes(); + ++texCoordIndex; + } + + AssertFatal(!( mVertexAttribActiveMask & BIT(glElement.attrIndex) ), "GFXGLVertexBuffer::_initVerticesFormat - Duplicate vertex attrib index"); + mVertexAttribActiveMask |= BIT(glElement.attrIndex); + } + + mVertexSize[stream] = vertexSize; + AssertFatal(vertexSize == buffer, ""); +} \ No newline at end of file diff --git a/Engine/source/gfx/gl/gfxGLVertexDecl.h b/Engine/source/gfx/gl/gfxGLVertexDecl.h new file mode 100644 index 000000000..545694323 --- /dev/null +++ b/Engine/source/gfx/gl/gfxGLVertexDecl.h @@ -0,0 +1,39 @@ +#ifndef GFX_GL_VERTEX_DECL +#define GFX_GL_VERTEX_DECL + +class GFXVertexFormat; +class GFXGLDevice; + +class GFXGLVertexDecl : public GFXVertexDecl +{ +public: + GFXGLVertexDecl() : mFormat(NULL), mVertexAttribActiveMask(0) {} + void init(const GFXVertexFormat *format); + + void prepareVertexFormat() const; + void prepareBuffer_old(U32 stream, GLint mBuffer, GLint mDivisor) const; + void updateActiveVertexAttrib(U32 lastActiveMask) const; + + struct glVertexAttribData + { + U32 stream; + GLint attrIndex; + GLint elementCount; // 1 - 4 + GLenum type; // GL_FLOAT... + GLboolean normalized; + GLsizei stride; + GLvoid *pointerFirst; + }; + +protected: + friend class GFXGLDevice; + const GFXVertexFormat *mFormat; + GLuint mVertexSize[4]; + U32 mVertexAttribActiveMask; + Vector glVerticesFormat; + + void _initVerticesFormat(U32 stream); + void _initVerticesFormat2(); +}; + +#endif //GFX_GL_VERTEX_DECL \ No newline at end of file diff --git a/Engine/source/gfx/gl/gfxGLWindowTarget.cpp b/Engine/source/gfx/gl/gfxGLWindowTarget.cpp index 852cd8359..c02ff1bc3 100644 --- a/Engine/source/gfx/gl/gfxGLWindowTarget.cpp +++ b/Engine/source/gfx/gl/gfxGLWindowTarget.cpp @@ -25,9 +25,19 @@ #include "gfx/gl/gfxGLWindowTarget.h" #include "gfx/gl/gfxGLTextureObject.h" #include "gfx/gl/gfxGLUtils.h" +#include "postFx/postEffect.h" + +GFX_ImplementTextureProfile( BackBufferDepthProfile, + GFXTextureProfile::DiffuseMap, + GFXTextureProfile::PreserveSize | + GFXTextureProfile::NoMipmap | + GFXTextureProfile::ZTarget | + GFXTextureProfile::Pooled, + GFXTextureProfile::NONE ); GFXGLWindowTarget::GFXGLWindowTarget(PlatformWindow *win, GFXDevice *d) : GFXWindowTarget(win), mDevice(d), mContext(NULL), mFullscreenContext(NULL) + , mCopyFBO(0), mBackBufferFBO(0) { win->appEvent.notify(this, &GFXGLWindowTarget::_onAppSignal); } @@ -59,21 +69,85 @@ void GFXGLWindowTarget::resolveTo(GFXTextureObject* obj) AssertFatal(dynamic_cast(obj), "GFXGLTextureTarget::resolveTo - Incorrect type of texture, expected a GFXGLTextureObject"); GFXGLTextureObject* glTexture = static_cast(obj); + if( gglHasExtension(ARB_copy_image) ) + { + if(mBackBufferColorTex.getWidth() == glTexture->getWidth() + && mBackBufferColorTex.getHeight() == glTexture->getHeight() + && mBackBufferColorTex.getFormat() == glTexture->getFormat()) + { + glCopyImageSubData( + static_cast(mBackBufferColorTex.getPointer())->getHandle(), GL_TEXTURE_2D, 0, 0, 0, 0, + glTexture->getHandle(), GL_TEXTURE_2D, 0, 0, 0, 0, + getSize().x, getSize().y, 1); + return; + } + } + PRESERVE_FRAMEBUFFER(); + + if(!mCopyFBO) + { + glGenFramebuffers(1, &mCopyFBO); + } - GLuint dest; + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mCopyFBO); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glTexture->getHandle(), 0); - glGenFramebuffersEXT(1, &dest); + glBindFramebuffer(GL_READ_FRAMEBUFFER, mBackBufferFBO); - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, dest); - glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, glTexture->getHandle(), 0); - - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); - - glBlitFramebufferEXT(0, 0, getSize().x, getSize().y, + glBlitFramebuffer(0, 0, getSize().x, getSize().y, 0, 0, glTexture->getWidth(), glTexture->getHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST); - - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); - - glDeleteFramebuffersEXT(1, &dest); +} + +inline void GFXGLWindowTarget::_setupAttachments() +{ + glBindFramebuffer( GL_FRAMEBUFFER, mBackBufferFBO); + GFXGL->getOpenglCache()->setCacheBinded(GL_FRAMEBUFFER, mBackBufferFBO); + const Point2I dstSize = getSize(); + mBackBufferColorTex.set(dstSize.x, dstSize.y, getFormat(), &PostFxTargetProfile, "backBuffer"); + GFXGLTextureObject *color = static_cast(mBackBufferColorTex.getPointer()); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color->getHandle(), 0); + mBackBufferDepthTex.set(dstSize.x, dstSize.y, GFXFormatD24S8, &BackBufferDepthProfile, "backBuffer"); + GFXGLTextureObject *depth = static_cast(mBackBufferDepthTex.getPointer()); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth->getHandle(), 0); +} + +void GFXGLWindowTarget::makeActive() +{ + if(mBackBufferFBO) + { + glBindFramebuffer( GL_FRAMEBUFFER, mBackBufferFBO); + GFXGL->getOpenglCache()->setCacheBinded(GL_FRAMEBUFFER, mBackBufferFBO); + } + else + { + glGenFramebuffers(1, &mBackBufferFBO); + _setupAttachments(); + CHECK_FRAMEBUFFER_STATUS(); + } +} + +bool GFXGLWindowTarget::present() +{ + PRESERVE_FRAMEBUFFER(); + + const Point2I srcSize = mBackBufferColorTex.getWidthHeight(); + const Point2I dstSize = getSize(); + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, mBackBufferFBO); + + // OpenGL render upside down for make render more similar to DX. + // Final screen are corrected here + glBlitFramebuffer( + 0, 0, srcSize.x, srcSize.y, + 0, dstSize.y, dstSize.x, 0, // Y inverted + GL_COLOR_BUFFER_BIT, GL_NEAREST); + + _WindowPresent(); + + if(srcSize != dstSize || mBackBufferDepthTex.getWidthHeight() != dstSize) + _setupAttachments(); + + return true; } diff --git a/Engine/source/gfx/gl/gfxGLWindowTarget.h b/Engine/source/gfx/gl/gfxGLWindowTarget.h index 88aa6a6f7..4baa6a53f 100644 --- a/Engine/source/gfx/gl/gfxGLWindowTarget.h +++ b/Engine/source/gfx/gl/gfxGLWindowTarget.h @@ -51,12 +51,17 @@ public: private: friend class GFXGLDevice; + + GLuint mCopyFBO, mBackBufferFBO; + GFXTexHandle mBackBufferColorTex, mBackBufferDepthTex; Point2I size; GFXDevice* mDevice; void* mContext; void* mFullscreenContext; void _teardownCurrentMode(); void _setupNewMode(); + void _setupAttachments(); + void _WindowPresent(); }; #endif \ No newline at end of file diff --git a/Engine/source/gfx/gl/sdl/gfxGLDevice.sdl.cpp b/Engine/source/gfx/gl/sdl/gfxGLDevice.sdl.cpp new file mode 100644 index 000000000..b2e9aaba5 --- /dev/null +++ b/Engine/source/gfx/gl/sdl/gfxGLDevice.sdl.cpp @@ -0,0 +1,225 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- +#if defined( TORQUE_SDL ) + +#include "gfx/gfxCubemap.h" +#include "gfx/screenshot.h" + +#include "gfx/gl/gfxGLDevice.h" +#include "gfx/gl/gfxGLEnumTranslate.h" +#include "gfx/gl/gfxGLVertexBuffer.h" +#include "gfx/gl/gfxGLPrimitiveBuffer.h" +#include "gfx/gl/gfxGLTextureTarget.h" +#include "gfx/gl/gfxGLWindowTarget.h" +#include "gfx/gl/gfxGLTextureManager.h" +#include "gfx/gl/gfxGLTextureObject.h" +#include "gfx/gl/gfxGLCubemap.h" +#include "gfx/gl/gfxGLCardProfiler.h" + +#include "windowManager/sdl/sdlWindow.h" +#include "platform/platformGL.h" +#include "SDL.h" + +extern void loadGLCore(); +extern void loadGLExtensions(void* context); + +void EnumerateVideoModes(Vector& outModes) +{ + int count = SDL_GetNumDisplayModes( 0 ); + if( count < 0) + { + AssertFatal(0, ""); + return; + } + + SDL_DisplayMode mode; + for(int i = 0; i < count; ++i) + { + SDL_GetDisplayMode( 0, i, &mode); + GFXVideoMode outMode; + outMode.resolution.set( mode.w, mode.h ); + outMode.refreshRate = mode.refresh_rate; + outMode.bitDepth = SDL_BYTESPERPIXEL( mode.format ); + outMode.wideScreen = (mode.w / mode.h) > (4 / 3); + outMode.fullScreen = true; + + outModes.push_back( outMode ); + } +} + +void GFXGLDevice::enumerateAdapters( Vector &adapterList ) +{ + AssertFatal( SDL_WasInit(SDL_INIT_VIDEO), ""); + + PlatformGL::init(); // for hints about context creation + + // Create a dummy window & openGL context so that gl functions can be used here + SDL_Window* tempWindow = SDL_CreateWindow( + "", // window title + SDL_WINDOWPOS_UNDEFINED, // initial x position + SDL_WINDOWPOS_UNDEFINED, // initial y position + 640, // width, in pixels + 480, // height, in pixels + SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN // flags - see below + ); + + SDL_ClearError(); + SDL_GLContext tempContext = SDL_GL_CreateContext( tempWindow ); + if( !tempContext ) + { + const char *err = SDL_GetError(); + Con::printf( err ); + AssertFatal(0, err ); + return; + } + + SDL_ClearError(); + SDL_GL_MakeCurrent( tempWindow, tempContext ); + + const char *err = SDL_GetError(); + if( err && err[0] ) + { + Con::printf( err ); + AssertFatal(0, err ); + } + + //check minimun Opengl 3.2 + int major, minor; + glGetIntegerv(GL_MAJOR_VERSION, &major); + glGetIntegerv(GL_MINOR_VERSION, &minor); + if( major < 3 || ( major == 3 && minor < 2 ) ) + { + return; + } + + loadGLCore(); + + GFXAdapter *toAdd = new GFXAdapter; + toAdd->mIndex = 0; + + const char* renderer = (const char*) glGetString( GL_RENDERER ); + AssertFatal( renderer != NULL, "GL_RENDERER returned NULL!" ); + + if (renderer) + { + dStrcpy(toAdd->mName, renderer); + dStrncat(toAdd->mName, " OpenGL", GFXAdapter::MaxAdapterNameLen); + } + else + dStrcpy(toAdd->mName, "OpenGL"); + + toAdd->mType = OpenGL; + toAdd->mShaderModel = 0.f; + toAdd->mCreateDeviceInstanceDelegate = mCreateDeviceInstance; + + // Enumerate all available resolutions: + EnumerateVideoModes(toAdd->mAvailableModes); + + // Add to the list of available adapters. + adapterList.push_back(toAdd); + + // Cleanup window & open gl context + SDL_DestroyWindow( tempWindow ); + SDL_GL_DeleteContext( tempContext ); +} + +void GFXGLDevice::enumerateVideoModes() +{ + mVideoModes.clear(); + EnumerateVideoModes(mVideoModes); +} + +void GFXGLDevice::init( const GFXVideoMode &mode, PlatformWindow *window ) +{ + AssertFatal(window, "GFXGLDevice::init - no window specified, can't init device without a window!"); + PlatformWindowSDL* x11Window = dynamic_cast(window); + AssertFatal(x11Window, "Window is not a valid PlatformWindowSDL object"); + + // Create OpenGL context + mContext = PlatformGL::CreateContextGL( x11Window ); + PlatformGL::MakeCurrentGL( x11Window, mContext ); + + loadGLCore(); + loadGLExtensions(0); + + // It is very important that extensions be loaded before we call initGLState() + initGLState(); + + mProjectionMatrix.identity(); + + mInitialized = true; + deviceInited(); +} + +bool GFXGLDevice::beginSceneInternal() +{ + mCanCurrentlyRender = true; + return true; +} + +U32 GFXGLDevice::getTotalVideoMemory() +{ + return getTotalVideoMemory_GL_EXT(); +} + +//------------------------------------------------------------------------------ + +GFXWindowTarget *GFXGLDevice::allocWindowTarget( PlatformWindow *window ) +{ + AssertFatal(!mContext, "This GFXGLDevice is already assigned to a window"); + + GFXGLWindowTarget* ggwt = 0; + if( !mContext ) + { + // no context, init the device now + init(window->getVideoMode(), window); + ggwt = new GFXGLWindowTarget(window, this); + ggwt->registerResourceWithDevice(this); + ggwt->mContext = mContext; + } + + return ggwt; +} + +GFXFence* GFXGLDevice::_createPlatformSpecificFence() +{ + return NULL; +} + + +//----------------------------------------------------------------------------- + +void GFXGLWindowTarget::_WindowPresent() +{ + SDL_GL_SwapWindow( static_cast( getWindow() )->getSDLWindow() ); +} + +void GFXGLWindowTarget::_teardownCurrentMode() +{ + +} + +void GFXGLWindowTarget::_setupNewMode() +{ +} + +#endif diff --git a/Engine/source/gfx/gl/tGL/tGL.cpp b/Engine/source/gfx/gl/tGL/tGL.cpp new file mode 100644 index 000000000..94953b487 --- /dev/null +++ b/Engine/source/gfx/gl/tGL/tGL.cpp @@ -0,0 +1,41 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "tGL.h" + +#include "core/strings/stringFunctions.h" +#include "console/console.h" + +namespace GL +{ + void gglPerformBinds() + { + GLenum err = glewInit(); + AssertFatal(GLEW_OK == err, avar("Error: %s\n", glewGetErrorString(err)) ); + } + + void gglPerformExtensionBinds(void *context) + { + + } +} + diff --git a/Engine/source/gfx/gl/tGL/tGL.h b/Engine/source/gfx/gl/tGL/tGL.h new file mode 100644 index 000000000..aa1275ee5 --- /dev/null +++ b/Engine/source/gfx/gl/tGL/tGL.h @@ -0,0 +1,30 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef T_GL_H +#define T_GL_H +#include "GL/glew.h" + +#define gglHasExtension(EXTENSION) GLEW_##EXTENSION + +#endif + diff --git a/Engine/source/gfx/gl/tGL/tWGL.h b/Engine/source/gfx/gl/tGL/tWGL.h new file mode 100644 index 000000000..d6575ae2d --- /dev/null +++ b/Engine/source/gfx/gl/tGL/tWGL.h @@ -0,0 +1,38 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef GFX_TORQUE_WGL_H +#define GFX_TORQUE_WGL_H + +#include "platform/platform.h" + +#ifdef TORQUE_OS_WIN32 + +#include "tGL.h" +#include "GL/wglew.h" + +#define gglHasWExtension(EXTENSION) WGLEW_##EXTENSION + +#endif //TORQUE_OS_WIN32 + +#endif + diff --git a/Engine/source/gfx/gl/tGL/tXGL.h b/Engine/source/gfx/gl/tGL/tXGL.h new file mode 100644 index 000000000..0cf2df966 --- /dev/null +++ b/Engine/source/gfx/gl/tGL/tXGL.h @@ -0,0 +1,38 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef GFX_TORQUE_XGL_H +#define GFX_TORQUE_XGL_H + +#include "platform/platform.h" + +#ifdef TORQUE_OS_LINUX + +#include "tGL.h" +#include "GL/glxew.h" + +#define gglHasXExtension(EXTENSION) GLXEW##EXTENSION + +#endif //TORQUE_OS_LINUX + +#endif + diff --git a/Engine/source/gfx/gl/util/glFrameAllocatorLockableHelper.h b/Engine/source/gfx/gl/util/glFrameAllocatorLockableHelper.h new file mode 100644 index 000000000..218427cc1 --- /dev/null +++ b/Engine/source/gfx/gl/util/glFrameAllocatorLockableHelper.h @@ -0,0 +1,53 @@ +#ifndef GL_FRAMEALLOCATOR_LOCKABLE_HELPER_H +#define GL_FRAMEALLOCATOR_LOCKABLE_HELPER_H + +#include "core/frameAllocator.h" + +/// Helper class for simulate lock/unlock on gfx buffers using FrameAllocator +class FrameAllocatorLockableHelper +{ +public: + FrameAllocatorLockableHelper() + : mFrameAllocatorMark(0), + mFrameAllocatorPtr(NULL) +#if TORQUE_DEBUG + , mFrameAllocatorMarkGuard(0) +#endif + { + + } + + U8* lock(const U32 size) + { + AssertFatal(!mFrameAllocatorMark && !mFrameAllocatorPtr, ""); + mFrameAllocatorMark = FrameAllocator::getWaterMark(); + mFrameAllocatorPtr = (U8*)FrameAllocator::alloc( size ); +#if TORQUE_DEBUG + mFrameAllocatorMarkGuard = FrameAllocator::getWaterMark(); +#endif + + return mFrameAllocatorPtr; + } + + void unlock() + { +#if TORQUE_DEBUG + AssertFatal(mFrameAllocatorMarkGuard == FrameAllocator::getWaterMark(), ""); +#endif + FrameAllocator::setWaterMark(mFrameAllocatorMark); + mFrameAllocatorMark = 0; + mFrameAllocatorPtr = NULL; + } + + U8* getlockedPtr() const { return mFrameAllocatorPtr; } + +protected: + U32 mFrameAllocatorMark; + U8 *mFrameAllocatorPtr; + +#if TORQUE_DEBUG + U32 mFrameAllocatorMarkGuard; +#endif +}; + +#endif //GL_FRAMEALLOCATOR_LOCKABLE_HELPER_H diff --git a/Engine/source/gfx/gl/gfxGLDevice.win.cpp b/Engine/source/gfx/gl/win32/gfxGLDevice.win.cpp similarity index 77% rename from Engine/source/gfx/gl/gfxGLDevice.win.cpp rename to Engine/source/gfx/gl/win32/gfxGLDevice.win.cpp index d68b9ea2e..f2f81b8fa 100644 --- a/Engine/source/gfx/gl/gfxGLDevice.win.cpp +++ b/Engine/source/gfx/gl/win32/gfxGLDevice.win.cpp @@ -35,7 +35,10 @@ #include "gfx/GL/gfxGLCubemap.h" #include "gfx/GL/gfxGLCardProfiler.h" #include "windowManager/win32/win32Window.h" -#include "ggl/Win32/wgl.h" +#include "gfx/gl/tGL/tWGL.h" + +#include "postFx/postEffect.h" +#include "gfx/gl/gfxGLUtils.h" #define GETHWND(x) static_cast(x)->getHWND() @@ -105,7 +108,7 @@ void GFXGLDevice::enumerateAdapters( Vector &adapterList ) // Create pixel format descriptor... PIXELFORMATDESCRIPTOR pfd; - CreatePixelFormat( &pfd, 16, 16, 8, false ); // 16 bit color, 16 bit depth, 8 bit stencil...everyone can do this + CreatePixelFormat( &pfd, 32, 0, 0, false ); if( !SetPixelFormat( tempDC, ChoosePixelFormat( tempDC, &pfd ), &pfd ) ) AssertFatal( false, "I don't know who's responcible for this, but I want caught..." ); @@ -239,6 +242,8 @@ void GFXGLDevice::init( const GFXVideoMode &mode, PlatformWindow *window ) AssertFatal(dynamic_cast(window), "Invalid window class type!"); HWND hwnd = GETHWND(window); + mWindowRT = &static_cast(window)->mTarget; + RECT rect; GetClientRect(hwnd, &rect); @@ -252,14 +257,41 @@ void GFXGLDevice::init( const GFXVideoMode &mode, PlatformWindow *window ) // Create pixel format descriptor... PIXELFORMATDESCRIPTOR pfd; - CreatePixelFormat( &pfd, 16, 16, 8, false ); // 16 bit color, 16 bit depth, 8 bit stencil...everyone can do this + CreatePixelFormat( &pfd, 32, 0, 0, false ); // 32 bit color... We do not need depth or stencil, OpenGL renders into a FBO and then copy the image to window if( !SetPixelFormat( hdcGL, ChoosePixelFormat( hdcGL, &pfd ), &pfd ) ) { AssertFatal( false, "GFXGLDevice::init - cannot get the one and only pixel format we check for." ); } - // Create a rendering context! - mContext = wglCreateContext( hdcGL ); + int OGL_MAJOR = 3; + int OGL_MINOR = 2; + +#if TORQUE_DEBUG + int debugFlag = WGL_CONTEXT_DEBUG_BIT_ARB; +#else + int debugFlag = 0; +#endif + + if( gglHasWExtension(ARB_create_context) ) + { + int const create_attribs[] = { + WGL_CONTEXT_MAJOR_VERSION_ARB, OGL_MAJOR, + WGL_CONTEXT_MINOR_VERSION_ARB, OGL_MINOR, + WGL_CONTEXT_FLAGS_ARB, /*WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB |*/ debugFlag, + WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, + //WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, + 0 + }; + + mContext = wglCreateContextAttribsARB(hdcGL, 0, create_attribs); + if(!mContext) + { + AssertFatal(0,""); + } + } + else + mContext = wglCreateContext( hdcGL ); + if( !wglMakeCurrent( hdcGL, (HGLRC)mContext ) ) AssertFatal( false , "GFXGLDevice::init - cannot make our context current. Or maybe we can't create it." ); @@ -280,101 +312,30 @@ void GFXGLDevice::init( const GFXVideoMode &mode, PlatformWindow *window ) bool GFXGLDevice::beginSceneInternal() { - glGetError(); + mCanCurrentlyRender = true; return true; } U32 GFXGLDevice::getTotalVideoMemory() { - // CodeReview [ags 12/21/07] Figure out how to do this. - return 0; + return getTotalVideoMemory_GL_EXT(); } //------------------------------------------------------------------------------ GFXWindowTarget *GFXGLDevice::allocWindowTarget( PlatformWindow *window ) { - HDC hdcGL = GetDC(GETHWND(window)); - - if(!mContext) - { - init(window->getVideoMode(), window); - GFXGLWindowTarget *ggwt = new GFXGLWindowTarget(window, this); - ggwt->registerResourceWithDevice(this); - ggwt->mContext = wglCreateContext(hdcGL); - AssertFatal(ggwt->mContext, "GFXGLDevice::allocWindowTarget - failed to allocate window target!"); - - return ggwt; - } - + AssertFatal(!mContext, ""); + + init(window->getVideoMode(), window); GFXGLWindowTarget *ggwt = new GFXGLWindowTarget(window, this); ggwt->registerResourceWithDevice(this); - - // Create pixel format descriptor... - PIXELFORMATDESCRIPTOR pfd; - CreatePixelFormat( &pfd, 16, 16, 8, false ); // 16 bit color, 16 bit depth, 8 bit stencil...everyone can do this - if( !SetPixelFormat( hdcGL, ChoosePixelFormat( hdcGL, &pfd ), &pfd ) ) - { - AssertFatal( false, "GFXGLDevice::allocWindowTarget - cannot get the one and only pixel format we check for." ); - } - - ggwt->mContext = wglCreateContext(hdcGL); - DWORD w = GetLastError(); + ggwt->mContext = mContext; AssertFatal(ggwt->mContext, "GFXGLDevice::allocWindowTarget - failed to allocate window target!"); - wglMakeCurrent(NULL, NULL); - bool res = wglShareLists((HGLRC)mContext, (HGLRC)ggwt->mContext); - w = GetLastError(); - - wglMakeCurrent(hdcGL, (HGLRC)ggwt->mContext); - AssertFatal(res, "GFXGLDevice::allocWindowTarget - wasn't able to share contexts!"); - return ggwt; } -void GFXGLDevice::_updateRenderTargets() -{ - if ( mRTDirty || mCurrentRT->isPendingState() ) - { - // GL doesn't need to deactivate targets. - mRTDeactivate = NULL; - - // NOTE: The render target changes is not really accurate - // as the GFXTextureTarget supports MRT internally. So when - // we activate a GFXTarget it could result in multiple calls - // to SetRenderTarget on the actual device. - mDeviceStatistics.mRenderTargetChanges++; - - GFXGLTextureTarget *tex = dynamic_cast( mCurrentRT.getPointer() ); - if ( tex ) - { - tex->applyState(); - tex->makeActive(); - } - else - { - GFXGLWindowTarget *win = dynamic_cast( mCurrentRT.getPointer() ); - AssertFatal( win != NULL, - "GFXGLDevice::_updateRenderTargets() - invalid target subclass passed!" ); - - //DWORD w1 = GetLastError(); - HWND hwnd = GETHWND(win->getWindow()); - HDC winDc = GetDC(hwnd); - bool res = wglMakeCurrent(winDc,(HGLRC)win->mContext); - //DWORD w2 = GetLastError(); - AssertFatal(res==true,"GFXGLDevice::setActiveRenderTarget - failed"); - } - - mRTDirty = false; - } - - if ( mViewportDirty ) - { - glViewport( mViewport.point.x, mViewport.point.y, mViewport.extent.x, mViewport.extent.y ); - mViewportDirty = false; - } -} - GFXFence* GFXGLDevice::_createPlatformSpecificFence() { return NULL; @@ -382,16 +343,10 @@ GFXFence* GFXGLDevice::_createPlatformSpecificFence() //----------------------------------------------------------------------------- - -void GFXGLWindowTarget::makeActive() -{ -} - -bool GFXGLWindowTarget::present() +void GFXGLWindowTarget::_WindowPresent() { HWND hwnd = GETHWND(getWindow()); SwapBuffers(GetDC(hwnd)); - return true; } void GFXGLWindowTarget::_teardownCurrentMode() diff --git a/Engine/source/lighting/advanced/advancedLightBufferConditioner.cpp b/Engine/source/lighting/advanced/advancedLightBufferConditioner.cpp index 5dff21fb4..55d9a2e5f 100644 --- a/Engine/source/lighting/advanced/advancedLightBufferConditioner.cpp +++ b/Engine/source/lighting/advanced/advancedLightBufferConditioner.cpp @@ -142,7 +142,7 @@ Var *AdvancedLightBufferConditioner::printMethodHeader( MethodType methodType, c meta->addStatement( new GenOp( " -1.0217f, 1.9777f, 0.0439f,\r\n" ) ); meta->addStatement( new GenOp( " 0.0753f, -0.2543f, 1.1892f\r\n" ) ); meta->addStatement( new GenOp( " };\r\n" ) ); - meta->addStatement( new GenOp( " return mul(XYZ2RGB, XYZ);\r\n" ) ); + meta->addStatement( new GenOp( " return tMul(XYZ2RGB, XYZ);\r\n" ) ); meta->addStatement( new GenOp( "}\r\n\r\n" ) ); } else diff --git a/Engine/source/lighting/advanced/advancedLightManager.cpp b/Engine/source/lighting/advanced/advancedLightManager.cpp index 96a4b926c..29adfcc08 100644 --- a/Engine/source/lighting/advanced/advancedLightManager.cpp +++ b/Engine/source/lighting/advanced/advancedLightManager.cpp @@ -35,6 +35,8 @@ #include "math/util/sphereMesh.h" #include "console/consoleTypes.h" #include "scene/sceneRenderState.h" +#include "gfx/gfxCardProfile.h" +#include "gfx/gfxTextureProfile.h" ImplementEnumType( ShadowType, @@ -81,6 +83,9 @@ bool AdvancedLightManager::isCompatible() const return false; // TODO: Test for the necessary texture formats! + bool autoMips; + if(!GFX->getCardProfiler()->checkFormat(GFXFormatR16F, &GFXDefaultRenderTargetProfile, autoMips)) + return false; return true; } diff --git a/Engine/source/materials/materialManager.cpp b/Engine/source/materials/materialManager.cpp index e0d04e9ad..5f48adf9b 100644 --- a/Engine/source/materials/materialManager.cpp +++ b/Engine/source/materials/materialManager.cpp @@ -81,13 +81,13 @@ MaterialManager::MaterialManager() Con::addVariableNotify( "$pref::Video::defaultAnisotropy", callabck ); Con::NotifyDelegate callabck2( this, &MaterialManager::_onDisableMaterialFeature ); - Con::setVariable( "$pref::Video::disableNormalMapping", false ); + Con::setVariable( "$pref::Video::disableNormalMapping", "false" ); Con::addVariableNotify( "$pref::Video::disableNormalMapping", callabck2 ); - Con::setVariable( "$pref::Video::disablePixSpecular", false ); + Con::setVariable( "$pref::Video::disablePixSpecular", "false" ); Con::addVariableNotify( "$pref::Video::disablePixSpecular", callabck2 ); - Con::setVariable( "$pref::Video::disableCubemapping", false ); + Con::setVariable( "$pref::Video::disableCubemapping", "false" ); Con::addVariableNotify( "$pref::Video::disableCubemapping", callabck2 ); - Con::setVariable( "$pref::Video::disableParallaxMapping", false ); + Con::setVariable( "$pref::Video::disableParallaxMapping", "false" ); Con::addVariableNotify( "$pref::Video::disableParallaxMapping", callabck2 ); } @@ -416,6 +416,9 @@ void MaterialManager::recalcFeaturesFromPrefs() mExclusionFeatures.setFeature( MFT_NormalMap, Con::getBoolVariable( "$pref::Video::disableNormalMapping", false ) ); + mExclusionFeatures.setFeature( MFT_SpecularMap, + Con::getBoolVariable( "$pref::Video::disablePixSpecular", false ) ); + mExclusionFeatures.setFeature( MFT_PixSpecular, Con::getBoolVariable( "$pref::Video::disablePixSpecular", false ) ); diff --git a/Engine/source/platform/platformGL.h b/Engine/source/platform/platformGL.h new file mode 100644 index 000000000..7cca42a64 --- /dev/null +++ b/Engine/source/platform/platformGL.h @@ -0,0 +1,17 @@ +#ifndef PLATFORM_GL_H +#define PLATFORM_GL_H + +class PlatformWindow; + +namespace PlatformGL +{ + void init(); + + void* CreateContextGL( PlatformWindow *window ); + + void MakeCurrentGL( PlatformWindow *window, void *glContext ); + + void setVSync(const int i); +} + +#endif //PLATFORM_GL_H diff --git a/Engine/source/platformWin32/WinPlatformGL.cpp b/Engine/source/platformWin32/WinPlatformGL.cpp new file mode 100644 index 000000000..5413d37b7 --- /dev/null +++ b/Engine/source/platformWin32/WinPlatformGL.cpp @@ -0,0 +1,11 @@ +#if defined(TORQUE_OPENGL) && !defined(TORQUE_SDL) + +#include "platform/platformGL.h" +#include "gfx/gl/tGL/tWGL.h" + +void PlatformGL::setVSync(const int i) +{ + wglSwapIntervalEXT( i ); +} + +#endif \ No newline at end of file diff --git a/Engine/source/renderInstance/renderPrePassMgr.cpp b/Engine/source/renderInstance/renderPrePassMgr.cpp index bb64d1dd7..4bf1870f1 100644 --- a/Engine/source/renderInstance/renderPrePassMgr.cpp +++ b/Engine/source/renderInstance/renderPrePassMgr.cpp @@ -834,12 +834,12 @@ Var* LinearEyeDepthConditioner::printMethodHeader( MethodType methodType, const // possible so that the shader compiler can optimize. meta->addStatement( new GenOp( " #if TORQUE_SM >= 30\r\n" ) ); if (GFX->getAdapterType() == OpenGL) - meta->addStatement( new GenOp( " @ = texture2DLod(@, @, 0); \r\n", bufferSampleDecl, prepassSampler, screenUV) ); + meta->addStatement( new GenOp( " @ = textureLod(@, @, 0); \r\n", bufferSampleDecl, prepassSampler, screenUV) ); else meta->addStatement( new GenOp( " @ = tex2Dlod(@, float4(@,0,0));\r\n", bufferSampleDecl, prepassSampler, screenUV ) ); meta->addStatement( new GenOp( " #else\r\n" ) ); if (GFX->getAdapterType() == OpenGL) - meta->addStatement( new GenOp( " @ = texture2D(@, @);\r\n", bufferSampleDecl, prepassSampler, screenUV) ); + meta->addStatement( new GenOp( " @ = texture(@, @);\r\n", bufferSampleDecl, prepassSampler, screenUV) ); else meta->addStatement( new GenOp( " @ = tex2D(@, @);\r\n", bufferSampleDecl, prepassSampler, screenUV ) ); meta->addStatement( new GenOp( " #endif\r\n\r\n" ) ); diff --git a/Engine/source/shaderGen/GLSL/bumpGLSL.cpp b/Engine/source/shaderGen/GLSL/bumpGLSL.cpp index 1b1cd0437..07f874f8b 100644 --- a/Engine/source/shaderGen/GLSL/bumpGLSL.cpp +++ b/Engine/source/shaderGen/GLSL/bumpGLSL.cpp @@ -384,6 +384,7 @@ void ParallaxFeatGLSL::setTexData( Material::StageData &stageDat, GFXTextureObject *tex = stageDat.getTex( MFT_NormalMap ); if ( tex ) { + passData.mSamplerNames[ texIndex ] = "bumpMap"; passData.mTexType[ texIndex ] = Material::Bump; passData.mTexSlot[ texIndex++ ].texObject = tex; } diff --git a/Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp b/Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp index c8942f454..8a56e03c5 100644 --- a/Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp +++ b/Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp @@ -1073,7 +1073,10 @@ void OverlayTexFeatGLSL::setTexData( Material::StageData &stageDat, { GFXTextureObject *tex = stageDat.getTex( MFT_OverlayMap ); if ( tex ) + { + passData.mSamplerNames[ texIndex ] = "overlayMap"; passData.mTexSlot[ texIndex++ ].texObject = tex; + } } @@ -2383,7 +2386,7 @@ void GlowMaskGLSL::processPix( Vector &componentList, // code above that doesn't contribute to the alpha mask. Var *color = (Var*)LangElement::find( "col" ); if ( color ) - output = new GenOp( " @.rgb = 0;\r\n", color ); + output = new GenOp( " @.rgb = vec3(0);\r\n", color ); } diff --git a/Engine/source/shaderGen/langElement.cpp b/Engine/source/shaderGen/langElement.cpp index 60db59a0a..315fe4fca 100644 --- a/Engine/source/shaderGen/langElement.cpp +++ b/Engine/source/shaderGen/langElement.cpp @@ -22,7 +22,7 @@ #include "core/strings/stringFunctions.h" #include "core/util/str.h" - +#include "gfx/gfxDevice.h" #include "langElement.h" //************************************************************************** @@ -158,6 +158,9 @@ void Var::print( Stream &stream ) if( structName[0] != '\0' ) { stream.write( dStrlen((char*)structName), structName ); + if(GFX->getAdapterType() == OpenGL) + stream.write( 1, "_" ); + else stream.write( 1, "." ); } diff --git a/Engine/source/terrain/hlsl/terrFeatureHLSL.cpp b/Engine/source/terrain/hlsl/terrFeatureHLSL.cpp index e5025cf30..94c7e4943 100644 --- a/Engine/source/terrain/hlsl/terrFeatureHLSL.cpp +++ b/Engine/source/terrain/hlsl/terrFeatureHLSL.cpp @@ -30,15 +30,16 @@ #include "shaderGen/langElement.h" #include "shaderGen/shaderOp.h" #include "shaderGen/featureMgr.h" +#include "shaderGen/shaderGen.h" #include "core/module.h" - -MODULE_BEGIN( TerrainFeatHLSL ) - - MODULE_INIT_AFTER( ShaderGenFeatureMgr ) - - MODULE_INIT +namespace +{ + void register_hlsl_shader_features_for_terrain(GFXAdapterType type) { + if(type != Direct3D9 && type != Direct3D9_360) + return; + FEATUREMGR->registerFeature( MFT_TerrainBaseMap, new TerrainBaseMapFeatHLSL ); FEATUREMGR->registerFeature( MFT_TerrainParallaxMap, new NamedFeatureHLSL( "Terrain Parallax Texture" ) ); FEATUREMGR->registerFeature( MFT_TerrainDetailMap, new TerrainDetailMapFeatHLSL ); @@ -49,6 +50,17 @@ MODULE_BEGIN( TerrainFeatHLSL ) FEATUREMGR->registerFeature( MFT_TerrainAdditive, new TerrainAdditiveFeatHLSL ); } +}; + +MODULE_BEGIN( TerrainFeatHLSL ) + + MODULE_INIT_AFTER( ShaderGen ) + + MODULE_INIT + { + SHADERGEN->getFeatureInitSignal().notify(®ister_hlsl_shader_features_for_terrain); + } + MODULE_END; diff --git a/Engine/source/windowManager/win32/win32Window.h b/Engine/source/windowManager/win32/win32Window.h index c205098ba..765a3c900 100644 --- a/Engine/source/windowManager/win32/win32Window.h +++ b/Engine/source/windowManager/win32/win32Window.h @@ -30,12 +30,14 @@ #include "sim/actionMap.h" class Win32WindowManager; +class GFXGLDevice; /// Implementation of a window on Win32. class Win32Window : public PlatformWindow { friend class Win32WindowManager; friend class GFXPCD3D9Device; + friend class GFXGLDevice; friend class GFXPCD3D9WindowTarget; friend class GFXD3D8WindowTarget; diff --git a/Templates/Empty/game/core/main.cs b/Templates/Empty/game/core/main.cs index 3adaf5a56..0baeb9364 100644 --- a/Templates/Empty/game/core/main.cs +++ b/Templates/Empty/game/core/main.cs @@ -68,8 +68,8 @@ function onStart() if ($platform $= "macos") $pref::Video::displayDevice = "OpenGL"; - else - $pref::Video::displayDevice = "D3D9"; + //else + //$pref::Video::displayDevice = "D3D9"; // Initialise stuff. exec("./scripts/client/core.cs"); diff --git a/Templates/Full/game/core/main.cs b/Templates/Full/game/core/main.cs index 3adaf5a56..0baeb9364 100644 --- a/Templates/Full/game/core/main.cs +++ b/Templates/Full/game/core/main.cs @@ -68,8 +68,8 @@ function onStart() if ($platform $= "macos") $pref::Video::displayDevice = "OpenGL"; - else - $pref::Video::displayDevice = "D3D9"; + //else + //$pref::Video::displayDevice = "D3D9"; // Initialise stuff. exec("./scripts/client/core.cs"); diff --git a/Tools/CMake/torque3d.cmake b/Tools/CMake/torque3d.cmake index cd6e1a199..dc15bd28e 100644 --- a/Tools/CMake/torque3d.cmake +++ b/Tools/CMake/torque3d.cmake @@ -58,6 +58,12 @@ option(TORQUE_HIFI "HIFI? support" OFF) mark_as_advanced(TORQUE_HIFI) option(TORQUE_EXTENDED_MOVE "Extended move support" OFF) mark_as_advanced(TORQUE_EXTENDED_MOVE) +if(WIN32) + option(TORQUE_OPENGL "Allow OpenGL render" OFF) + #mark_as_advanced(TORQUE_OPENGL) +else() + set(TORQUE_OPENGL ON) # we need OpenGL to render on Linux/Mac +endif() option(TORQUE_NAVIGATION "Enable Navigation module" OFF) #mark_as_advanced(TORQUE_NAVIGATION) option(TORQUE_TESTING "Enable unit test module" OFF) @@ -446,8 +452,12 @@ if( TORQUE_OPENGL ) if( TORQUE_OPENGL AND NOT TORQUE_DEDICATED ) addPath("${srcDir}/gfx/gl") addPath("${srcDir}/gfx/gl/tGL") + addPath("${srcDir}/shaderGen/GLSL") addPath("${srcDir}/terrain/glsl") addPath("${srcDir}/forest/glsl") + + # glew + LIST(APPEND ${PROJECT_NAME}_files "${libDir}/glew/src/glew.c") endif() if(WIN32 AND NOT TORQUE_SDL) @@ -506,6 +516,10 @@ if(WIN32) set(TORQUE_EXTERNAL_LIBS "COMCTL32.LIB;COMDLG32.LIB;USER32.LIB;ADVAPI32.LIB;GDI32.LIB;WINMM.LIB;WSOCK32.LIB;vfw32.lib;Imm32.lib;d3d9.lib;d3dx9.lib;DxErr.lib;ole32.lib;shell32.lib;oleaut32.lib;version.lib" CACHE STRING "external libs to link against") mark_as_advanced(TORQUE_EXTERNAL_LIBS) addLib("${TORQUE_EXTERNAL_LIBS}") + + if(TORQUE_OPENGL) + addLib(OpenGL32.lib) + endif() endif() if(UNIX) @@ -544,6 +558,12 @@ if(UNIX) addDef(LINUX) endif() +if(TORQUE_OPENGL) + addDef(TORQUE_OPENGL) + if(WIN32) + addDef(GLEW_STATIC) + endif() +endif() ############################################################################### # Include Paths ############################################################################### @@ -562,6 +582,9 @@ addInclude("${libDir}/libogg/include") addInclude("${libDir}/opcode") addInclude("${libDir}/collada/include") addInclude("${libDir}/collada/include/1.4") +if(TORQUE_OPENGL) + addInclude("${libDir}/glew/include") +endif() # external things if(WIN32)