Răsfoiți Sursa

Added ability to change sampler filter when setting texture. GL/GLES3: Added support for GL_ARB_sampler_objects.

bkaradzic 12 ani în urmă
părinte
comite
a1dfd1ab0d
11 a modificat fișierele cu 557 adăugiri și 366 ștergeri
  1. 0 1
      README.md
  2. 32 8
      include/bgfx.h
  3. 4 4
      src/bgfx.cpp
  4. 16 9
      src/bgfx_p.h
  5. 6 0
      src/glimports.h
  6. 46 34
      src/renderer_d3d11.cpp
  7. 4 17
      src/renderer_d3d11.h
  8. 48 43
      src/renderer_d3d9.cpp
  9. 4 13
      src/renderer_d3d9.h
  10. 335 235
      src/renderer_gl.cpp
  11. 62 2
      src/renderer_gl.h

+ 0 - 1
README.md

@@ -267,7 +267,6 @@ Todo
  - DX11: MSAA.
  - Fullscreen mode.
  - GL/DX11: Add support for ARB_depth_clamp, DepthBiasClamp.
- - GL/GLES3: Add support for GL_ARB_sampler_objects.
  - Primitive scissor.
 
 Contact

+ 32 - 8
include/bgfx.h

@@ -67,7 +67,6 @@
 #define BGFX_STATE_POINT_SIZE_SHIFT      44
 #define BGFX_STATE_POINT_SIZE_MASK       UINT64_C(0x000ff00000000000)
 
-#define BGFX_STATE_SRGBWRITE             UINT64_C(0x0010000000000000)
 #define BGFX_STATE_MSAA                  UINT64_C(0x0020000000000000)
 
 #define BGFX_STATE_RESERVED_MASK         UINT64_C(0xff00000000000000)
@@ -191,7 +190,7 @@
 #define BGFX_TEXTURE_MIP_POINT           UINT32_C(0x00100000)
 #define BGFX_TEXTURE_MIP_SHIFT           20
 #define BGFX_TEXTURE_MIP_MASK            UINT32_C(0x00100000)
-#define BGFX_TEXTURE_SRGB                UINT32_C(0x00200000)
+#define BGFX_TEXTURE_RESERVED_MASK       UINT32_C(0xf0000000)
 
 ///
 #define BGFX_RENDER_TARGET_NONE          UINT32_C(0x00000000)
@@ -212,7 +211,6 @@
 #define BGFX_RENDER_TARGET_MSAA_X16      UINT32_C(0x00040000)
 #define BGFX_RENDER_TARGET_MSAA_SHIFT    16
 #define BGFX_RENDER_TARGET_MSAA_MASK     UINT32_C(0x00070000)
-#define BGFX_RENDER_TARGET_SRGBWRITE     UINT32_C(0x00080000)
 
 ///
 #define BGFX_RESET_NONE                  UINT32_C(0x00000000)
@@ -701,8 +699,6 @@ namespace bgfx
 	///   BGFX_TEXTURE_[MIN/MAG/MIP]_[POINT/ANISOTROPIC] - Point or anisotropic
 	///     sampling.
 	///
-	///   BGFX_TEXTURE_SRGB - Sample as sRGB texture.
-	///
 	/// @param _info Returns parsed DDS texture information.
 	/// @returns Texture handle.
 	///
@@ -830,7 +826,6 @@ namespace bgfx
 	///   BGFX_STATE_BLEND_EQUATION_* - See NOTE 2.
 	///   BGFX_STATE_CULL_* - Backface culling mode.
 	///   BGFX_STATE_RGB_WRITE - Enable RGB write.
-	///   BGFX_STATE_SRGBWRITE - Enable sRGB write.
 	///   BGFX_STATE_MSAA - Enable MSAA.
 	///   BGFX_STATE_PT_[LINES/POINTS] - Primitive type.
 	///
@@ -907,10 +902,39 @@ namespace bgfx
 	void setProgram(ProgramHandle _handle);
 
 	/// Set texture stage for draw primitive.
-	void setTexture(uint8_t _stage, UniformHandle _sampler, TextureHandle _handle);
+	///
+	/// @param _stage Texture unit.
+	/// @param _sampler Program sampler.
+	/// @param _handle Texture handle.
+	/// @param _flags Texture sampling mode. Default value UINT32_MAX uses
+	///   texture sampling settings from the texture.
+	///
+	///   BGFX_TEXTURE_[U/V/W]_[MIRROR/CLAMP] - Mirror or clamp to edge wrap
+	///     mode.
+	///
+	///   BGFX_TEXTURE_[MIN/MAG/MIP]_[POINT/ANISOTROPIC] - Point or anisotropic
+	///     sampling.
+	///
+	/// @param _flags Texture sampler filtering flags. UINT32_MAX use the
+	///   sampler filtering mode set by texture.
+	///
+	void setTexture(uint8_t _stage, UniformHandle _sampler, TextureHandle _handle, uint32_t _flags = UINT32_MAX);
 
 	/// Set texture stage for draw primitive.
-	void setTexture(uint8_t _stage, UniformHandle _sampler, RenderTargetHandle _handle, bool _depth = false);
+	///
+	/// @param _stage Texture unit.
+	/// @param _sampler Program sampler.
+	/// @param _handle Render target handle.
+	/// @param _flags Texture sampling mode. Default value UINT32_MAX uses
+	///   texture sampling settings from the texture.
+	///
+	///   BGFX_TEXTURE_[U/V/W]_[MIRROR/CLAMP] - Mirror or clamp to edge wrap
+	///     mode.
+	///
+	///   BGFX_TEXTURE_[MIN/MAG/MIP]_[POINT/ANISOTROPIC] - Point or anisotropic
+	///     sampling.
+	///
+	void setTexture(uint8_t _stage, UniformHandle _sampler, RenderTargetHandle _handle, bool _depth = false, uint32_t _flags = UINT32_MAX);
 
 	/// Submit primitive for rendering into single view.
 	///

+ 4 - 4
src/bgfx.cpp

@@ -1472,16 +1472,16 @@ namespace bgfx
 		s_ctx.m_submit->setProgram(_handle);
 	}
 
-	void setTexture(uint8_t _stage, UniformHandle _sampler, TextureHandle _handle)
+	void setTexture(uint8_t _stage, UniformHandle _sampler, TextureHandle _handle, uint32_t _flags)
 	{
 		BGFX_CHECK_MAIN_THREAD();
-		s_ctx.m_submit->setTexture(_stage, _sampler, _handle);
+		s_ctx.m_submit->setTexture(_stage, _sampler, _handle, _flags);
 	}
 
-	void setTexture(uint8_t _stage, UniformHandle _sampler, RenderTargetHandle _handle, bool _depth)
+	void setTexture(uint8_t _stage, UniformHandle _sampler, RenderTargetHandle _handle, bool _depth, uint32_t _flags)
 	{
 		BGFX_CHECK_MAIN_THREAD();
-		s_ctx.m_submit->setTexture(_stage, _sampler, _handle, _depth);
+		s_ctx.m_submit->setTexture(_stage, _sampler, _handle, _depth, _flags);
 	}
 
 	void submit(uint8_t _id, int32_t _depth)

+ 16 - 9
src/bgfx_p.h

@@ -131,10 +131,11 @@ namespace stl {
 #define BGFX_STATE_TEX_MASK  UINT64_C(0xff00000000000000)
 #define BGFX_STATE_TEX_COUNT 8
 
-#define BGFX_SAMPLER_TEXTURE            UINT16_C(0x0000)
-#define BGFX_SAMPLER_RENDERTARGET_COLOR UINT16_C(0x0001)
-#define BGFX_SAMPLER_RENDERTARGET_DEPTH UINT16_C(0x0002)
-#define BGFX_SAMPLER_TYPE_MASK          UINT16_C(0x0003)
+#define BGFX_SAMPLER_DEFAULT_FLAGS      UINT32_C(0x10000000)
+#define BGFX_SAMPLER_TEXTURE            UINT32_C(0x00000000)
+#define BGFX_SAMPLER_RENDERTARGET_COLOR UINT32_C(0x40000000)
+#define BGFX_SAMPLER_RENDERTARGET_DEPTH UINT32_C(0x80000000)
+#define BGFX_SAMPLER_TYPE_MASK          UINT32_C(0xc0000000)
 
 #if BGFX_CONFIG_RENDERER_DIRECT3D9
 #	define BGFX_RENDERER_NAME "Direct3D 9"
@@ -651,8 +652,8 @@ namespace bgfx
 
 	struct Sampler
 	{
+		uint32_t m_flags;
 		uint16_t m_idx;
-		uint16_t m_flags;
 	};
 
 	struct Uniform
@@ -1084,12 +1085,15 @@ namespace bgfx
 			m_key.m_program = _handle.idx;
 		}
 
-		void setTexture(uint8_t _stage, UniformHandle _sampler, TextureHandle _handle)
+		void setTexture(uint8_t _stage, UniformHandle _sampler, TextureHandle _handle, uint32_t _flags)
 		{
 			m_flags |= BGFX_STATE_TEX0<<_stage;
 			Sampler& sampler = m_state.m_sampler[_stage];
 			sampler.m_idx = _handle.idx;
-			sampler.m_flags = BGFX_SAMPLER_TEXTURE;
+			sampler.m_flags = 0
+						| BGFX_SAMPLER_TEXTURE
+						| ( (_flags&BGFX_SAMPLER_TYPE_MASK) ? BGFX_SAMPLER_DEFAULT_FLAGS : _flags)
+						;
 
 			if (invalidHandle != _sampler.idx)
 			{
@@ -1098,12 +1102,15 @@ namespace bgfx
 			}
 		}
 
-		void setTexture(uint8_t _stage, UniformHandle _sampler, RenderTargetHandle _handle, bool _depth)
+		void setTexture(uint8_t _stage, UniformHandle _sampler, RenderTargetHandle _handle, bool _depth, uint32_t _flags)
 		{
 			m_flags |= BGFX_STATE_TEX0<<_stage;
 			Sampler& sampler = m_state.m_sampler[_stage];
 			sampler.m_idx = _handle.idx;
-			sampler.m_flags = _depth ? BGFX_SAMPLER_RENDERTARGET_DEPTH : BGFX_SAMPLER_RENDERTARGET_COLOR;
+			sampler.m_flags = 0
+						| (_depth ? BGFX_SAMPLER_RENDERTARGET_DEPTH : BGFX_SAMPLER_RENDERTARGET_COLOR)
+						| ( (_flags&BGFX_SAMPLER_TYPE_MASK) ? BGFX_SAMPLER_DEFAULT_FLAGS : _flags)
+						;
 
 			if (invalidHandle != _sampler.idx)
 			{

+ 6 - 0
src/glimports.h

@@ -143,6 +143,12 @@ GL_IMPORT(true,  PFNGLDEBUGMESSAGEINSERTARBPROC,          glDebugMessageInsertAR
 GL_IMPORT(true,  PFNGLDEBUGMESSAGECALLBACKARBPROC,        glDebugMessageCallbackARB);
 GL_IMPORT(true,  PFNGLGETDEBUGMESSAGELOGARBPROC,          glGetDebugMessageLogARB);
 
+GL_IMPORT(true,  PFNGLGENSAMPLERSPROC,                    glGenSamplers);
+GL_IMPORT(true,  PFNGLDELETESAMPLERSPROC,                 glDeleteSamplers);
+GL_IMPORT(true,  PFNGLBINDSAMPLERPROC,                    glBindSampler);
+GL_IMPORT(true,  PFNGLSAMPLERPARAMETERIPROC,              glSamplerParameteri);
+GL_IMPORT(true,  PFNGLSAMPLERPARAMETERFPROC,              glSamplerParameterf);
+
 #if BGFX_CONFIG_DEBUG_GREMEDY
 GL_IMPORT(true,  PFNGLSTRINGMARKERGREMEDYPROC,            glStringMarkerGREMEDY);
 GL_IMPORT(true,  PFNGLFRAMETERMINATORGREMEDYPROC,         glFrameTerminatorGREMEDY);

+ 46 - 34
src/renderer_d3d11.cpp

@@ -12,8 +12,6 @@ namespace bgfx
 {
 	static wchar_t s_viewNameW[BGFX_CONFIG_MAX_VIEWS][256];
 
-	typedef HRESULT (WINAPI * PFN_CREATEDXGIFACTORY)(REFIID _riid, void** _factory);
-
 	static const D3D11_PRIMITIVE_TOPOLOGY s_primType[] =
 	{
 		D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
@@ -939,33 +937,32 @@ namespace bgfx
 					| BGFX_TEXTURE_U_MASK|BGFX_TEXTURE_V_MASK|BGFX_TEXTURE_W_MASK
 					;
 
-			uint8_t minFilter = s_textureFilter[0][(_flags&BGFX_TEXTURE_MIN_MASK)>>BGFX_TEXTURE_MIN_SHIFT];
-			uint8_t magFilter = s_textureFilter[1][(_flags&BGFX_TEXTURE_MAG_MASK)>>BGFX_TEXTURE_MAG_SHIFT];
-			uint8_t mipFilter = s_textureFilter[2][(_flags&BGFX_TEXTURE_MIP_MASK)>>BGFX_TEXTURE_MIP_SHIFT];
-
-			D3D11_SAMPLER_DESC sd;
-			sd.Filter = (D3D11_FILTER)(minFilter|magFilter|mipFilter);
-			sd.AddressU = s_textureAddress[(_flags&BGFX_TEXTURE_U_MASK)>>BGFX_TEXTURE_U_SHIFT];
-			sd.AddressV = s_textureAddress[(_flags&BGFX_TEXTURE_V_MASK)>>BGFX_TEXTURE_V_SHIFT];
-			sd.AddressW = s_textureAddress[(_flags&BGFX_TEXTURE_W_MASK)>>BGFX_TEXTURE_W_SHIFT];
-			sd.MipLODBias = 0.0f;
-			sd.MaxAnisotropy = 1;
-			sd.ComparisonFunc = D3D11_COMPARISON_NEVER;
-			sd.BorderColor[0] = 0.0f;
-			sd.BorderColor[1] = 0.0f;
-			sd.BorderColor[2] = 0.0f;
-			sd.BorderColor[3] = 0.0f;
-			sd.MinLOD = 0;
-			sd.MaxLOD = D3D11_FLOAT32_MAX;
-			uint32_t hash = bx::hashMurmur2A(sd);
-
-			ID3D11SamplerState* sampler = m_samplerStateCache.find(hash);
+			ID3D11SamplerState* sampler = m_samplerStateCache.find(_flags);
 			if (NULL == sampler)
 			{
+				uint8_t minFilter = s_textureFilter[0][(_flags&BGFX_TEXTURE_MIN_MASK)>>BGFX_TEXTURE_MIN_SHIFT];
+				uint8_t magFilter = s_textureFilter[1][(_flags&BGFX_TEXTURE_MAG_MASK)>>BGFX_TEXTURE_MAG_SHIFT];
+				uint8_t mipFilter = s_textureFilter[2][(_flags&BGFX_TEXTURE_MIP_MASK)>>BGFX_TEXTURE_MIP_SHIFT];
+
+				D3D11_SAMPLER_DESC sd;
+				sd.Filter = (D3D11_FILTER)(minFilter|magFilter|mipFilter);
+				sd.AddressU = s_textureAddress[(_flags&BGFX_TEXTURE_U_MASK)>>BGFX_TEXTURE_U_SHIFT];
+				sd.AddressV = s_textureAddress[(_flags&BGFX_TEXTURE_V_MASK)>>BGFX_TEXTURE_V_SHIFT];
+				sd.AddressW = s_textureAddress[(_flags&BGFX_TEXTURE_W_MASK)>>BGFX_TEXTURE_W_SHIFT];
+				sd.MipLODBias = 0.0f;
+				sd.MaxAnisotropy = 1;
+				sd.ComparisonFunc = D3D11_COMPARISON_NEVER;
+				sd.BorderColor[0] = 0.0f;
+				sd.BorderColor[1] = 0.0f;
+				sd.BorderColor[2] = 0.0f;
+				sd.BorderColor[3] = 0.0f;
+				sd.MinLOD = 0;
+				sd.MaxLOD = D3D11_FLOAT32_MAX;
+
 				m_device->CreateSamplerState(&sd, &sampler);
 				DX_CHECK_REFCOUNT(sampler, 1);
 
-				m_samplerStateCache.add(hash, sampler);
+				m_samplerStateCache.add(_flags, sampler);
 			}
 
 			return sampler;
@@ -1962,10 +1959,14 @@ namespace bgfx
 		DX_RELEASE(m_ptr, 0);
 	}
 
-	void Texture::commit(uint8_t _stage)
+	void Texture::commit(uint8_t _stage, uint32_t _flags)
 	{
-		s_renderCtx.m_textureStage.m_srv[_stage] = m_srv;
-		s_renderCtx.m_textureStage.m_sampler[_stage] = m_sampler;
+		TextureStage& ts = s_renderCtx.m_textureStage;
+		ts.m_srv[_stage] = m_srv;
+		ts.m_sampler[_stage] = 0 == (BGFX_SAMPLER_DEFAULT_FLAGS & _flags) 
+							 ? s_renderCtx.getSamplerState(_flags)
+							 : m_sampler
+							 ;
 	}
 
 	void Texture::update(uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, const Memory* _mem)
@@ -2060,10 +2061,14 @@ namespace bgfx
 		m_flags = 0;
 	}
 
-	void RenderTarget::commit(uint8_t _stage)
+	void RenderTarget::commit(uint8_t _stage, uint32_t _flags)
 	{
-		s_renderCtx.m_textureStage.m_srv[_stage] = m_srv;
-		s_renderCtx.m_textureStage.m_sampler[_stage] = m_sampler;
+		TextureStage& ts = s_renderCtx.m_textureStage;
+		ts.m_srv[_stage] = m_srv;
+		ts.m_sampler[_stage] = 0 == (BGFX_SAMPLER_DEFAULT_FLAGS & _flags) 
+							 ? s_renderCtx.getSamplerState(_flags)
+							 : m_sampler
+							 ;
 	}
 
 	void UniformBuffer::create(UniformType::Enum _type, uint16_t _num, bool _alloc)
@@ -2418,7 +2423,6 @@ namespace bgfx
 					 | BGFX_STATE_ALPHA_REF_MASK
 					 | BGFX_STATE_PT_MASK
 					 | BGFX_STATE_POINT_SIZE_MASK
-					 | BGFX_STATE_SRGBWRITE
 					 | BGFX_STATE_MSAA
 					 ) & changedFlags)
 				{
@@ -2629,15 +2633,23 @@ namespace bgfx
 								switch (sampler.m_flags&BGFX_SAMPLER_TYPE_MASK)
 								{
 								case BGFX_SAMPLER_TEXTURE:
-									s_renderCtx.m_textures[sampler.m_idx].commit(stage);
+									{
+										Texture& texture = s_renderCtx.m_textures[sampler.m_idx];
+										texture.commit(stage, sampler.m_flags);
+									}
 									break;
 
 								case BGFX_SAMPLER_RENDERTARGET_COLOR:
-									s_renderCtx.m_renderTargets[sampler.m_idx].commit(stage);
+									{
+										RenderTarget& rt = s_renderCtx.m_renderTargets[sampler.m_idx];
+										rt.commit(stage, sampler.m_flags);
+									}
 									break;
 
 								case BGFX_SAMPLER_RENDERTARGET_DEPTH:
-//									id = s_renderCtx.m_renderTargets[sampler.m_idx].m_depth.m_id;
+									{
+//										id = s_renderCtx.m_renderTargets[sampler.m_idx].m_depth.m_id;
+									}
 									break;
 								}
 							}

+ 4 - 17
src/renderer_d3d11.h

@@ -15,6 +15,8 @@
 
 namespace bgfx
 {
+	typedef HRESULT (WINAPI * PFN_CREATEDXGIFACTORY)(REFIID _riid, void** _factory);
+
 	template <typename Ty>
 	class StateCacheT
 	{
@@ -235,7 +237,6 @@ namespace bgfx
 			: m_ptr(NULL)
 			, m_srv(NULL)
 			, m_sampler(NULL)
-			, m_srgb(false)
 			, m_numMips(0)
 		{
 		}
@@ -243,7 +244,7 @@ namespace bgfx
 		void create(const Memory* _mem, uint32_t _flags);
 		void destroy();
 		void update(uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, const Memory* _mem);
-		void commit(uint8_t _stage);
+		void commit(uint8_t _stage, uint32_t _flags = BGFX_SAMPLER_DEFAULT_FLAGS);
 
 		union
 		{
@@ -255,7 +256,6 @@ namespace bgfx
 		ID3D11ShaderResourceView* m_srv;
 		ID3D11SamplerState* m_sampler;
 		Enum m_type;
-		bool m_srgb;
 		uint8_t m_numMips;
 	};
 
@@ -267,8 +267,6 @@ namespace bgfx
 			, m_rtv(NULL)
  			, m_dsv(NULL)
 			, m_srv(NULL)
-// 			, m_minFilter(D3DTEXF_LINEAR)
-// 			, m_magFilter(D3DTEXF_LINEAR)
 			, m_width(0)
 			, m_height(0)
 			, m_flags(0)
@@ -278,18 +276,7 @@ namespace bgfx
 
 		void create(uint16_t _width, uint16_t _height, uint32_t _flags, uint32_t _textureFlags);
 		void destroy();
-
- 		void commit(uint8_t _stage);
-// 		void resolve();
-
-//		Msaa m_msaa;
-// 		IDirect3DSurface9* m_rt;
-// 		IDirect3DTexture9* m_colorTexture;
-// 		IDirect3DSurface9* m_color;
-// 		IDirect3DTexture9* m_depthTexture;
-// 		IDirect3DSurface9* m_depth;
-// 		D3DTEXTUREFILTERTYPE m_minFilter;
-// 		D3DTEXTUREFILTERTYPE m_magFilter;
+ 		void commit(uint8_t _stage, uint32_t _flags = BGFX_SAMPLER_DEFAULT_FLAGS);
 
 		ID3D11Texture2D* m_colorTexture;
 		ID3D11Texture2D* m_depthTexture;

+ 48 - 43
src/renderer_d3d9.cpp

@@ -677,6 +677,8 @@ namespace bgfx
 
 		void preReset()
 		{
+			invalidateSamplerState();
+
 			for (uint32_t stage = 0; stage < BGFX_STATE_TEX_COUNT; ++stage)
 			{
 				DX_CHECK(m_device->SetTexture(stage, NULL) );
@@ -733,6 +735,36 @@ namespace bgfx
 			}
 		}
 
+		void invalidateSamplerState()
+		{
+			for (uint32_t stage = 0; stage < BGFX_STATE_TEX_COUNT; ++stage)
+			{
+				m_samplerFlags[stage] = UINT32_MAX;
+			}
+		}
+
+		void setSamplerState(uint8_t _stage, uint32_t _flags)
+		{
+			const uint32_t flags = _flags&(~BGFX_TEXTURE_RESERVED_MASK);
+			if (m_samplerFlags[_stage] != flags)
+			{
+				m_samplerFlags[_stage] = flags;
+				IDirect3DDevice9* device = m_device;
+				D3DTEXTUREADDRESS tau = s_textureAddress[(_flags&BGFX_TEXTURE_U_MASK)>>BGFX_TEXTURE_U_SHIFT];
+				D3DTEXTUREADDRESS tav = s_textureAddress[(_flags&BGFX_TEXTURE_V_MASK)>>BGFX_TEXTURE_V_SHIFT];
+				D3DTEXTUREADDRESS taw = s_textureAddress[(_flags&BGFX_TEXTURE_W_MASK)>>BGFX_TEXTURE_W_SHIFT];
+				D3DTEXTUREFILTERTYPE minFilter = s_textureFilter[(_flags&BGFX_TEXTURE_MIN_MASK)>>BGFX_TEXTURE_MIN_SHIFT];
+				D3DTEXTUREFILTERTYPE magFilter = s_textureFilter[(_flags&BGFX_TEXTURE_MAG_MASK)>>BGFX_TEXTURE_MAG_SHIFT];
+				D3DTEXTUREFILTERTYPE mipFilter = s_textureFilter[(_flags&BGFX_TEXTURE_MIP_MASK)>>BGFX_TEXTURE_MIP_SHIFT];
+				DX_CHECK(device->SetSamplerState(_stage, D3DSAMP_ADDRESSU, tau) );
+				DX_CHECK(device->SetSamplerState(_stage, D3DSAMP_ADDRESSV, tav) );
+				DX_CHECK(device->SetSamplerState(_stage, D3DSAMP_MINFILTER, minFilter) );
+				DX_CHECK(device->SetSamplerState(_stage, D3DSAMP_MAGFILTER, magFilter) );
+				DX_CHECK(device->SetSamplerState(_stage, D3DSAMP_MIPFILTER, mipFilter) );
+				DX_CHECK(device->SetSamplerState(_stage, D3DSAMP_ADDRESSW, taw) );
+			}
+		}
+
 		void capturePreReset()
 		{
 			if (NULL != m_captureSurface)
@@ -917,6 +949,8 @@ namespace bgfx
 		UniformRegistry m_uniformReg;
 		void* m_uniforms[BGFX_CONFIG_MAX_UNIFORMS];
 
+		uint32_t m_samplerFlags[BGFX_STATE_TEX_COUNT];
+
 		Texture* m_updateTexture;
 		uint8_t* m_updateTextureBits;
 		uint32_t m_updateTexturePitch;
@@ -1433,13 +1467,7 @@ namespace bgfx
 
 	void Texture::create(const Memory* _mem, uint32_t _flags)
 	{
-		m_tau = s_textureAddress[(_flags&BGFX_TEXTURE_U_MASK)>>BGFX_TEXTURE_U_SHIFT];
-		m_tav = s_textureAddress[(_flags&BGFX_TEXTURE_V_MASK)>>BGFX_TEXTURE_V_SHIFT];
-		m_taw = s_textureAddress[(_flags&BGFX_TEXTURE_W_MASK)>>BGFX_TEXTURE_W_SHIFT];
-		m_minFilter = s_textureFilter[(_flags&BGFX_TEXTURE_MIN_MASK)>>BGFX_TEXTURE_MIN_SHIFT];
-		m_magFilter = s_textureFilter[(_flags&BGFX_TEXTURE_MAG_MASK)>>BGFX_TEXTURE_MAG_SHIFT];
-		m_mipFilter = s_textureFilter[(_flags&BGFX_TEXTURE_MIP_MASK)>>BGFX_TEXTURE_MIP_SHIFT];
-		m_srgb = (_flags&BGFX_TEXTURE_SRGB) == BGFX_TEXTURE_SRGB;
+		m_flags = _flags;
 
 		Dds dds;
 
@@ -1673,22 +1701,10 @@ namespace bgfx
 		unlock(s_renderCtx.m_updateTextureSide, s_renderCtx.m_updateTextureMip);
 	}
 
-	void Texture::commit(uint8_t _stage)
+	void Texture::commit(uint8_t _stage, uint32_t _flags)
 	{
-		IDirect3DDevice9* device = s_renderCtx.m_device;
-		DX_CHECK(device->SetSamplerState(_stage, D3DSAMP_MINFILTER, m_minFilter) );
-		DX_CHECK(device->SetSamplerState(_stage, D3DSAMP_MAGFILTER, m_magFilter) );
-		DX_CHECK(device->SetSamplerState(_stage, D3DSAMP_MIPFILTER, m_mipFilter) );
-		DX_CHECK(device->SetSamplerState(_stage, D3DSAMP_ADDRESSU, m_tau) );
-		DX_CHECK(device->SetSamplerState(_stage, D3DSAMP_ADDRESSV, m_tav) );
-		if (m_type == Texture3D)
-		{
-			DX_CHECK(device->SetSamplerState(_stage, D3DSAMP_ADDRESSW, m_taw) );
-		}
-#if BX_PLATFORM_WINDOWS
-		DX_CHECK(device->SetSamplerState(_stage, D3DSAMP_SRGBTEXTURE, m_srgb) );
-#endif // BX_PLATFORM_WINDOWS
-		DX_CHECK(device->SetTexture(_stage, m_ptr) );
+		s_renderCtx.setSamplerState(_stage, 0 == (BGFX_SAMPLER_DEFAULT_FLAGS & _flags) ? _flags : m_flags);
+		DX_CHECK(s_renderCtx.m_device->SetTexture(_stage, m_ptr) );
 	}
 
 	void RenderTarget::create(uint16_t _width, uint16_t _height, uint32_t _flags, uint32_t _textureFlags)
@@ -1696,8 +1712,10 @@ namespace bgfx
 		m_width = _width;
 		m_height = _height;
 		m_flags = _flags;
-		m_minFilter = s_textureFilter[(_textureFlags&BGFX_TEXTURE_MIN_MASK)>>BGFX_TEXTURE_MIN_SHIFT];
-		m_magFilter = s_textureFilter[(_textureFlags&BGFX_TEXTURE_MAG_MASK)>>BGFX_TEXTURE_MAG_SHIFT];
+		m_textureFlags = (_textureFlags&(BGFX_TEXTURE_MIN_MASK|BGFX_TEXTURE_MAG_MASK) )
+						| BGFX_TEXTURE_U_CLAMP
+						| BGFX_TEXTURE_V_CLAMP
+						;
 
 		createTextures();
 	}
@@ -1828,16 +1846,9 @@ namespace bgfx
 		}
 	}
 
-	void RenderTarget::commit(uint8_t _stage)
+	void RenderTarget::commit(uint8_t _stage, uint32_t _textureFlags)
 	{
-		DX_CHECK(s_renderCtx.m_device->SetSamplerState(_stage, D3DSAMP_MINFILTER, m_minFilter) );
-		DX_CHECK(s_renderCtx.m_device->SetSamplerState(_stage, D3DSAMP_MAGFILTER, m_magFilter) );
-		DX_CHECK(s_renderCtx.m_device->SetSamplerState(_stage, D3DSAMP_MIPFILTER, D3DTEXF_POINT) );
-		DX_CHECK(s_renderCtx.m_device->SetSamplerState(_stage, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP) );
-		DX_CHECK(s_renderCtx.m_device->SetSamplerState(_stage, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP) );
-#if BX_PLATFORM_WINDOWS
-		DX_CHECK(s_renderCtx.m_device->SetSamplerState(_stage, D3DSAMP_SRGBTEXTURE, (m_flags&BGFX_RENDER_TARGET_SRGBWRITE) == BGFX_RENDER_TARGET_SRGBWRITE) );
-#endif // BX_PLATFORM_WINDOWS
+		s_renderCtx.setSamplerState(_stage, 0 == (BGFX_SAMPLER_DEFAULT_FLAGS & _textureFlags) ? _textureFlags : m_textureFlags);
 		DX_CHECK(s_renderCtx.m_device->SetTexture(_stage, m_depthOnly ? m_depthTexture : m_colorTexture) );
 	}
 
@@ -2221,6 +2232,8 @@ namespace bgfx
 		uint32_t statsNumInstances = 0;
 		uint32_t statsNumPrimsRendered = 0;
 
+		s_renderCtx.invalidateSamplerState();
+
 		if (0 == (m_render->m_debug&BGFX_DEBUG_IFH) )
 		{
 			for (uint32_t item = 0, numItems = m_render->m_num; item < numItems; ++item)
@@ -2393,7 +2406,6 @@ namespace bgfx
 					 | BGFX_STATE_ALPHA_REF_MASK
 					 | BGFX_STATE_PT_MASK
 					 | BGFX_STATE_POINT_SIZE_MASK
-					 | BGFX_STATE_SRGBWRITE
 					 | BGFX_STATE_MSAA
 					 ) & changedFlags)
 				{
@@ -2430,13 +2442,6 @@ namespace bgfx
 						DX_CHECK(device->SetRenderState(D3DRS_POINTSIZE, castfu( (float)( (newFlags&BGFX_STATE_POINT_SIZE_MASK)>>BGFX_STATE_POINT_SIZE_SHIFT) ) ) );
 					}
 
-#if BX_PLATFORM_WINDOWS
-					if (BGFX_STATE_SRGBWRITE & changedFlags)
-					{
-						DX_CHECK(device->SetRenderState(D3DRS_SRGBWRITEENABLE, (newFlags&BGFX_STATE_SRGBWRITE) == BGFX_STATE_SRGBWRITE) );
-					}
-#endif // BX_PLATFORM_WINDOWS
-
 					if (BGFX_STATE_MSAA & changedFlags)
 					{
 						DX_CHECK(device->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, (newFlags&BGFX_STATE_MSAA) == BGFX_STATE_MSAA) );
@@ -2651,11 +2656,11 @@ namespace bgfx
 								switch (sampler.m_flags&BGFX_SAMPLER_TYPE_MASK)
 								{
 								case BGFX_SAMPLER_TEXTURE:
-									s_renderCtx.m_textures[sampler.m_idx].commit(stage);
+									s_renderCtx.m_textures[sampler.m_idx].commit(stage, sampler.m_flags);
 									break;
 
 								case BGFX_SAMPLER_RENDERTARGET_COLOR:
-									s_renderCtx.m_renderTargets[sampler.m_idx].commit(stage);
+									s_renderCtx.m_renderTargets[sampler.m_idx].commit(stage, sampler.m_flags);
 									break;
 
 								case BGFX_SAMPLER_RENDERTARGET_DEPTH:

+ 4 - 13
src/renderer_d3d9.h

@@ -310,7 +310,7 @@ namespace bgfx
 		void updateBegin(uint8_t _side, uint8_t _mip);
 		void update(uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, const Memory* _mem);
 		void updateEnd();
-		void commit(uint8_t _stage);
+		void commit(uint8_t _stage, uint32_t _flags = BGFX_SAMPLER_DEFAULT_FLAGS);
 	
 		union
 		{
@@ -320,15 +320,9 @@ namespace bgfx
 			IDirect3DCubeTexture9* m_textureCube;
 		};
 
-		D3DTEXTUREFILTERTYPE m_minFilter;
-		D3DTEXTUREFILTERTYPE m_magFilter;
-		D3DTEXTUREFILTERTYPE m_mipFilter;
-		D3DTEXTUREADDRESS m_tau;
-		D3DTEXTUREADDRESS m_tav;
-		D3DTEXTUREADDRESS m_taw;
+		uint32_t m_flags;
 		TextureFormat::Enum m_format;
 		Enum m_type;
-		bool m_srgb;
 	};
 
 	struct RenderTarget
@@ -339,8 +333,6 @@ namespace bgfx
 			, m_color(NULL)
 			, m_depthTexture(NULL)
 			, m_depth(NULL)
-			, m_minFilter(D3DTEXF_LINEAR)
-			, m_magFilter(D3DTEXF_LINEAR)
 			, m_width(0)
 			, m_height(0)
 			, m_flags(0)
@@ -368,7 +360,7 @@ namespace bgfx
 			createTextures();
 		}
 
-		void commit(uint8_t _stage);
+		void commit(uint8_t _stage, uint32_t _textureFlags = BGFX_SAMPLER_DEFAULT_FLAGS);
 		void resolve();
 
 		Msaa m_msaa;
@@ -377,11 +369,10 @@ namespace bgfx
 		IDirect3DSurface9* m_color;
 		IDirect3DTexture9* m_depthTexture;
 		IDirect3DSurface9* m_depth;
-		D3DTEXTUREFILTERTYPE m_minFilter;
-		D3DTEXTUREFILTERTYPE m_magFilter;
 		uint16_t m_width;
 		uint16_t m_height;
 		uint32_t m_flags;
+		uint32_t m_textureFlags;
 		bool m_depthOnly;
 	};
 

+ 335 - 235
src/renderer_gl.cpp

@@ -14,6 +14,204 @@ namespace bgfx
 {
 	static char s_viewName[BGFX_CONFIG_MAX_VIEWS][256];
 
+	static const GLenum s_primType[] =
+	{
+		GL_TRIANGLES,
+		GL_LINES,
+		GL_POINTS,
+	};
+
+	static const char* s_attribName[Attrib::Count] =
+	{
+		"a_position",
+		"a_normal",
+		"a_tangent",
+		"a_color0",
+		"a_color1",
+		"a_indices",
+		"a_weight",
+		"a_texcoord0",
+		"a_texcoord1",
+		"a_texcoord2",
+		"a_texcoord3",
+		"a_texcoord4",
+		"a_texcoord5",
+		"a_texcoord6",
+		"a_texcoord7",
+	};
+
+	static const char* s_instanceDataName[BGFX_CONFIG_MAX_INSTANCE_DATA_COUNT] =
+	{
+		"i_data0",
+		"i_data1",
+		"i_data2",
+		"i_data3",
+		"i_data4",
+	};
+
+	static const GLenum s_attribType[AttribType::Count] =
+	{
+		GL_UNSIGNED_BYTE,
+		GL_SHORT,
+		GL_HALF_FLOAT,
+		GL_FLOAT,
+	};
+
+	struct Blend
+	{
+		GLenum m_src;
+		GLenum m_dst;
+		bool m_factor;
+	};
+
+	static const Blend s_blendFactor[] =
+	{
+		{ 0,                           0,                           false }, // ignored
+		{ GL_ZERO,                     GL_ZERO,                     false },
+		{ GL_ONE,                      GL_ONE,                      false },
+		{ GL_SRC_COLOR,                GL_SRC_COLOR,                false },
+		{ GL_ONE_MINUS_SRC_COLOR,      GL_ONE_MINUS_SRC_COLOR,      false },
+		{ GL_SRC_ALPHA,                GL_SRC_ALPHA,                false },
+		{ GL_ONE_MINUS_SRC_ALPHA,      GL_ONE_MINUS_SRC_ALPHA,      false },
+		{ GL_DST_ALPHA,                GL_DST_ALPHA,                false },
+		{ GL_ONE_MINUS_DST_ALPHA,      GL_ONE_MINUS_DST_ALPHA,      false },
+		{ GL_DST_COLOR,                GL_DST_COLOR,                false },
+		{ GL_ONE_MINUS_DST_COLOR,      GL_ONE_MINUS_DST_COLOR,      false },
+		{ GL_SRC_ALPHA_SATURATE,       GL_ONE,                      false },
+		{ GL_CONSTANT_COLOR,           GL_CONSTANT_COLOR,           true  },
+		{ GL_ONE_MINUS_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR, true  },
+	};
+
+	static const GLenum s_blendEquation[] =
+	{
+		GL_FUNC_ADD,
+		GL_FUNC_SUBTRACT,
+		GL_FUNC_REVERSE_SUBTRACT,
+		GL_MIN,
+		GL_MAX,
+	};
+
+	static const GLenum s_depthFunc[] =
+	{
+		0, // ignored
+		GL_LESS,
+		GL_LEQUAL,
+		GL_EQUAL,
+		GL_GEQUAL,
+		GL_GREATER,
+		GL_NOTEQUAL,
+		GL_NEVER,
+		GL_ALWAYS,
+	};
+
+	static const GLenum s_stencilFunc[] =
+	{
+		0, // ignored
+		GL_LESS,
+		GL_LEQUAL,
+		GL_EQUAL,
+		GL_GEQUAL,
+		GL_GREATER,
+		GL_NOTEQUAL,
+		GL_NEVER,
+		GL_ALWAYS,
+	};
+
+	static const GLenum s_stencilOp[] =
+	{
+		GL_ZERO,
+		GL_KEEP,
+		GL_REPLACE,
+		GL_INCR_WRAP,
+		GL_INCR,
+		GL_DECR_WRAP,
+		GL_DECR,
+		GL_INVERT,
+	};
+
+	static const GLenum s_stencilFace[] =
+	{
+		GL_FRONT_AND_BACK,
+		GL_FRONT,
+		GL_BACK,
+	};
+
+	struct RenderTargetColorFormat
+	{
+		GLenum m_internalFmt;
+		GLenum m_type;
+		uint8_t m_bpp;
+	};
+
+	// Specifies the internal format of the texture.
+	// Must be one of the following symbolic constants:
+	// GL_ALPHA, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA.
+	static const RenderTargetColorFormat s_colorFormat[] =
+	{
+		{ 0,           0,                               0 }, // ignored
+		{ GL_RGBA8,    GL_UNSIGNED_BYTE,               32 },
+		{ GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV, 32 },
+		{ GL_RGBA16,   GL_UNSIGNED_SHORT,              64 },
+		{ GL_RGBA16F,  GL_HALF_FLOAT,                  64 },
+		{ GL_R16F,     GL_HALF_FLOAT,                  16 },
+		{ GL_R32F,     GL_FLOAT,                       32 },
+	};
+
+	static const GLenum s_depthFormat[] =
+	{
+		0, // ignored
+		0,
+	};
+
+	static const GLenum s_textureAddress[] =
+	{
+		GL_REPEAT,
+		GL_MIRRORED_REPEAT,
+		GL_CLAMP_TO_EDGE,
+	};
+
+	static const GLenum s_textureFilterMag[] =
+	{
+		GL_LINEAR,
+		GL_NEAREST,
+		GL_LINEAR,
+	};
+
+	static const GLenum s_textureFilterMin[][3] =
+	{
+		{ GL_LINEAR,  GL_LINEAR_MIPMAP_LINEAR,  GL_NEAREST_MIPMAP_LINEAR  },
+		{ GL_NEAREST, GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_NEAREST },
+		{ GL_LINEAR,  GL_LINEAR_MIPMAP_LINEAR,  GL_NEAREST_MIPMAP_LINEAR  },
+	};
+
+	struct TextureFormatInfo
+	{
+		GLenum m_internalFmt;
+		GLenum m_fmt;
+		GLenum m_type;
+		uint8_t m_bpp;
+		bool m_supported;
+	};
+
+	static TextureFormatInfo s_textureFormat[TextureFormat::Count] =
+	{
+		{ GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,        GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,        GL_ZERO,                        4,  false },
+		{ GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,        GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,        GL_ZERO,                        8,  false },
+		{ GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,        GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,        GL_ZERO,                        8,  false },
+		{ GL_COMPRESSED_LUMINANCE_LATC1_EXT,       GL_COMPRESSED_LUMINANCE_LATC1_EXT,       GL_ZERO,                        4,  false },
+		{ GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT, GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT, GL_ZERO,                        8,  false },
+		{ GL_ZERO,                                 GL_ZERO,                                 GL_ZERO,                        0,  true  },
+		{ GL_LUMINANCE,                            GL_LUMINANCE,                            GL_UNSIGNED_BYTE,               8,  true  },
+		{ GL_RGBA,                                 GL_RGBA,                                 GL_UNSIGNED_BYTE,               32, true  },
+		{ GL_RGBA,                                 GL_RGBA,                                 GL_UNSIGNED_BYTE,               32, true  },
+		{ GL_RGBA16,                               GL_RGBA,                                 GL_UNSIGNED_BYTE,               64, true  },
+		{ GL_RGBA16F,                              GL_RGBA,                                 GL_HALF_FLOAT,                  64, true  },
+		{ GL_RGB565,                               GL_RGB,                                  GL_UNSIGNED_SHORT_5_6_5,        16, true  },
+		{ GL_RGBA4,                                GL_RGBA,                                 GL_UNSIGNED_SHORT_4_4_4_4,      16, true  },
+		{ GL_RGB5_A1,                              GL_RGBA,                                 GL_UNSIGNED_SHORT_5_5_5_1,      16, true  },
+		{ GL_RGB10_A2,                             GL_RGBA,                                 GL_UNSIGNED_INT_2_10_10_10_REV, 32, true  },
+	};
+
 	struct Extension
 	{
 		enum Enum
@@ -26,6 +224,7 @@ namespace bgfx
 			ARB_half_float_vertex,
 			ARB_instanced_arrays,
 			ARB_multisample,
+			ARB_sampler_objects,
 			ARB_seamless_cube_map,
 			ARB_texture_float,
 			ARB_texture_multisample,
@@ -85,6 +284,7 @@ namespace bgfx
 		{ "GL_ARB_half_float_vertex",             false,                             true  },
 		{ "GL_ARB_instanced_arrays",              BGFX_CONFIG_RENDERER_OPENGL >= 33, true  },
 		{ "GL_ARB_multisample",                   false,                             true  },
+		{ "GL_ARB_sampler_objects",               BGFX_CONFIG_RENDERER_OPENGL >= 31, true  },
 		{ "GL_ARB_seamless_cube_map",             BGFX_CONFIG_RENDERER_OPENGL >= 31, true  },
 		{ "GL_ARB_texture_float",                 BGFX_CONFIG_RENDERER_OPENGL >= 31, true  },
 		{ "GL_ARB_texture_multisample",           false,                             true  },
@@ -467,8 +667,52 @@ namespace bgfx
 		{
 			if (m_vaoSupport)
 			{
-				m_vaoCache.invalidate();
+				m_vaoStateCache.invalidate();
 			}
+
+#if !BGFX_CONFIG_RENDERER_OPENGLES2
+			if (m_samplerObjectSupport)
+			{
+				m_samplerStateCache.invalidate();
+			}
+#endif // !BGFX_CONFIG_RENDERER_OPENGLES2
+		}
+
+		void setSamplerState(uint32_t _stage, uint32_t _numMips, uint32_t _flags)
+		{
+#if !BGFX_CONFIG_RENDERER_OPENGLES2
+			if (0 == (BGFX_SAMPLER_DEFAULT_FLAGS & _flags) )
+			{
+				GLuint sampler = m_samplerStateCache.find(_flags);
+
+				if (UINT32_MAX == sampler)
+				{
+					sampler = m_samplerStateCache.add(_flags);
+
+					GL_CHECK(glSamplerParameteri(sampler, GL_TEXTURE_WRAP_S, s_textureAddress[(_flags&BGFX_TEXTURE_U_MASK)>>BGFX_TEXTURE_U_SHIFT]) );
+					GL_CHECK(glSamplerParameteri(sampler, GL_TEXTURE_WRAP_T, s_textureAddress[(_flags&BGFX_TEXTURE_V_MASK)>>BGFX_TEXTURE_V_SHIFT]) );
+					GL_CHECK(glSamplerParameteri(sampler, GL_TEXTURE_WRAP_R, s_textureAddress[(_flags&BGFX_TEXTURE_W_MASK)>>BGFX_TEXTURE_W_SHIFT]) );
+
+					uint32_t mag = (_flags&BGFX_TEXTURE_MAG_MASK)>>BGFX_TEXTURE_MAG_SHIFT;
+					uint32_t min = (_flags&BGFX_TEXTURE_MIN_MASK)>>BGFX_TEXTURE_MIN_SHIFT;
+					uint32_t mip = (_flags&BGFX_TEXTURE_MIP_MASK)>>BGFX_TEXTURE_MIP_SHIFT;
+					GLenum minFilter = s_textureFilterMin[min][1 < _numMips ? mip+1 : 0];
+					GL_CHECK(glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, s_textureFilterMag[mag]) );
+					GL_CHECK(glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, minFilter) );
+					if (0 != (_flags & (BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC) ) 
+					&&  0.0f < m_maxAnisotropy)
+					{
+						GL_CHECK(glSamplerParameterf(sampler, GL_TEXTURE_MAX_ANISOTROPY_EXT, m_maxAnisotropy) );
+					}
+				}
+
+				GL_CHECK(glBindSampler(_stage, sampler) );
+			}
+			else
+			{
+				GL_CHECK(glBindSampler(_stage, 0) );
+			}
+#endif // !BGFX_CONFIG_RENDERER_OPENGLES2
 		}
 
 		void updateCapture()
@@ -594,7 +838,10 @@ namespace bgfx
 		Queries m_queries;
 #endif // BGFX_CONFIG_RENDERER_OPENGL
 
-		VaoCache m_vaoCache;
+		VaoStateCache m_vaoStateCache;
+#if !BGFX_CONFIG_RENDERER_OPENGLES2
+		SamplerStateCache m_samplerStateCache;
+#endif // !BGFX_CONFIG_RENDERER_OPENGLES2
 
 		TextVideoMem m_textVideoMem;
 		RenderTargetHandle m_rt;
@@ -607,6 +854,7 @@ namespace bgfx
 		int32_t m_maxMsaa;
 		GLuint m_vao;
 		bool m_vaoSupport;
+		bool m_samplerObjectSupport;
 		bool m_programBinarySupport;
 		bool m_textureSwizzleSupport;
 		bool m_useClearQuad;
@@ -667,204 +915,6 @@ namespace bgfx
 	}
 #endif // BX_PLATFORM_
 
-	static const GLenum s_primType[] =
-	{
-		GL_TRIANGLES,
-		GL_LINES,
-		GL_POINTS,
-	};
-
-	static const char* s_attribName[Attrib::Count] =
-	{
-		"a_position",
-		"a_normal",
-		"a_tangent",
-		"a_color0",
-		"a_color1",
-		"a_indices",
-		"a_weight",
-		"a_texcoord0",
-		"a_texcoord1",
-		"a_texcoord2",
-		"a_texcoord3",
-		"a_texcoord4",
-		"a_texcoord5",
-		"a_texcoord6",
-		"a_texcoord7",
-	};
-
-	static const char* s_instanceDataName[BGFX_CONFIG_MAX_INSTANCE_DATA_COUNT] =
-	{
-		"i_data0",
-		"i_data1",
-		"i_data2",
-		"i_data3",
-		"i_data4",
-	};
-
-	static const GLenum s_attribType[AttribType::Count] =
-	{
-		GL_UNSIGNED_BYTE,
-		GL_SHORT,
-		GL_HALF_FLOAT,
-		GL_FLOAT,
-	};
-
-	struct Blend
-	{
-		GLenum m_src;
-		GLenum m_dst;
-		bool m_factor;
-	};
-
-	static const Blend s_blendFactor[] =
-	{
-		{ 0,                           0,                           false }, // ignored
-		{ GL_ZERO,                     GL_ZERO,                     false },
-		{ GL_ONE,                      GL_ONE,                      false },
-		{ GL_SRC_COLOR,                GL_SRC_COLOR,                false },
-		{ GL_ONE_MINUS_SRC_COLOR,      GL_ONE_MINUS_SRC_COLOR,      false },
-		{ GL_SRC_ALPHA,                GL_SRC_ALPHA,                false },
-		{ GL_ONE_MINUS_SRC_ALPHA,      GL_ONE_MINUS_SRC_ALPHA,      false },
-		{ GL_DST_ALPHA,                GL_DST_ALPHA,                false },
-		{ GL_ONE_MINUS_DST_ALPHA,      GL_ONE_MINUS_DST_ALPHA,      false },
-		{ GL_DST_COLOR,                GL_DST_COLOR,                false },
-		{ GL_ONE_MINUS_DST_COLOR,      GL_ONE_MINUS_DST_COLOR,      false },
-		{ GL_SRC_ALPHA_SATURATE,       GL_ONE,                      false },
-		{ GL_CONSTANT_COLOR,           GL_CONSTANT_COLOR,           true  },
-		{ GL_ONE_MINUS_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR, true  },
-	};
-
-	static const GLenum s_blendEquation[] =
-	{
-		GL_FUNC_ADD,
-		GL_FUNC_SUBTRACT,
-		GL_FUNC_REVERSE_SUBTRACT,
-		GL_MIN,
-		GL_MAX,
-	};
-
-	static const GLenum s_depthFunc[] =
-	{
-		0, // ignored
-		GL_LESS,
-		GL_LEQUAL,
-		GL_EQUAL,
-		GL_GEQUAL,
-		GL_GREATER,
-		GL_NOTEQUAL,
-		GL_NEVER,
-		GL_ALWAYS,
-	};
-
-	static const GLenum s_stencilFunc[] =
-	{
-		0, // ignored
-		GL_LESS,
-		GL_LEQUAL,
-		GL_EQUAL,
-		GL_GEQUAL,
-		GL_GREATER,
-		GL_NOTEQUAL,
-		GL_NEVER,
-		GL_ALWAYS,
-	};
-
-	static const GLenum s_stencilOp[] =
-	{
-		GL_ZERO,
-		GL_KEEP,
-		GL_REPLACE,
-		GL_INCR_WRAP,
-		GL_INCR,
-		GL_DECR_WRAP,
-		GL_DECR,
-		GL_INVERT,
-	};
-
-	static const GLenum s_stencilFace[] =
-	{
-		GL_FRONT_AND_BACK,
-		GL_FRONT,
-		GL_BACK,
-	};
-
-	struct RenderTargetColorFormat
-	{
-		GLenum m_internalFmt;
-		GLenum m_type;
-		uint8_t m_bpp;
-	};
-
-	// Specifies the internal format of the texture.
-	// Must be one of the following symbolic constants:
-	// GL_ALPHA, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA.
-	static const RenderTargetColorFormat s_colorFormat[] =
-	{
-		{ 0,           0,                               0 }, // ignored
-		{ GL_RGBA8,    GL_UNSIGNED_BYTE,               32 },
-		{ GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV, 32 },
-		{ GL_RGBA16,   GL_UNSIGNED_SHORT,              64 },
-		{ GL_RGBA16F,  GL_HALF_FLOAT,                  64 },
-		{ GL_R16F,     GL_HALF_FLOAT,                  16 },
-		{ GL_R32F,     GL_FLOAT,                       32 },
-	};
-
-	static const GLenum s_depthFormat[] =
-	{
-		0, // ignored
-		0,
-	};
-
-	static const GLenum s_textureAddress[] =
-	{
-		GL_REPEAT,
-		GL_MIRRORED_REPEAT,
-		GL_CLAMP_TO_EDGE,
-	};
-
-	static const GLenum s_textureFilterMag[] =
-	{
-		GL_LINEAR,
-		GL_NEAREST,
-		GL_LINEAR,
-	};
-
-	static const GLenum s_textureFilterMin[][3] =
-	{
-		{ GL_LINEAR,  GL_LINEAR_MIPMAP_LINEAR,  GL_NEAREST_MIPMAP_LINEAR  },
-		{ GL_NEAREST, GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_NEAREST },
-		{ GL_LINEAR,  GL_LINEAR_MIPMAP_LINEAR,  GL_NEAREST_MIPMAP_LINEAR  },
-	};
-
-	struct TextureFormatInfo
-	{
-		GLenum m_internalFmt;
-		GLenum m_fmt;
-		GLenum m_type;
-		uint8_t m_bpp;
-		bool m_supported;
-	};
-
-	static TextureFormatInfo s_textureFormat[TextureFormat::Count] =
-	{
-		{ GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,        GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,        GL_ZERO,                        4,  false },
-		{ GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,        GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,        GL_ZERO,                        8,  false },
-		{ GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,        GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,        GL_ZERO,                        8,  false },
-		{ GL_COMPRESSED_LUMINANCE_LATC1_EXT,       GL_COMPRESSED_LUMINANCE_LATC1_EXT,       GL_ZERO,                        4,  false },
-		{ GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT, GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT, GL_ZERO,                        8,  false },
-		{ GL_ZERO,                                 GL_ZERO,                                 GL_ZERO,                        0,  true  },
-		{ GL_LUMINANCE,                            GL_LUMINANCE,                            GL_UNSIGNED_BYTE,               8,  true  },
-		{ GL_RGBA,                                 GL_RGBA,                                 GL_UNSIGNED_BYTE,               32, true  },
-		{ GL_RGBA,                                 GL_RGBA,                                 GL_UNSIGNED_BYTE,               32, true  },
-		{ GL_RGBA16,                               GL_RGBA,                                 GL_UNSIGNED_BYTE,               64, true  },
-		{ GL_RGBA16F,                              GL_RGBA,                                 GL_HALF_FLOAT,                  64, true  },
-		{ GL_RGB565,                               GL_RGB,                                  GL_UNSIGNED_SHORT_5_6_5,        16, true  },
-		{ GL_RGBA4,                                GL_RGBA,                                 GL_UNSIGNED_SHORT_4_4_4_4,      16, true  },
-		{ GL_RGB5_A1,                              GL_RGBA,                                 GL_UNSIGNED_SHORT_5_5_5_1,      16, true  },
-		{ GL_RGB10_A2,                             GL_RGBA,                                 GL_UNSIGNED_INT_2_10_10_10_REV, 32, true  },
-	};
-
 	const char* glslTypeName(GLuint _type)
 	{
 #define GLSL_TYPE(_ty) case _ty: return #_ty
@@ -1042,7 +1092,7 @@ namespace bgfx
 		GL_CHECK(glUseProgram(0) );
 		GL_CHECK(glDeleteProgram(m_id) );
 
-		m_vcref.invalidate(s_renderCtx.m_vaoCache);
+		m_vcref.invalidate(s_renderCtx.m_vaoStateCache);
 	}
 
 	void Program::init()
@@ -1245,7 +1295,7 @@ namespace bgfx
 		GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) );
 		GL_CHECK(glDeleteBuffers(1, &m_id) );
 
-		m_vcref.invalidate(s_renderCtx.m_vaoCache);
+		m_vcref.invalidate(s_renderCtx.m_vaoStateCache);
 	}
 
 	void VertexBuffer::destroy()
@@ -1253,7 +1303,7 @@ namespace bgfx
 		GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0) );
 		GL_CHECK(glDeleteBuffers(1, &m_id) );
 
-		m_vcref.invalidate(s_renderCtx.m_vaoCache);
+		m_vcref.invalidate(s_renderCtx.m_vaoStateCache);
 	}
 
 	static void texImage(GLenum _target, GLint _level, GLint _internalFormat, GLsizei _width, GLsizei _height, GLsizei _depth, GLint _border, GLenum _format, GLenum _type, const GLvoid* _pixels)
@@ -1325,34 +1375,15 @@ namespace bgfx
 	void Texture::init(GLenum _target, uint8_t _numMips, uint32_t _flags)
 	{
 		m_target = _target;
+		m_numMips = _numMips;
+		m_flags = _flags;
+		m_currentFlags = UINT32_MAX;
 
 		GL_CHECK(glGenTextures(1, &m_id) );
 		BX_CHECK(0 != m_id, "Failed to generate texture id.");
 		GL_CHECK(glBindTexture(_target, m_id) );
 
-		GL_CHECK(glTexParameteri(_target, GL_TEXTURE_WRAP_S, s_textureAddress[(_flags&BGFX_TEXTURE_U_MASK)>>BGFX_TEXTURE_U_SHIFT]) );
-		GL_CHECK(glTexParameteri(_target, GL_TEXTURE_WRAP_T, s_textureAddress[(_flags&BGFX_TEXTURE_V_MASK)>>BGFX_TEXTURE_V_SHIFT]) );
-
-#if BGFX_CONFIG_RENDERER_OPENGL|BGFX_CONFIG_RENDERER_OPENGLES3
-		GL_CHECK(glTexParameteri(_target, GL_TEXTURE_MAX_LEVEL, _numMips-1) );
-
-		if (_target == GL_TEXTURE_3D)
-		{
-			GL_CHECK(glTexParameteri(_target, GL_TEXTURE_WRAP_R, s_textureAddress[(_flags&BGFX_TEXTURE_W_MASK)>>BGFX_TEXTURE_W_SHIFT]) );
-		}
-#endif // BGFX_CONFIG_RENDERER_OPENGL|BGFX_CONFIG_RENDERER_OPENGLES3
-
-		uint32_t mag = (_flags&BGFX_TEXTURE_MAG_MASK)>>BGFX_TEXTURE_MAG_SHIFT;
-		uint32_t min = (_flags&BGFX_TEXTURE_MIN_MASK)>>BGFX_TEXTURE_MIN_SHIFT;
-		uint32_t mip = (_flags&BGFX_TEXTURE_MIP_MASK)>>BGFX_TEXTURE_MIP_SHIFT;
-		GLenum minFilter = s_textureFilterMin[min][1 < _numMips ? mip+1 : 0];
-		GL_CHECK(glTexParameteri(_target, GL_TEXTURE_MAG_FILTER, s_textureFilterMag[mag]) );
-		GL_CHECK(glTexParameteri(_target, GL_TEXTURE_MIN_FILTER, minFilter) );
-		if (0 != (_flags & (BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC) ) 
-		&&  0.0f < s_renderCtx.m_maxAnisotropy)
-		{
-			GL_CHECK(glTexParameterf(_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, s_renderCtx.m_maxAnisotropy) );
-		}
+		setSamplerState(_flags);
 	}
 
 	void Texture::create(const Memory* _mem, uint32_t _flags)
@@ -1635,6 +1666,9 @@ namespace bgfx
 		GLenum internalFormat = rtcf.m_internalFmt;
 		GLenum type = rtcf.m_type;
 		m_target = GL_TEXTURE_2D;
+		m_numMips = 1;
+//		m_flags = _flags;
+		m_currentFlags = UINT32_MAX;
 
 		GL_CHECK(glGenTextures(1, &m_id) );
 		BX_CHECK(0 != m_id, "Failed to generate texture id.");
@@ -1666,6 +1700,7 @@ namespace bgfx
 	void Texture::createDepth(uint32_t _width, uint32_t _height)
 	{
 		m_target = GL_TEXTURE_2D;
+		m_numMips = 1;
 
 		GL_CHECK(glGenTextures(1, &m_id) );
 		BX_CHECK(0 != m_id, "Failed to generate texture id.");
@@ -1812,6 +1847,67 @@ namespace bgfx
 		}
 	}
 
+	void Texture::setSamplerState(uint32_t _flags)
+	{
+		const uint32_t flags = _flags&(~BGFX_TEXTURE_RESERVED_MASK);
+		if ( (0 != (BGFX_SAMPLER_DEFAULT_FLAGS & _flags) && m_flags != m_currentFlags)
+		||  m_currentFlags != flags)
+		{
+			const GLenum target = m_target;
+			const uint8_t numMips = m_numMips;
+
+			GL_CHECK(glTexParameteri(target, GL_TEXTURE_WRAP_S, s_textureAddress[(flags&BGFX_TEXTURE_U_MASK)>>BGFX_TEXTURE_U_SHIFT]) );
+			GL_CHECK(glTexParameteri(target, GL_TEXTURE_WRAP_T, s_textureAddress[(flags&BGFX_TEXTURE_V_MASK)>>BGFX_TEXTURE_V_SHIFT]) );
+
+#if BGFX_CONFIG_RENDERER_OPENGL|BGFX_CONFIG_RENDERER_OPENGLES3
+			GL_CHECK(glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, numMips-1) );
+
+			if (target == GL_TEXTURE_3D)
+			{
+				GL_CHECK(glTexParameteri(target, GL_TEXTURE_WRAP_R, s_textureAddress[(flags&BGFX_TEXTURE_W_MASK)>>BGFX_TEXTURE_W_SHIFT]) );
+			}
+#endif // BGFX_CONFIG_RENDERER_OPENGL|BGFX_CONFIG_RENDERER_OPENGLES3
+
+			uint32_t mag = (flags&BGFX_TEXTURE_MAG_MASK)>>BGFX_TEXTURE_MAG_SHIFT;
+			uint32_t min = (flags&BGFX_TEXTURE_MIN_MASK)>>BGFX_TEXTURE_MIN_SHIFT;
+			uint32_t mip = (flags&BGFX_TEXTURE_MIP_MASK)>>BGFX_TEXTURE_MIP_SHIFT;
+			GLenum minFilter = s_textureFilterMin[min][1 < numMips ? mip+1 : 0];
+			GL_CHECK(glTexParameteri(target, GL_TEXTURE_MAG_FILTER, s_textureFilterMag[mag]) );
+			GL_CHECK(glTexParameteri(target, GL_TEXTURE_MIN_FILTER, minFilter) );
+			if (0 != (flags & (BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC) ) 
+			&&  0.0f < s_renderCtx.m_maxAnisotropy)
+			{
+				GL_CHECK(glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, s_renderCtx.m_maxAnisotropy) );
+			}
+
+			m_currentFlags = flags;
+		}
+	}
+
+	void Texture::commit(uint32_t _stage, uint32_t _flags)
+	{
+		GL_CHECK(glActiveTexture(GL_TEXTURE0+_stage) );
+		GL_CHECK(glBindTexture(m_target, m_id) );
+
+#if BGFX_CONFIG_RENDERER_OPENGLES2
+		// GLES2 doesn't have support for sampler object.
+		setSamplerState(_flags);
+#elif BGFX_CONFIG_RENDERER_OPENGL < 31
+		// In case that GL 2.1 sampler object is supported via extension.
+		if (s_renderCtx.m_samplerObjectSupport)
+		{
+			s_renderCtx.setSamplerState(_stage, m_numMips, _flags);
+		}
+		else
+		{
+			setSamplerState(_flags);
+		}
+#else
+		// Everything else has sampler object.
+		s_renderCtx.setSamplerState(_stage, m_numMips, _flags);
+#endif // BGFX_CONFIG_RENDERER_*
+	}
+
 	void RenderTarget::create(uint16_t _width, uint16_t _height, uint32_t _flags, uint32_t _textureFlags)
 	{
 		BX_TRACE("Create render target %dx%d 0x%02x", _width, _height, _flags);
@@ -2382,6 +2478,11 @@ namespace bgfx
 			|| s_extension[Extension::OES_vertex_array_object].m_supported
 			;
 
+		s_renderCtx.m_samplerObjectSupport = !!BGFX_CONFIG_RENDERER_OPENGLES3
+			|| s_extension[Extension::ARB_sampler_objects].m_supported
+			;
+s_renderCtx.m_samplerObjectSupport = false;
+
 		s_renderCtx.m_programBinarySupport = !!BGFX_CONFIG_RENDERER_OPENGLES3
 			|| s_extension[Extension::ARB_get_program_binary].m_supported
 			|| s_extension[Extension::OES_get_program_binary].m_supported
@@ -3133,27 +3234,26 @@ namespace bgfx
 							{
 								if (invalidHandle != sampler.m_idx)
 								{
-									GL_CHECK(glActiveTexture(GL_TEXTURE0+stage) );
 									switch (sampler.m_flags&BGFX_SAMPLER_TYPE_MASK)
 									{
 									case BGFX_SAMPLER_TEXTURE:
 										{
-											const Texture& texture = s_renderCtx.m_textures[sampler.m_idx];
-											GL_CHECK(glBindTexture(texture.m_target, texture.m_id) );
+											Texture& texture = s_renderCtx.m_textures[sampler.m_idx];
+											texture.commit(stage, sampler.m_flags);
 										}
 										break;
 
 									case BGFX_SAMPLER_RENDERTARGET_COLOR:
 										{
-											const RenderTarget& rt = s_renderCtx.m_renderTargets[sampler.m_idx];
-											GL_CHECK(glBindTexture(rt.m_color.m_target, rt.m_color.m_id) );
+											RenderTarget& rt = s_renderCtx.m_renderTargets[sampler.m_idx];
+											rt.m_color.commit(stage, sampler.m_flags);
 										}
 										break;
 
 									case BGFX_SAMPLER_RENDERTARGET_DEPTH:
 										{
-											const RenderTarget& rt = s_renderCtx.m_renderTargets[sampler.m_idx];
-											GL_CHECK(glBindTexture(rt.m_depth.m_target, rt.m_depth.m_id) );
+											RenderTarget& rt = s_renderCtx.m_renderTargets[sampler.m_idx];
+											rt.m_depth.commit(stage, sampler.m_flags);
 										}
 										break;
 									}
@@ -3186,7 +3286,7 @@ namespace bgfx
 							currentState.m_indexBuffer = state.m_indexBuffer;
 							baseVertex = state.m_startVertex;
 
-							GLuint id = s_renderCtx.m_vaoCache.find(hash);
+							GLuint id = s_renderCtx.m_vaoStateCache.find(hash);
 							if (UINT32_MAX != id)
 							{
 								currentVao = id;
@@ -3194,7 +3294,7 @@ namespace bgfx
 							}
 							else
 							{
-								id = s_renderCtx.m_vaoCache.add(hash);
+								id = s_renderCtx.m_vaoStateCache.add(hash);
 								currentVao = id;
 								GL_CHECK(glBindVertexArray(id) );
 

+ 62 - 2
src/renderer_gl.h

@@ -296,7 +296,7 @@ namespace bgfx
 
 	class ConstantBuffer;
 	
-	class VaoCache
+	class VaoStateCache
 	{
 	public:
 		GLuint add(uint32_t _hash)
@@ -358,7 +358,7 @@ namespace bgfx
 			m_vaoSet.insert(_hash);
 		}
 
-		void invalidate(VaoCache& _vaoCache)
+		void invalidate(VaoStateCache& _vaoCache)
 		{
 			for (VaoSet::iterator it = m_vaoSet.begin(), itEnd = m_vaoSet.end(); it != itEnd; ++it)
 			{
@@ -372,6 +372,58 @@ namespace bgfx
 		VaoSet m_vaoSet;
 	};
 
+#if !BGFX_CONFIG_RENDERER_OPENGLES2
+	class SamplerStateCache
+	{
+	public:
+		GLuint add(uint32_t _hash)
+		{
+			invalidate(_hash);
+
+			GLuint samplerId;
+			GL_CHECK(glGenSamplers(1, &samplerId) );
+
+			m_hashMap.insert(stl::make_pair(_hash, samplerId) );
+
+			return samplerId;
+		}
+
+		GLuint find(uint32_t _hash)
+		{
+			HashMap::iterator it = m_hashMap.find(_hash);
+			if (it != m_hashMap.end() )
+			{
+				return it->second;
+			}
+
+			return UINT32_MAX;
+		}
+
+		void invalidate(uint32_t _hash)
+		{
+			HashMap::iterator it = m_hashMap.find(_hash);
+			if (it != m_hashMap.end() )
+			{
+				GL_CHECK(glDeleteSamplers(1, &it->second) );
+				m_hashMap.erase(it);
+			}
+		}
+
+		void invalidate()
+		{
+			for (HashMap::iterator it = m_hashMap.begin(), itEnd = m_hashMap.end(); it != itEnd; ++it)
+			{
+				GL_CHECK(glDeleteSamplers(1, &it->second) );
+			}
+			m_hashMap.clear();
+		}
+
+	private:
+		typedef stl::unordered_map<uint32_t, GLuint> HashMap;
+		HashMap m_hashMap;
+	};
+#endif // !BGFX_CONFIG_RENDERER_OPENGLES2
+
 	struct IndexBuffer
 	{
 		void create(uint32_t _size, void* _data)
@@ -461,6 +513,9 @@ namespace bgfx
 			, m_target(GL_TEXTURE_2D)
 			, m_fmt(GL_ZERO)
 			, m_type(GL_ZERO)
+			, m_flags(0)
+			, m_currentFlags(UINT32_MAX)
+			, m_numMips(0)
 			, m_compressed(false)
 		{
 		}
@@ -471,11 +526,16 @@ namespace bgfx
 		void createDepth(uint32_t _width, uint32_t _height);
 		void destroy();
 		void update(uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, const Memory* _mem);
+		void setSamplerState(uint32_t _flags);
+		void commit(uint32_t _stage, uint32_t _flags);
 
 		GLuint m_id;
 		GLenum m_target;
 		GLenum m_fmt;
 		GLenum m_type;
+		uint32_t m_flags;
+		uint32_t m_currentFlags;
+		uint8_t m_numMips;
 		bool m_compressed;
 	};