Browse Source

D3D11: Fixed compute image mip selection.

Branimir Karadžić 10 years ago
parent
commit
63e10f3357
7 changed files with 238 additions and 51 deletions
  1. 5 1
      examples/common/bgfx_utils.cpp
  2. 4 14
      src/bgfx.cpp
  3. 25 2
      src/bgfx_p.h
  4. 85 27
      src/renderer_d3d.h
  5. 115 5
      src/renderer_d3d11.cpp
  6. 1 0
      src/renderer_d3d11.h
  7. 3 2
      src/renderer_d3d12.cpp

+ 5 - 1
examples/common/bgfx_utils.cpp

@@ -131,7 +131,11 @@ bgfx::ShaderHandle loadShader(const char* _name)
 bgfx::ProgramHandle loadProgram(bx::FileReaderI* _reader, const char* _vsName, const char* _fsName)
 {
 	bgfx::ShaderHandle vsh = loadShader(_reader, _vsName);
-	bgfx::ShaderHandle fsh = loadShader(_reader, _fsName);
+	bgfx::ShaderHandle fsh = BGFX_INVALID_HANDLE;
+	if (NULL != _fsName)
+	{
+		fsh = loadShader(_reader, _fsName);
+	}
 
 	return bgfx::createProgram(vsh, fsh, true /* destroy shaders when program is destroyed */);
 }

+ 4 - 14
src/bgfx.cpp

@@ -2507,28 +2507,18 @@ again:
 	ProgramHandle createProgram(ShaderHandle _vsh, ShaderHandle _fsh, bool _destroyShaders)
 	{
 		BGFX_CHECK_MAIN_THREAD();
-		ProgramHandle handle = s_ctx->createProgram(_vsh, _fsh);
-
-		if (_destroyShaders)
+		if (!isValid(_fsh) )
 		{
-			destroyShader(_vsh);
-			destroyShader(_fsh);
+			return createProgram(_vsh, _destroyShaders);
 		}
 
-		return handle;
+		return s_ctx->createProgram(_vsh, _fsh, _destroyShaders);
 	}
 
 	ProgramHandle createProgram(ShaderHandle _csh, bool _destroyShader)
 	{
 		BGFX_CHECK_MAIN_THREAD();
-		ProgramHandle handle = s_ctx->createProgram(_csh);
-
-		if (_destroyShader)
-		{
-			destroyShader(_csh);
-		}
-
-		return handle;
+		return s_ctx->createProgram(_csh, _destroyShader);
 	}
 
 	void destroyProgram(ProgramHandle _handle)

+ 25 - 2
src/bgfx_p.h

@@ -2603,6 +2603,7 @@ namespace bgfx
 				sr.m_refCount = 1;
 				sr.m_hash     = iohash;
 				sr.m_num      = 0;
+				sr.m_owned    = false;
 				sr.m_uniforms = NULL;
 
 				UniformHandle* uniforms = (UniformHandle*)alloca(count*sizeof(UniformHandle) );
@@ -2682,6 +2683,16 @@ namespace bgfx
 			shaderDecRef(_handle);
 		}
 
+		void shaderTakeOwnership(ShaderHandle _handle)
+		{
+			ShaderRef& sr = m_shaderRef[_handle.idx];
+			if (!sr.m_owned)
+			{
+				sr.m_owned = true;
+				shaderDecRef(_handle);
+			}
+		}
+
 		void shaderIncRef(ShaderHandle _handle)
 		{
 			ShaderRef& sr = m_shaderRef[_handle.idx];
@@ -2712,7 +2723,7 @@ namespace bgfx
 			}
 		}
 
-		BGFX_API_FUNC(ProgramHandle createProgram(ShaderHandle _vsh, ShaderHandle _fsh) )
+		BGFX_API_FUNC(ProgramHandle createProgram(ShaderHandle _vsh, ShaderHandle _fsh, bool _destroyShaders) )
 		{
 			if (!isValid(_vsh)
 			||  !isValid(_fsh) )
@@ -2749,10 +2760,16 @@ namespace bgfx
 				cmdbuf.write(_fsh);
 			}
 
+			if (_destroyShaders)
+			{
+				shaderTakeOwnership(_vsh);
+				shaderTakeOwnership(_fsh);
+			}
+
 			return handle;
 		}
 
-		BGFX_API_FUNC(ProgramHandle createProgram(ShaderHandle _vsh) )
+		BGFX_API_FUNC(ProgramHandle createProgram(ShaderHandle _vsh, bool _destroyShader) )
 		{
 			if (!isValid(_vsh) )
 			{
@@ -2779,6 +2796,11 @@ namespace bgfx
 				cmdbuf.write(fsh);
 			}
 
+			if (_destroyShader)
+			{
+				shaderTakeOwnership(_vsh);
+			}
+
 			return handle;
 		}
 
@@ -3564,6 +3586,7 @@ namespace bgfx
 			uint32_t m_hash;
 			int16_t  m_refCount;
 			uint16_t m_num;
+			bool     m_owned;
 		};
 
 		struct ProgramRef

+ 85 - 27
src/renderer_d3d.h

@@ -100,15 +100,15 @@ namespace bgfx
 	class StateCacheT
 	{
 	public:
-		void add(uint64_t _id, Ty* _item)
+		void add(uint64_t _key, Ty* _value)
 		{
-			invalidate(_id);
-			m_hashMap.insert(stl::make_pair(_id, _item) );
+			invalidate(_key);
+			m_hashMap.insert(stl::make_pair(_key, _value) );
 		}
 
-		Ty* find(uint64_t _id)
+		Ty* find(uint64_t _key)
 		{
-			typename HashMap::iterator it = m_hashMap.find(_id);
+			typename HashMap::iterator it = m_hashMap.find(_key);
 			if (it != m_hashMap.end() )
 			{
 				return it->second;
@@ -117,9 +117,9 @@ namespace bgfx
 			return NULL;
 		}
 
-		void invalidate(uint64_t _id)
+		void invalidate(uint64_t _key)
 		{
-			typename HashMap::iterator it = m_hashMap.find(_id);
+			typename HashMap::iterator it = m_hashMap.find(_key);
 			if (it != m_hashMap.end() )
 			{
 				DX_RELEASE_WARNONLY(it->second, 0);
@@ -151,15 +151,15 @@ namespace bgfx
 	class StateCache
 	{
 	public:
-		void add(uint64_t _id, uint16_t _item)
+		void add(uint64_t _key, uint16_t _value)
 		{
-			invalidate(_id);
-			m_hashMap.insert(stl::make_pair(_id, _item) );
+			invalidate(_key);
+			m_hashMap.insert(stl::make_pair(_key, _value) );
 		}
 
-		uint16_t find(uint64_t _id)
+		uint16_t find(uint64_t _key)
 		{
-			HashMap::iterator it = m_hashMap.find(_id);
+			HashMap::iterator it = m_hashMap.find(_key);
 			if (it != m_hashMap.end() )
 			{
 				return it->second;
@@ -168,9 +168,9 @@ namespace bgfx
 			return UINT16_MAX;
 		}
 
-		void invalidate(uint64_t _id)
+		void invalidate(uint64_t _key)
 		{
-			HashMap::iterator it = m_hashMap.find(_id);
+			HashMap::iterator it = m_hashMap.find(_key);
 			if (it != m_hashMap.end() )
 			{
 				m_hashMap.erase(it);
@@ -196,33 +196,28 @@ namespace bgfx
 	class StateCacheLru
 	{
 	public:
-		void add(uint64_t _hash, Ty _value)
+		void add(uint64_t _key, Ty _value, uint16_t _parent)
 		{
 			uint16_t handle = m_alloc.alloc();
 			if (UINT16_MAX == handle)
 			{
 				uint16_t back = m_alloc.getBack();
-				m_alloc.free(back);
-				HashMap::iterator it = m_hashMap.find(m_data[back].m_hash);
-				if (it != m_hashMap.end() )
-				{
-					m_hashMap.erase(it);
-				}
-
+				invalidate(back);
 				handle = m_alloc.alloc();
 			}
 
 			BX_CHECK(UINT16_MAX != handle, "Failed to find handle.");
 
 			Data& data = m_data[handle];
-			data.m_hash  = _hash;
-			data.m_value = _value;
-			m_hashMap.insert(stl::make_pair(_hash, handle) );
+			data.m_hash   = _key;
+			data.m_value  = _value;
+			data.m_parent = _parent;
+			m_hashMap.insert(stl::make_pair(_key, handle) );
 		}
 
-		Ty* find(uint64_t _hash)
+		Ty* find(uint64_t _key)
 		{
-			HashMap::iterator it = m_hashMap.find(_hash);
+			HashMap::iterator it = m_hashMap.find(_key);
 			if (it != m_hashMap.end() )
 			{
 				uint16_t handle = it->second;
@@ -233,8 +228,59 @@ namespace bgfx
 			return NULL;
 		}
 
+		void invalidate(uint64_t _key)
+		{
+			HashMap::iterator it = m_hashMap.find(_key);
+			if (it != m_hashMap.end() )
+			{
+				uint16_t handle = it->second;
+				m_alloc.free(_handle);
+				m_hashMap.erase(it);
+				release(m_data[handle].m_value);
+			}
+		}
+
+		void invalidate(uint16_t _handle)
+		{
+			if (m_alloc.isValid(_handle) )
+			{
+				m_alloc.free(_handle);
+				Data& data = m_data[_handle];
+				m_hashMap.erase(m_hashMap.find(data.m_hash) );
+				release(data.m_value);
+			}
+		}
+
+		void invalidateWithParent(uint16_t _parent)
+		{
+			for (uint32_t ii = 0; ii < m_alloc.getNumHandles();)
+			{
+				uint16_t handle = m_alloc.getHandleAt(ii);
+				Data& data = m_data[handle];
+
+				if (data.m_parent == _parent)
+				{
+					m_alloc.free(handle);
+					Data& data = m_data[handle];
+					m_hashMap.erase(m_hashMap.find(data.m_hash) );
+					release(data.m_value);
+				}
+				else
+				{
+					++ii;
+				}
+			}
+		}
+
 		void invalidate()
 		{
+			for (uint32_t ii = 0, num =  m_alloc.getNumHandles(); ii < num; ++ii)
+			{
+				uint16_t handle = m_alloc.getHandleAt(ii);
+				Data& data = m_data[handle];
+				release(data.m_value);
+			}
+
 			m_hashMap.clear();
 			m_alloc.reset();
 		}
@@ -244,6 +290,17 @@ namespace bgfx
 			return uint32_t(m_hashMap.size() );
 		}
 
+		template<typename Ty>
+		void release(Ty)
+		{
+		}
+
+		template<>
+		void release<IUnknown*>(IUnknown* _ptr)
+		{
+			DX_RELEASE(_ptr, 0);
+		}
+
 	private:
 		typedef stl::unordered_map<uint64_t, uint16_t> HashMap;
 		HashMap m_hashMap;
@@ -252,6 +309,7 @@ namespace bgfx
 		{
 			uint64_t m_hash;
 			Ty m_value;
+			uint16_t m_parent;
 		};
 
 		Data m_data[MaxHandleT];

+ 115 - 5
src/renderer_d3d11.cpp

@@ -680,7 +680,7 @@ namespace bgfx { namespace d3d11
 					uint32_t flags = 0
 						| D3D11_CREATE_DEVICE_SINGLETHREADED
 						| D3D11_CREATE_DEVICE_BGRA_SUPPORT
-//						| D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
+						| D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
 						| (BX_ENABLED(BGFX_CONFIG_DEBUG) ? D3D11_CREATE_DEVICE_DEBUG : 0)
 						;
 
@@ -1777,6 +1777,7 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 			m_depthStencilStateCache.invalidate();
 			m_rasterizerStateCache.invalidate();
 			m_samplerStateCache.invalidate();
+			m_srvUavLru.invalidate();
 		}
 
 		void invalidateCompute()
@@ -2394,6 +2395,101 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 			commitTextureStage();
 		}
 
+		ID3D11UnorderedAccessView* getCachedUav(TextureHandle _handle, uint8_t _mip)
+		{
+			bx::HashMurmur2A murmur;
+			murmur.begin();
+			murmur.add(_handle);
+			murmur.add(_mip);
+			murmur.add(0);
+			uint32_t hash = murmur.end();
+
+			IUnknown** ptr = m_srvUavLru.find(hash);
+			ID3D11UnorderedAccessView* uav;
+			if (NULL == ptr)
+			{
+				TextureD3D11& texture = m_textures[_handle.idx];
+
+				D3D11_UNORDERED_ACCESS_VIEW_DESC desc;
+				desc.Format = s_textureFormat[texture.m_textureFormat].m_fmtSrv;
+				switch (texture.m_type)
+				{
+				case TextureD3D11::Texture2D:
+				case TextureD3D11::TextureCube:
+					desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D;
+					desc.Texture2D.MipSlice = _mip;
+					break;
+
+				case TextureD3D11::Texture3D:
+					desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D;
+					desc.Texture3D.MipSlice    = _mip;
+					desc.Texture3D.FirstWSlice = 0;
+					desc.Texture3D.WSize       = 1;
+					break;
+				}
+
+				DX_CHECK(m_device->CreateUnorderedAccessView(texture.m_ptr, &desc, &uav) );
+
+				m_srvUavLru.add(hash, uav, _handle.idx);
+			}
+			else
+			{
+				uav = static_cast<ID3D11UnorderedAccessView*>(*ptr);
+			}
+
+			return uav;
+		}
+
+		ID3D11ShaderResourceView* getCachedSrv(TextureHandle _handle, uint8_t _mip)
+		{
+			bx::HashMurmur2A murmur;
+			murmur.begin();
+			murmur.add(_handle);
+			murmur.add(_mip);
+			murmur.add(0);
+			uint32_t hash = murmur.end();
+
+			IUnknown** ptr = m_srvUavLru.find(hash);
+			ID3D11ShaderResourceView* srv;
+			if (NULL == ptr)
+			{
+				TextureD3D11& texture = m_textures[_handle.idx];
+
+				D3D11_SHADER_RESOURCE_VIEW_DESC desc;
+				desc.Format = s_textureFormat[texture.m_textureFormat].m_fmtSrv;
+				switch (texture.m_type)
+				{
+				case TextureD3D11::Texture2D:
+					desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+					desc.Texture2D.MostDetailedMip = _mip;
+					desc.Texture2D.MipLevels       = 1;
+					break;
+
+				case TextureD3D11::TextureCube:
+					desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
+					desc.TextureCube.MostDetailedMip = _mip;
+					desc.TextureCube.MipLevels       = 1;
+					break;
+
+				case TextureD3D11::Texture3D:
+					desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
+					desc.Texture3D.MostDetailedMip = _mip;
+					desc.Texture3D.MipLevels       = 1;
+					break;
+				}
+
+				DX_CHECK(m_device->CreateShaderResourceView(texture.m_ptr, &desc, &srv) );
+
+				m_srvUavLru.add(hash, srv, _handle.idx);
+			}
+			else
+			{
+				srv = static_cast<ID3D11ShaderResourceView*>(*ptr);
+			}
+
+			return srv;
+		}
+
 		void ovrPostReset()
 		{
 #if BGFX_CONFIG_USE_OVR
@@ -2838,6 +2934,7 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 		StateCacheT<ID3D11InputLayout> m_inputLayoutCache;
 		StateCacheT<ID3D11RasterizerState> m_rasterizerStateCache;
 		StateCacheT<ID3D11SamplerState> m_samplerStateCache;
+		StateCacheLru<IUnknown*, 1024> m_srvUavLru;
 
 		TextVideoMem m_textVideoMem;
 
@@ -3307,7 +3404,7 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 			const bool swizzle    = TextureFormat::BGRA8 == m_textureFormat && 0 != (m_flags&BGFX_TEXTURE_COMPUTE_WRITE);
 
 			BX_TRACE("Texture %3d: %s (requested: %s), %dx%d%s%s%s."
-				, this - s_renderD3D11->m_textures
+				, getHandle()
 				, getName( (TextureFormat::Enum)m_textureFormat)
 				, getName( (TextureFormat::Enum)m_requestedFormat)
 				, textureWidth
@@ -3504,6 +3601,7 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 
 	void TextureD3D11::destroy()
 	{
+		s_renderD3D11->m_srvUavLru.invalidateWithParent(getHandle().idx);
 		DX_RELEASE(m_srv, 0);
 		DX_RELEASE(m_uav, 0);
 		DX_RELEASE(m_ptr, 0);
@@ -3560,6 +3658,12 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 	{
 	}
 
+	TextureHandle TextureD3D11::getHandle() const
+	{
+		TextureHandle handle = { (uint16_t)(this - s_renderD3D11->m_textures) };
+		return handle;
+	}
+
 	void FrameBufferD3D11::create(uint8_t _num, const TextureHandle* _handles)
 	{
 		for (uint32_t ii = 0; ii < BX_COUNTOF(m_rtv); ++ii)
@@ -4074,14 +4178,20 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 							{
 							case Binding::Image:
 								{
-									const TextureD3D11& texture = m_textures[bind.m_idx];
+									TextureD3D11& texture = m_textures[bind.m_idx];
 									if (Access::Read != bind.m_un.m_compute.m_access)
 									{
-										uav[ii] = texture.m_uav;
+										uav[ii] = 0 == bind.m_un.m_compute.m_mip
+											? texture.m_uav
+											: s_renderD3D11->getCachedUav(texture.getHandle(), bind.m_un.m_compute.m_mip)
+											;
 									}
 									else
 									{
-										srv[ii]     = texture.m_srv;
+										srv[ii] = 0 == bind.m_un.m_compute.m_mip
+											? texture.m_srv
+											: s_renderD3D11->getCachedSrv(texture.getHandle(), bind.m_un.m_compute.m_mip)
+											;
 										sampler[ii] = texture.m_sampler;
 									}
 								}

+ 1 - 0
src/renderer_d3d11.h

@@ -284,6 +284,7 @@ namespace bgfx { namespace d3d11
 		void update(uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem);
 		void commit(uint8_t _stage, uint32_t _flags = BGFX_SAMPLER_DEFAULT_FLAGS);
 		void resolve();
+		TextureHandle getHandle() const;
 
 		union
 		{

+ 3 - 2
src/renderer_d3d12.cpp

@@ -2589,7 +2589,8 @@ data.NumQualityLevels = 0;
 			{
 			default:
 			case D3D12_UAV_DIMENSION_TEXTURE2D:
-				uavd->Texture2D.MipSlice = _mip;
+				uavd->Texture2D.MipSlice   = _mip;
+				uavd->Texture2D.PlaneSlice = 0;
 				break;
 
 			case D3D12_UAV_DIMENSION_TEXTURE3D:
@@ -4111,7 +4112,7 @@ data.NumQualityLevels = 0;
 
 								m_commandList->SetGraphicsRootDescriptorTable(Rdt::SRV, srvHandle[0]);
 
-								bindLru.add(bindHash, srvHandle[0]);
+								bindLru.add(bindHash, srvHandle[0], 0);
 							}
 						}
 						else