Explorar o código

Added support for GL binary shader caching. Added support for gDEBugger.

bkaradzic %!s(int64=13) %!d(string=hai) anos
pai
achega
a48b3a9ee3
Modificáronse 9 ficheiros con 274 adicións e 96 borrados
  1. 67 0
      3rdparty/glext/gl/GRemedyGLExtensions.h
  2. 2 1
      include/bgfx.h
  3. 34 23
      src/bgfx.cpp
  4. 7 0
      src/bgfx_p.h
  5. 4 0
      src/config.h
  6. 5 0
      src/glimports.h
  7. 4 4
      src/renderer_d3d9.cpp
  8. 97 45
      src/renderer_gl.cpp
  9. 54 23
      src/renderer_gl.h

+ 67 - 0
3rdparty/glext/gl/GRemedyGLExtensions.h

@@ -0,0 +1,67 @@
+// ------------------------------ GRemdeyGLExtensions.h ------------------------------
+
+// -----------------------------------------------------------------
+//   © 2004 - 2012 Advanced Micro Devices, Inc. All rights reserved.
+// -----------------------------------------------------------------
+
+#ifndef __GREMDEYGLEXTENSIONS
+#define __GREMDEYGLEXTENSIONS
+
+
+#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
+#define WIN32_LEAN_AND_MEAN 1
+#include <windows.h>
+#endif
+
+#ifndef APIENTRY
+#define APIENTRY
+#endif
+
+#ifndef APIENTRYP
+#define APIENTRYP APIENTRY *
+#endif
+
+#ifndef GLAPI
+#define GLAPI extern
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+        /* ----------------------- GL_GREMEDY_string_marker ----------------------- */
+        
+#ifndef GL_GREMEDY_string_marker
+#define GL_GREMEDY_string_marker 1
+        
+#ifdef GL_GLEXT_PROTOTYPES
+        GLAPI void APIENTRY glStringMarkerGREMEDY(GLsizei len, const GLvoid *string);
+#endif /* GL_GLEXT_PROTOTYPES */
+        
+        typedef void (APIENTRYP PFNGLSTRINGMARKERGREMEDYPROC)(GLsizei len, const GLvoid *string);
+        
+#endif /* GL_GREMEDY_string_marker */
+        
+        
+        
+        /* ----------------------- GL_GREMEDY_frame_terminator ----------------------- */
+        
+#ifndef GL_GREMEDY_frame_terminator
+#define GL_GREMEDY_frame_terminator 1
+        
+#ifdef GL_GLEXT_PROTOTYPES
+        GLAPI void APIENTRY glFrameTerminatorGREMEDY(void);
+#endif /* GL_GLEXT_PROTOTYPES */
+        
+        typedef void (APIENTRYP PFNGLFRAMETERMINATORGREMEDYPROC)(void);
+        
+#endif /* GL_GREMEDY_frame_terminator */
+        
+        
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif  /* __GREMDEYGLEXTENSIONS */

+ 2 - 1
include/bgfx.h

@@ -254,6 +254,7 @@ namespace bgfx
 	typedef void (*fatalFn)(Fatal::Enum _code, const char* _str);
 	typedef void* (*reallocFn)(void* _ptr, size_t _size);
 	typedef void (*freeFn)(void* _ptr);
+	typedef void (*cacheFn)(uint64_t _id, bool _store, void* _data, uint32_t& _length);
 
 	struct VertexDecl
 	{
@@ -272,7 +273,7 @@ namespace bgfx
 	RendererType::Enum getRendererType();
 
 	///
-	void init(bool _createRenderThread = true, fatalFn _fatal = NULL, reallocFn _realloc = NULL, freeFn _free = NULL);
+	void init(bool _createRenderThread = true, fatalFn _fatal = NULL, reallocFn _realloc = NULL, freeFn _free = NULL, cacheFn _cache = NULL);
 
 	///
 	void shutdown();

+ 34 - 23
src/bgfx.cpp

@@ -5,25 +5,6 @@
 
 #include "bgfx_p.h"
 
-BX_NO_INLINE void bgfxFatalStub(bgfx::Fatal::Enum _code, const char* _str)
-{
-	BX_TRACE("0x%08x: %s", _code, _str);
-}
-
-BX_NO_INLINE void* bgfxReallocStub(void* _ptr, size_t _size)
-{
-	void* ptr = ::realloc(_ptr, _size);
-	BX_CHECK(NULL != ptr, "Out of memory!");
-//	BX_TRACE("alloc %d, %p", _size, ptr);
-	return ptr;
-}
-
-BX_NO_INLINE void bgfxFreeStub(void* _ptr)
-{
-//	BX_TRACE("free %p", _ptr);
-	::free(_ptr);
-}
-
 #if BX_PLATFORM_WINDOWS
 HWND g_bgfxHwnd = NULL;
 #endif // BX_PLATFORM_WINDOWS
@@ -40,9 +21,34 @@ namespace bgfx
 #	define BGFX_RENDER_THREAD()
 #endif // BGFX_CONFIG_MULTITHREADED
 
-	fatalFn g_fatal = bgfxFatalStub;
-	reallocFn g_realloc = bgfxReallocStub;
-	freeFn g_free = bgfxFreeStub;
+	void fatalStub(bgfx::Fatal::Enum _code, const char* _str)
+	{
+		BX_TRACE("0x%08x: %s", _code, _str);
+	}
+
+	void* reallocStub(void* _ptr, size_t _size)
+	{
+		void* ptr = ::realloc(_ptr, _size);
+		BX_CHECK(NULL != ptr, "Out of memory!");
+		//	BX_TRACE("alloc %d, %p", _size, ptr);
+		return ptr;
+	}
+
+	void freeStub(void* _ptr)
+	{
+		//	BX_TRACE("free %p", _ptr);
+		::free(_ptr);
+	}
+
+	void cacheStub(uint64_t _id, bool _store, void* _data, uint32_t& _length)
+	{
+		_length = 0;
+	}
+
+	fatalFn g_fatal = fatalStub;
+	reallocFn g_realloc = reallocStub;
+	freeFn g_free = freeStub;
+	cacheFn g_cache = cacheStub;
 
 	static BX_THREAD uint32_t s_threadIndex = 0;
 	static Context s_ctx;
@@ -481,7 +487,7 @@ namespace bgfx
 #endif // BGFX_CONFIG_RENDERER_
 	}
 
-	void init(bool _createRenderThread, fatalFn _fatal, reallocFn _realloc, freeFn _free)
+	void init(bool _createRenderThread, fatalFn _fatal, reallocFn _realloc, freeFn _free, cacheFn _cache)
 	{
 		if (NULL != _fatal)
 		{
@@ -495,6 +501,11 @@ namespace bgfx
 			g_free = _free;
 		}
 
+		if (NULL != _cache)
+		{
+			g_cache = _cache;
+		}
+
 		s_threadIndex = BGFX_MAIN_THREAD_MAGIC;
 		s_ctx.init(_createRenderThread);
 	}

+ 7 - 0
src/bgfx_p.h

@@ -112,6 +112,8 @@ namespace bgfx
 	extern fatalFn g_fatal;
 	extern reallocFn g_realloc;
 	extern freeFn g_free;
+	extern cacheFn g_cache;
+
 	extern void fatal(bgfx::Fatal::Enum _code, const char* _format, ...);
 	extern void release(Memory* _mem);
 	extern void saveTga(const char* _filePath, uint32_t _width, uint32_t _height, uint32_t _pitch, const void* _data);
@@ -348,6 +350,11 @@ namespace bgfx
 			m_pos = strideAlign(m_pos, _align);
 		}
 
+		uint32_t remaining() const
+		{
+			return m_size-m_pos;
+		}
+
 	private:
 		const uint8_t* m_data;
 		uint32_t m_size;

+ 4 - 0
src/config.h

@@ -32,6 +32,10 @@
 #	define BGFX_CONFIG_DEBUG_PIX 0
 #endif // BGFX_CONFIG_DEBUG_PIX
 
+#ifndef BGFX_CONFIG_DEBUG_GREMEDY
+#	define BGFX_CONFIG_DEBUG_GREMEDY 0
+#endif // BGFX_CONFIG_DEBUG_GREMEDY
+
 #ifndef BGFX_CONFIG_MULTITHREADED
 #	define BGFX_CONFIG_MULTITHREADED ( (BX_PLATFORM_WINDOWS|BX_PLATFORM_XBOX360|BX_PLATFORM_NACL)&(!BGFX_CONFIG_RENDERER_NULL) )
 #endif // BGFX_CONFIG_MULTITHREADED

+ 5 - 0
src/glimports.h

@@ -61,3 +61,8 @@ GL_IMPORT(false, PFNGLUNIFORMMATRIX4FVPROC,         glUniformMatrix4fv);
 GL_IMPORT(true,  PFNGLGETPROGRAMBINARYPROC,         glGetProgramBinary);
 GL_IMPORT(true,  PFNGLPROGRAMBINARYPROC,            glProgramBinary);
 GL_IMPORT(true,  PFNGLPROGRAMPARAMETERIPROC,        glProgramParameteri);
+
+#if BGFX_CONFIG_DEBUG_GREMEDY
+GL_IMPORT(true,  PFNGLSTRINGMARKERGREMEDYPROC,      glStringMarkerGREMEDY);
+GL_IMPORT(true,  PFNGLFRAMETERMINATORGREMEDYPROC,   glFrameTerminatorGREMEDY);
+#endif // BGFX_CONFIG_DEBUG_GREMEDY

+ 4 - 4
src/renderer_d3d9.cpp

@@ -135,7 +135,7 @@ namespace bgfx
 			m_params.BackBufferHeight = rect.bottom-rect.top;
 
 			m_d3d9dll = LoadLibrary("d3d9.dll");
-			BX_CHECK(m_d3d9dll, "Module d3d9.dll not found.");
+			BGFX_FATAL(NULL != m_d3d9dll, bgfx::Fatal::D3D9_UnableToCreateInterface, "Failed to load d3d9.dll.");
 
 			m_D3DPERF_SetMarker = (D3DPERF_SetMarkerFunc)GetProcAddress(m_d3d9dll, "D3DPERF_SetMarker");
 			m_D3DPERF_BeginEvent = (D3DPERF_BeginEventFunc)GetProcAddress(m_d3d9dll, "D3DPERF_BeginEvent");
@@ -143,11 +143,11 @@ namespace bgfx
 
 #if BGFX_CONFIG_RENDERER_DIRECT3D_EX
 			Direct3DCreate9ExFunc direct3DCreate9Ex = (Direct3DCreate9ExFunc)GetProcAddress(m_d3d9dll, "Direct3DCreate9Ex");
-			BX_CHECK(direct3DCreate9Ex, "Function Direct3DCreate9Ex not found.");
-			DX_CHECK(direct3DCreate9Ex(D3D_SDK_VERSION, &m_d3d9) );
+			BGFX_FATAL(NULL != direct3DCreate9Ex, bgfx::Fatal::D3D9_UnableToCreateInterface, "Function Direct3DCreate9Ex not found.");
+			direct3DCreate9Ex(D3D_SDK_VERSION, &m_d3d9);
 #else
 			Direct3DCreate9Func direct3DCreate9 = (Direct3DCreate9Func)GetProcAddress(m_d3d9dll, "Direct3DCreate9");
-			BX_CHECK(direct3DCreate9, "Function Direct3DCreate9 not found.");
+			BGFX_FATAL(NULL != direct3DCreate9, bgfx::Fatal::D3D9_UnableToCreateInterface, "Function Direct3DCreate9 not found.");
 			m_d3d9 = direct3DCreate9(D3D_SDK_VERSION);
 #endif // defined(D3D_DISABLE_9EX)
 

+ 97 - 45
src/renderer_gl.cpp

@@ -41,6 +41,7 @@ namespace bgfx
 			: m_dxtSupport(false)
 			, m_flip(false)
 			, m_postSwapBuffers(NULL)
+			, m_hash( (BX_PLATFORM_WINDOWS<<1) | BX_ARCH_64BIT)
 #if BX_PLATFORM_NACL
 			, m_context(0)
 			, m_instance(0)
@@ -109,37 +110,39 @@ namespace bgfx
 #elif BX_PLATFORM_WINDOWS
 				if (NULL == m_hdc)
 				{
-					PIXELFORMATDESCRIPTOR pfd =
-					{
-						sizeof(PIXELFORMATDESCRIPTOR),
-						1,
-						PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER,
-						PFD_TYPE_RGBA,
-						32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-						24, 0, 0,
-						PFD_MAIN_PLANE,
-						0, 0, 0, 0
-					};
-
 					m_hdc = GetDC(g_bgfxHwnd);
+					BGFX_FATAL(NULL != m_hdc, bgfx::Fatal::OPENGL_UnableToCreateContext, "GetDC failed!");
+
+					PIXELFORMATDESCRIPTOR pfd;
+					memset(&pfd, 0, sizeof(pfd) );
+					pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
+					pfd.nVersion = 1;
+					pfd.iPixelType = PFD_TYPE_RGBA;
+					pfd.cColorBits = 32;
+					pfd.cAlphaBits = 8;
+					pfd.cDepthBits = 24;
+					pfd.cStencilBits = 8;
+					pfd.iLayerType = PFD_MAIN_PLANE;
 
 					int pixelFormat = ChoosePixelFormat(m_hdc, &pfd);
-					BX_CHECK(0 != pixelFormat, "ChoosePixelFormat failed!");
+					BGFX_FATAL(0 != pixelFormat, bgfx::Fatal::OPENGL_UnableToCreateContext, "ChoosePixelFormat failed!");
+
+					DescribePixelFormat(m_hdc, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
 
 					int result;
 					result = SetPixelFormat(m_hdc, pixelFormat, &pfd);
-					BX_CHECK(0 != result, "SetPixelFormat failed!");
+					BGFX_FATAL(0 != result, bgfx::Fatal::OPENGL_UnableToCreateContext, "SetPixelFormat failed!");
 
 					m_context = wglCreateContext(m_hdc);
-					BX_CHECK(NULL != m_context, "wglCreateContext failed!");
+					BGFX_FATAL(NULL != m_context, bgfx::Fatal::OPENGL_UnableToCreateContext, "wglCreateContext failed!");
 					
 					result = wglMakeCurrent(m_hdc, m_context);
-					BX_CHECK(0 != result, "wglMakeCurrent failed!");
+					BGFX_FATAL(0 != result, bgfx::Fatal::OPENGL_UnableToCreateContext, "wglMakeCurrent failed!");
 
 #	define GL_IMPORT(_optional, _proto, _func) \
 				{ \
 					_func = (_proto)wglGetProcAddress(#_func); \
-					BGFX_FATAL(!_optional && NULL != _func, bgfx::Fatal::OPENGL_UnableToCreateContext, "Failed to create OpenGL context. wglGetProcAddress %s", #_func); \
+					BGFX_FATAL(_optional || NULL != _func, bgfx::Fatal::OPENGL_UnableToCreateContext, "Failed to create OpenGL context. wglGetProcAddress(\"%s\")", #_func); \
 				}
 #	include "glimports.h"
 #	undef GL_IMPORT
@@ -257,7 +260,7 @@ namespace bgfx
 #	define GL_IMPORT(_optional, _proto, _func) \
 				{ \
 					_func = (_proto)glXGetProcAddress((const GLubyte*)#_func); \
-					BGFX_FATAL(!_optional && NULL != _func, bgfx::Fatal::OPENGL_UnableToCreateContext, "Failed to create OpenGL context. glXGetProcAddress %s", #_func); \
+					BGFX_FATAL(_optional || NULL != _func, bgfx::Fatal::OPENGL_UnableToCreateContext, "Failed to create OpenGL context. glXGetProcAddress %s", #_func); \
 				}
 #	include "glimports.h"
 #	undef GL_IMPORT
@@ -333,6 +336,7 @@ namespace bgfx
 		bool m_flip;
 
 		PostSwapBuffersFn m_postSwapBuffers;
+		uint64_t m_hash;
 
 #if BX_PLATFORM_NACL
 		PP_Resource m_context;
@@ -385,11 +389,13 @@ namespace bgfx
 		enum Enum
 		{
 			EXT_texture_format_BGRA8888,
+			EXT_texture_compression_s3tc,
 			EXT_texture_compression_dxt1,
 			CHROMIUM_texture_compression_dxt3,
 			CHROMIUM_texture_compression_dxt5,
 			OES_standard_derivatives,
 			ARB_get_program_binary,
+			OES_get_program_binary,
 
 			Count
 		};
@@ -404,11 +410,13 @@ namespace bgfx
 		// Nvidia BGRA on Linux bug:
 		// https://groups.google.com/a/chromium.org/forum/?fromgroups#!topic/chromium-reviews/yFfbUdyeUCQ
 		{ "GL_EXT_texture_format_BGRA8888",       false, !BX_PLATFORM_LINUX },
+		{ "GL_EXT_texture_compression_s3tc",      false, true },
 		{ "GL_EXT_texture_compression_dxt1",      false, true },
 		{ "GL_CHROMIUM_texture_compression_dxt3", false, true },
 		{ "GL_CHROMIUM_texture_compression_dxt5", false, true },
 		{ "GL_OES_standard_derivatives",          false, true },
-		{ "GL_ARB_get_program_binary",            false, false },
+		{ "GL_ARB_get_program_binary",            false, true },
+		{ "GL_OES_get_program_binary",            false, false },
 	};
 
 	static const GLenum s_primType[] =
@@ -605,44 +613,76 @@ namespace bgfx
 		m_id = glCreateProgram();
 		BX_TRACE("material create: %d: %d, %d", m_id, _vsh.m_id, _fsh.m_id);
 
+		bool cached = false;
+
 #if BGFX_CONFIG_RENDERER_OPENGL
+		uint64_t id = (uint64_t(_vsh.m_hash)<<32) | _fsh.m_hash;
+		id ^= s_renderCtx.m_hash;
+
 		if (s_extension[Extension::ARB_get_program_binary].m_supported)
 		{
-			GL_CHECK(glProgramParameteri(m_id, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE) );
+			uint32_t length;
+			g_cache(id, false, NULL, length);
+			cached = length > 0;
+
+			if (cached)
+			{
+				void* data = g_realloc(NULL, length);
+				g_cache(id, false, data, length);
+
+				StreamRead stream(data, length);
+
+				GLenum format;
+				stream.read(format);
+
+				GL_CHECK(glProgramBinary(m_id, format, stream.getDataPtr(), stream.remaining() ) );
+
+				g_free(data);
+			}
+			else
+			{
+				GL_CHECK(glProgramParameteri(m_id, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE) );
+			}
 		}
 #endif // BGFX_CONFIG_RENDERER_OPENGL
 
-		GL_CHECK(glAttachShader(m_id, _vsh.m_id) );
-		GL_CHECK(glAttachShader(m_id, _fsh.m_id) );
-		GL_CHECK(glLinkProgram(m_id) );
+		if (!cached)
+		{
+			GL_CHECK(glAttachShader(m_id, _vsh.m_id) );
+			GL_CHECK(glAttachShader(m_id, _fsh.m_id) );
+			GL_CHECK(glLinkProgram(m_id) );
 
-		GLint linked = 0;
-		GL_CHECK(glGetProgramiv(m_id, GL_LINK_STATUS, &linked) );
+			GLint linked = 0;
+			GL_CHECK(glGetProgramiv(m_id, GL_LINK_STATUS, &linked) );
 
-		if (0 == linked)
-		{
-			char log[1024];
-			GL_CHECK(glGetProgramInfoLog(m_id, sizeof(log), NULL, log) );
-			BX_TRACE("%d: %s", linked, log);
+			if (0 == linked)
+			{
+				char log[1024];
+				GL_CHECK(glGetProgramInfoLog(m_id, sizeof(log), NULL, log) );
+				BX_TRACE("%d: %s", linked, log);
 
-			GL_CHECK(glDeleteProgram(m_id) );
-			return;
-		}
+				GL_CHECK(glDeleteProgram(m_id) );
+				return;
+			}
 
 #if BGFX_CONFIG_RENDERER_OPENGL
-		if (s_extension[Extension::ARB_get_program_binary].m_supported)
-		{
-			GLint length;
-			GLenum format;
-			GL_CHECK(glGetProgramiv(m_id, GL_PROGRAM_BINARY_LENGTH, &length) );
-			void* data = g_realloc(NULL, length);
-			GL_CHECK(glGetProgramBinary(m_id, length, NULL, &format, data) );
+			if (s_extension[Extension::ARB_get_program_binary].m_supported)
+			{
+				GLint programLength;
+				GLenum format;
+				GL_CHECK(glGetProgramiv(m_id, GL_PROGRAM_BINARY_LENGTH, &programLength) );
 
-			dbgPrintfData(data, length, "Binary 0x%08x", format);
+				uint32_t length = programLength + 4;
+				uint8_t* data = (uint8_t*)g_realloc(NULL, length);
+				GL_CHECK(glGetProgramBinary(m_id, programLength, NULL, &format, &data[4]) );
+				*(uint32_t*)data = format;
 
-			g_free(data);
-		}
+				g_cache(id, true, data, length);
+
+				g_free(data);
+			}
 #endif // BGFX_CONFIG_RENDERER_OPENGL
+		}
 
 		init();
 	}
@@ -1120,10 +1160,16 @@ namespace bgfx
 		{
 			if (0 < colorFormat)
 			{
+#if BGFX_CONFIG_RENDERER_OPENGL
+				GLenum depthComponent = GL_DEPTH_COMPONENT32;
+#else
+				GLenum depthComponent = GL_DEPTH_COMPONENT16;
+#endif // BGFX_CONFIG_RENDERER_OPENGL
+
 				GL_CHECK(glGenRenderbuffers(1, &m_rbo) );
 				BX_CHECK(0 != m_rbo, "Failed to generate renderbuffer id.");
 				GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, m_rbo) );
-				GL_CHECK(glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, _width, _height) );
+				GL_CHECK(glRenderbufferStorage(GL_RENDERBUFFER, depthComponent, _width, _height) );
 				GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, 0) );
 
 				GL_CHECK(glFramebufferRenderbuffer(GL_FRAMEBUFFER
@@ -1390,6 +1436,10 @@ namespace bgfx
 			&& s_extension[Extension::CHROMIUM_texture_compression_dxt3].m_supported
 			&& s_extension[Extension::CHROMIUM_texture_compression_dxt5].m_supported
 			;
+
+		s_renderCtx.m_dxtSupport |=
+			s_extension[Extension::EXT_texture_compression_s3tc].m_supported
+			;
 	}
 
 	void Context::rendererShutdown()
@@ -1584,6 +1634,8 @@ namespace bgfx
 					changedFlags = BGFX_STATE_MASK;
 					currentState.m_flags = newFlags;
 
+					GREMEDY_SETMARKER("view");
+
 					view = key.m_view;
 					materialIdx = bgfx::invalidHandle;
 
@@ -2083,7 +2135,7 @@ namespace bgfx
 			g_textVideoMemBlitter.blit(m_render->m_textVideoMem);
 		}
 
-		GL_CHECK(glFlush() );
+		GREMEDY_FRAMETERMINATOR();
 	}
 
 #if BX_PLATFORM_WINDOWS

+ 54 - 23
src/renderer_gl.h

@@ -11,6 +11,30 @@
 #	include <gl/glext.h>
 #elif BGFX_CONFIG_RENDERER_OPENGLES
 #	include <GLES2/gl2.h>
+
+#	ifndef GL_BGRA_EXT
+#		define GL_BGRA_EXT 0x80E1
+#	endif // GL_BGRA_EXT
+
+#	ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT
+#		define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
+#	endif // GL_COMPRESSED_RGB_S3TC_DXT1_EXT
+
+#	ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
+#		define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
+#	endif // GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
+
+#	ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
+#		define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
+#	endif // GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
+
+#	ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
+#		define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
+#	endif // GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
+
+#	ifndef GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES
+#		define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES 0x8B8B
+#	endif // GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES
 #endif // BGFX_CONFIG_RENDERER_OPENGL
 
 #if BX_PLATFORM_NACL
@@ -25,29 +49,9 @@
 #	include <X11/Xlib.h>
 #endif // BX_PLATFORM_
 
-#ifndef GL_BGRA_EXT
-#	define GL_BGRA_EXT 0x80E1
-#endif // GL_BGRA_EXT
-
-#ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT
-#	define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
-#endif // GL_COMPRESSED_RGB_S3TC_DXT1_EXT
-
-#ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
-#	define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
-#endif // GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
-
-#ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
-#	define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
-#endif // GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
-
-#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
-#	define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
-#endif // GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
-
-#ifndef GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES
-#	define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES 0x8B8B
-#endif // GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES
+#if BGFX_CONFIG_DEBUG_GREMEDY && (BX_PLATFORM_WINDOWS || BX_PLATFORM_LINUX)
+#	include <gl/GRemedyGLExtensions.h>
+#endif // BGFX_CONFIG_DEBUG_GREMEDY && (BX_PLATFORM_WINDOWS || BX_PLATFORM_LINUX)
 
 namespace bgfx
 {
@@ -65,6 +69,31 @@ namespace bgfx
 #	define GL_CHECK(_call) _call
 #endif // BGFX_CONFIG_DEBUG
 
+#if BGFX_CONFIG_DEBUG_GREMEDY
+#	define _GREMEDY_SETMARKER(_string) \
+					do \
+					{ \
+						if (NULL != glStringMarkerGREMEDY) \
+						{ \
+							glStringMarkerGREMEDY( (GLsizei)strlen(_string), _string); \
+						} \
+					} while(0)
+#	define _GREMEDY_FRAMETERMINATOR() \
+					do \
+					{ \
+						if (NULL != glStringMarkerGREMEDY) \
+						{ \
+							glFrameTerminatorGREMEDY(); \
+						} \
+					} while(0)
+#else
+#	define _GREMEDY_SETMARKER(_string) do {} while(0)
+#	define _GREMEDY_FRAMETERMINATOR() do {} while(0)
+#endif // BGFX_CONFIG_DEBUG_GREMEDY
+
+#define GREMEDY_SETMARKER(_string) _GREMEDY_SETMARKER(_string)
+#define GREMEDY_FRAMETERMINATOR() _GREMEDY_FRAMETERMINATOR()
+
 #if BGFX_CONFIG_RENDERER_OPENGL
 #	define GL_IMPORT(_optional, _proto, _func) extern _proto _func
 #	include "glimports.h"
@@ -177,6 +206,7 @@ namespace bgfx
 
 			if (0 != m_id)
 			{
+				m_hash = hash(_code, (uint32_t)strlen( (const char*)_code) );
 				GL_CHECK(glShaderSource(m_id, 1, (const GLchar**)&_code, NULL) );
 				GL_CHECK(glCompileShader(m_id) );
 
@@ -202,6 +232,7 @@ namespace bgfx
 
 		GLuint m_id;
 		GLenum m_type;
+		uint32_t m_hash;
 	};
 
 	struct RenderTarget