瀏覽代碼

RenderTexturePool
Fixed DX11 and OpenGL so they can properly create windows without depth buffers

Marko Pintera 10 年之前
父節點
當前提交
58787ab8d2

+ 22 - 9
BansheeD3D11RenderSystem/Source/BsD3D11RenderWindow.cpp

@@ -565,8 +565,16 @@ namespace BansheeEngine
 		}
 		else if(name == "DSV")
 		{
-			D3D11TextureView* d3d11TextureView = static_cast<D3D11TextureView*>(mDepthStencilView.get());
-			*static_cast<ID3D11DepthStencilView**>(pData) = d3d11TextureView->getDSV();
+			if (mDepthStencilView != nullptr)
+			{
+				D3D11TextureView* d3d11TextureView = static_cast<D3D11TextureView*>(mDepthStencilView.get());
+				*static_cast<ID3D11DepthStencilView**>(pData) = d3d11TextureView->getDSV();
+			}
+			else
+			{
+				*static_cast<ID3D11DepthStencilView**>(pData) = nullptr;
+			}
+
 			return;
 		}
 
@@ -750,7 +758,7 @@ namespace BansheeEngine
 		ZeroMemory( &RTVDesc, sizeof(RTVDesc) );
 
 		RTVDesc.Format = BBDesc.Format;
-		RTVDesc.ViewDimension = getProperties().getMultisampleCount() ? D3D11_RTV_DIMENSION_TEXTURE2DMS : D3D11_RTV_DIMENSION_TEXTURE2D;
+		RTVDesc.ViewDimension = getProperties().getMultisampleCount() > 1 ? D3D11_RTV_DIMENSION_TEXTURE2DMS : D3D11_RTV_DIMENSION_TEXTURE2D;
 		RTVDesc.Texture2D.MipSlice = 0;
 		hr = mDevice.getD3D11Device()->CreateRenderTargetView(mBackBuffer, &RTVDesc, &mRenderTargetView);
 
@@ -760,17 +768,22 @@ namespace BansheeEngine
 			BS_EXCEPT(RenderingAPIException, "Unable to create rendertagert view\nError Description:" + errorDescription);
 		}
 
-		mDepthStencilBuffer = TextureCoreManager::instance().createTexture(TEX_TYPE_2D, 
-			BBDesc.Width, BBDesc.Height, 0, 0, PF_D24S8, TU_DEPTHSTENCIL, false, 
-			getProperties().getMultisampleCount());
-
-		if(mDepthStencilView != nullptr)
+		if (mDepthStencilView != nullptr)
 		{
 			TextureCore::releaseView(mDepthStencilView);
 			mDepthStencilView = nullptr;
 		}
 
-		mDepthStencilView = TextureCore::requestView(mDepthStencilBuffer, 0, 1, 0, 1, GVU_DEPTHSTENCIL);
+		if (mDesc.depthBuffer)
+		{
+			mDepthStencilBuffer = TextureCoreManager::instance().createTexture(TEX_TYPE_2D,
+				BBDesc.Width, BBDesc.Height, 0, 0, PF_D24S8, TU_DEPTHSTENCIL, false,
+				getProperties().getMultisampleCount());
+
+			mDepthStencilView = TextureCore::requestView(mDepthStencilBuffer, 0, 1, 0, 1, GVU_DEPTHSTENCIL);
+		}
+		else
+			mDepthStencilBuffer = nullptr;
 	}
 
 	void D3D11RenderWindowCore::destroySizeDependedD3DResources()

+ 9 - 8
BansheeGLRenderSystem/Include/BsWin32GLSupport.h

@@ -18,32 +18,32 @@ namespace BansheeEngine
 		/**
 		 * @copydoc	GLSupport::newWindow
 		 */
-		virtual RenderWindowPtr newWindow(RENDER_WINDOW_DESC& desc, UINT32 windowId, RenderWindowPtr parentWindow);
+		virtual RenderWindowPtr newWindow(RENDER_WINDOW_DESC& desc, UINT32 windowId, RenderWindowPtr parentWindow) override;
 
 		/**
 		 * @copydoc	GLSupport::newWindowCore
 		 */
-		virtual SPtr<RenderWindowCore> newWindowCore(RENDER_WINDOW_DESC& desc, UINT32 windowId);
+		virtual SPtr<RenderWindowCore> newWindowCore(RENDER_WINDOW_DESC& desc, UINT32 windowId) override;
 
 		/**
 		 * @copydoc	GLSupport::start
 		 */
-		void start();
+		void start() override;
 
 		/**
 		 * @copydoc	GLSupport::stop
 		 */
-		void stop();
+		void stop() override;
 
 		/**
 		 * @copydoc	GLSupport::getProcAddress
 		 */
-		void* getProcAddress(const String& procname);
+		void* getProcAddress(const String& procname) override;
 
 		/**
 		 * @copydoc	GLSupport::initializeExtensions
 		 */
-		virtual void initializeExtensions();
+		virtual void initializeExtensions() override;
 		
 		/**
 		 * @brief	Creates a new OpenGL context.
@@ -63,15 +63,16 @@ namespace BansheeEngine
 		 * @param	colorDepth	Wanted color depth of the pixel format, in bits.
 		 * @param	multisample	Amount of multisampling wanted, if any.
 		 * @param	hwGamma		Should the format support automatic gamma conversion on write/read.
+		 * @param	depth		Should the pixel format contain the depth/stencil buffer.
 		 *
 		 * @returns	True if a pixel format was successfully set.
 		 */
-		bool selectPixelFormat(HDC hdc, int colorDepth, int multisample, bool hwGamma);
+		bool selectPixelFormat(HDC hdc, int colorDepth, int multisample, bool hwGamma, bool depthStencil);
 
 		/**
 		 * @copydoc	GLSupport::getVideoModeInfo
 		 */
-		VideoModeInfoPtr getVideoModeInfo() const;
+		VideoModeInfoPtr getVideoModeInfo() const override;
 
 	private:
 		/**

+ 11 - 8
BansheeGLRenderSystem/Source/BsWin32GLSupport.cpp

@@ -231,15 +231,14 @@ namespace BansheeEngine
 				int formats[256];
 				unsigned int count;
                 WGLEW_GET_FUN(__wglewChoosePixelFormatARB) = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
+				PFNWGLGETPIXELFORMATATTRIBIVARBPROC _wglGetPixelFormatAttribivARB = 
+					(PFNWGLGETPIXELFORMATATTRIBIVARBPROC)wglGetProcAddress("wglGetPixelFormatAttribivARB");
                 if (WGLEW_GET_FUN(__wglewChoosePixelFormatARB)(hdc, iattr, 0, 256, formats, &count))
                 {
                     // determine what multisampling levels are offered
                     int query = WGL_SAMPLES_ARB, samples;
                     for (unsigned int i = 0; i < count; ++i)
                     {
-                        PFNWGLGETPIXELFORMATATTRIBIVARBPROC _wglGetPixelFormatAttribivARB =
-                            (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)
-                            wglGetProcAddress("wglGetPixelFormatAttribivARB");
                         if (_wglGetPixelFormatAttribivARB(hdc, formats[i], 0, 1, &query, &samples))
                         {
                             mMultisampleLevels.push_back(samples);
@@ -263,7 +262,7 @@ namespace BansheeEngine
 		return DefWindowProc(hwnd, umsg, wp, lp);
 	}
 
-	bool Win32GLSupport::selectPixelFormat(HDC hdc, int colorDepth, int multisample, bool hwGamma)
+	bool Win32GLSupport::selectPixelFormat(HDC hdc, int colorDepth, int multisample, bool hwGamma, bool depthStencil)
 	{
 		PIXELFORMATDESCRIPTOR pfd;
 		memset(&pfd, 0, sizeof(pfd));
@@ -273,8 +272,12 @@ namespace BansheeEngine
 		pfd.iPixelType = PFD_TYPE_RGBA;
 		pfd.cColorBits = (colorDepth > 16)? 24 : colorDepth;
 		pfd.cAlphaBits = (colorDepth > 16)? 8 : 0;
-		pfd.cDepthBits = 24;
-		pfd.cStencilBits = 8;
+
+		if (depthStencil)
+		{
+			pfd.cDepthBits = 24;
+			pfd.cStencilBits = 8;
+		}
 
 		int format = 0;
 
@@ -297,8 +300,8 @@ namespace BansheeEngine
 			attribList.push_back(WGL_ACCELERATION_ARB); attribList.push_back(WGL_FULL_ACCELERATION_ARB);
 			attribList.push_back(WGL_COLOR_BITS_ARB); attribList.push_back(pfd.cColorBits);
 			attribList.push_back(WGL_ALPHA_BITS_ARB); attribList.push_back(pfd.cAlphaBits);
-			attribList.push_back(WGL_DEPTH_BITS_ARB); attribList.push_back(24);
-			attribList.push_back(WGL_STENCIL_BITS_ARB); attribList.push_back(8);
+			attribList.push_back(WGL_DEPTH_BITS_ARB); attribList.push_back(pfd.cDepthBits);
+			attribList.push_back(WGL_STENCIL_BITS_ARB); attribList.push_back(pfd.cStencilBits);
 			attribList.push_back(WGL_SAMPLES_ARB); attribList.push_back(multisample);
 			if (useHwGamma && checkExtension("WGL_EXT_framebuffer_sRGB"))
 			{

+ 4 - 4
BansheeGLRenderSystem/Source/BsWin32Window.cpp

@@ -320,14 +320,14 @@ namespace BansheeEngine
 		{
 			int testMultisample = props.mMultisampleCount;
 			bool testHwGamma = mDesc.gamma;
-			bool formatOk = mGLSupport.selectPixelFormat(mHDC, props.mColorDepth, testMultisample, testHwGamma);
+			bool formatOk = mGLSupport.selectPixelFormat(mHDC, props.mColorDepth, testMultisample, testHwGamma, mDesc.depthBuffer);
 			if (!formatOk)
 			{
 				if (props.mMultisampleCount > 0)
 				{
 					// Try without multisampling
 					testMultisample = 0;
-					formatOk = mGLSupport.selectPixelFormat(mHDC, props.mColorDepth, testMultisample, testHwGamma);
+					formatOk = mGLSupport.selectPixelFormat(mHDC, props.mColorDepth, testMultisample, testHwGamma, mDesc.depthBuffer);
 				}
 
 				if (!formatOk && mDesc.gamma)
@@ -335,7 +335,7 @@ namespace BansheeEngine
 					// Try without sRGB
 					testHwGamma = false;
 					testMultisample = props.mMultisampleCount;
-					formatOk = mGLSupport.selectPixelFormat(mHDC, props.mColorDepth, testMultisample, testHwGamma);
+					formatOk = mGLSupport.selectPixelFormat(mHDC, props.mColorDepth, testMultisample, testHwGamma, mDesc.depthBuffer);
 				}
 
 				if (!formatOk && mDesc.gamma && (props.mMultisampleCount > 0))
@@ -343,7 +343,7 @@ namespace BansheeEngine
 					// Try without both
 					testHwGamma = false;
 					testMultisample = 0;
-					formatOk = mGLSupport.selectPixelFormat(mHDC, props.mColorDepth, testMultisample, testHwGamma);
+					formatOk = mGLSupport.selectPixelFormat(mHDC, props.mColorDepth, testMultisample, testHwGamma, mDesc.depthBuffer);
 				}
 
 				if (!formatOk)

+ 4 - 2
BansheeRenderer/BansheeRenderer.vcxproj

@@ -239,16 +239,18 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
-    <ClInclude Include="Include\BsBansheeLitTexRenderableController.h" />
+    <ClInclude Include="Include\BsLitTexRenderableController.h" />
     <ClInclude Include="Include\BsBansheeRenderer.h" />
     <ClInclude Include="Include\BsBansheeRendererFactory.h" />
     <ClInclude Include="Include\BsBansheeRendererPrerequisites.h" />
+    <ClInclude Include="Include\BsRenderTexturePool.h" />
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="Source\BsBansheeLitTexRenderableController.cpp" />
+    <ClCompile Include="Source\BsLitTexRenderableController.cpp" />
     <ClCompile Include="Source\BsBansheeRenderer.cpp" />
     <ClCompile Include="Source\BsBansheeRendererFactory.cpp" />
     <ClCompile Include="Source\BsBansheeRendererPlugin.cpp" />
+    <ClCompile Include="Source\BsRenderTexturePool.cpp" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">

+ 8 - 2
BansheeRenderer/BansheeRenderer.vcxproj.filters

@@ -24,7 +24,10 @@
     <ClInclude Include="Include\BsBansheeRendererPrerequisites.h">
       <Filter>Header Files</Filter>
     </ClInclude>
-    <ClInclude Include="Include\BsBansheeLitTexRenderableController.h">
+    <ClInclude Include="Include\BsLitTexRenderableController.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsRenderTexturePool.h">
       <Filter>Header Files</Filter>
     </ClInclude>
   </ItemGroup>
@@ -38,7 +41,10 @@
     <ClCompile Include="Source\BsBansheeRendererPlugin.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="Source\BsBansheeLitTexRenderableController.cpp">
+    <ClCompile Include="Source\BsLitTexRenderableController.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsRenderTexturePool.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
   </ItemGroup>

+ 0 - 0
BansheeRenderer/Include/BsBansheeLitTexRenderableController.h → BansheeRenderer/Include/BsLitTexRenderableController.h


+ 42 - 0
BansheeRenderer/Include/BsRenderTexturePool.h

@@ -0,0 +1,42 @@
+#pragma once
+
+#include "BsBansheeRendererPrerequisites.h"
+#include "BsPixelUtil.h"
+
+namespace BansheeEngine
+{
+	class RenderTexturePool;
+
+	struct PooledRenderTexture
+	{
+		PooledRenderTexture(RenderTexturePool* pool);
+		~PooledRenderTexture();
+
+		SPtr<RenderTextureCore> texture;
+
+	private:
+		friend class RenderTexturePool;
+
+		RenderTexturePool* mPool;
+		bool mIsFree;
+	};
+
+	class RenderTexturePool
+	{
+	public:
+		~RenderTexturePool();
+
+		SPtr<PooledRenderTexture> get(PixelFormat format, UINT32 width, UINT32 height, bool hwGamma = false, UINT32 samples = 0);
+		void free(const SPtr<PooledRenderTexture>& texture);
+
+	private:
+		friend struct PooledRenderTexture;
+
+		void _registerTexture(const SPtr<PooledRenderTexture>& texture);
+		void _unregisterTexture(PooledRenderTexture* texture);
+
+		bool matches(const SPtr<TextureCore>& texture, PixelFormat format, UINT32 width, UINT32 height, bool hwGamma, UINT32 samples);
+
+		Map<PooledRenderTexture*, SPtr<PooledRenderTexture>> mTextures;
+	};
+}

+ 1 - 1
BansheeRenderer/Source/BsBansheeRenderer.cpp

@@ -24,7 +24,7 @@
 #include "BsHardwareBufferManager.h"
 #include "BsGpuParamBlockBuffer.h"
 #include "BsShader.h"
-#include "BsBansheeLitTexRenderableController.h"
+#include "BsLitTexRenderableController.h"
 #include "BsTime.h"
 #include "BsRenderableElement.h"
 #include "BsFrameAlloc.h"

+ 1 - 1
BansheeRenderer/Source/BsBansheeLitTexRenderableController.cpp → BansheeRenderer/Source/BsLitTexRenderableController.cpp

@@ -1,4 +1,4 @@
-#include "BsBansheeLitTexRenderableController.h"
+#include "BsLitTexRenderableController.h"
 #include "BsShader.h"
 #include "BsGpuParams.h"
 #include "BsBansheeRenderer.h"

+ 92 - 0
BansheeRenderer/Source/BsRenderTexturePool.cpp

@@ -0,0 +1,92 @@
+#include "BsRenderTexturePool.h"
+#include "BsRenderTexture.h"
+#include "BsTexture.h"
+#include "BsTextureManager.h"
+
+namespace BansheeEngine
+{
+	PooledRenderTexture::PooledRenderTexture(RenderTexturePool* pool)
+		:mIsFree(false), mPool(pool)
+	{ }
+
+	PooledRenderTexture::~PooledRenderTexture()
+	{
+		if (mPool != nullptr)
+			mPool->_unregisterTexture(this);
+	}
+
+	RenderTexturePool::~RenderTexturePool()
+	{
+		for (auto& texture : mTextures)
+			texture.second->mPool = nullptr;
+	}
+
+	SPtr<PooledRenderTexture> RenderTexturePool::get(PixelFormat format, UINT32 width, UINT32 height, bool hwGamma, UINT32 samples)
+	{
+		bool depth = PixelUtil::isDepth(format);
+
+		for (auto& texturePair : mTextures)
+		{
+			SPtr<PooledRenderTexture> textureData = texturePair.second;
+
+			if (!textureData->mIsFree)
+				continue;
+
+			SPtr<TextureCore> textureCore;
+			if (!depth)
+				textureCore = textureData->texture->getBindableColorTexture(); 
+			else
+				textureCore = textureData->texture->getBindableDepthStencilTexture();
+
+			if (textureCore == nullptr)
+				continue;
+
+			if (matches(textureCore, format, width, height, hwGamma, samples))
+			{
+				textureData->mIsFree = false;
+				return textureData;
+			}
+		}
+
+		SPtr<PooledRenderTexture> newTextureData = bs_shared_ptr<PooledRenderTexture>(this);
+		_registerTexture(newTextureData);
+
+		RENDER_SURFACE_CORE_DESC surfaceDesc;
+		surfaceDesc.texture = TextureCoreManager::instance().createTexture(TEX_TYPE_2D, width, height, 1, 0, 
+			format, depth ? TU_DEPTHSTENCIL : TU_RENDERTARGET, hwGamma, samples);
+		surfaceDesc.face = 0;
+		surfaceDesc.mipLevel = 0;
+
+		RENDER_TEXTURE_CORE_DESC desc;
+		if (!depth)
+			desc.colorSurface = surfaceDesc;
+		else
+			desc.depthStencilSurface = surfaceDesc;
+
+		newTextureData->texture = TextureCoreManager::instance().createRenderTexture(desc);
+		return newTextureData;
+	}
+
+	void RenderTexturePool::free(const SPtr<PooledRenderTexture>& texture)
+	{
+		auto iterFind = mTextures.find(texture.get());
+		iterFind->second->mIsFree = true;
+	}
+
+	bool RenderTexturePool::matches(const SPtr<TextureCore>& texture, PixelFormat format, UINT32 width, UINT32 height, bool hwGamma, UINT32 samples)
+	{
+		const TextureProperties& texProps = texture->getProperties();
+		return texProps.getFormat() == format && texProps.getWidth() == width && texProps.getHeight() == height &&
+			texProps.isHardwareGammaEnabled() == hwGamma && texProps.getMultisampleCount() == samples;
+	}
+
+	void RenderTexturePool::_registerTexture(const SPtr<PooledRenderTexture>& texture)
+	{
+		mTextures.insert(std::make_pair(texture.get(), texture));
+	}
+
+	void RenderTexturePool::_unregisterTexture(PooledRenderTexture* texture)
+	{
+		mTextures.erase(texture);
+	}
+}

+ 42 - 12
TODOExperimentation.txt

@@ -1,11 +1,21 @@
 -------------------------
 Study shadow rendering implementations
 
+Test all APIs with new changes regarding depth buffer creation on windows
+Document RenderTargetPool and potentially move it outside of BansheeRenderer
+ - Quantize buffer sizes so they're divideable by 8
 Implement light added/removed/updated in BansheeRenderer
 Load up and set up a test-bed with Ribek's scene
 
 Need cone to use when rendering spot light
 
+Renderer needs options:
+ - Sample count
+ - sRGB output
+ - HDR rendering
+ - Texture filtering + anisotropic amount
+ - These need to properly recreate gbuffer and other objects when they change
+
 Create a basic GBuffer - albedo, normal, depth
  - Using HDR formats where needed
  - Will need some kind of a pool that handles multiple viewports (each with its own gbuffer) and viewport resizing
@@ -13,18 +23,38 @@ Create a basic GBuffer - albedo, normal, depth
 Implement deferred rendering (just basic lambert shading for now, only point light)
  - Then convert to tiled rendering (will likely need normal deferred too as a fallback - and to be able to toggle and compare)
 
-Create SceneRenderTargets class:
- - Allocate(Camera - call at start rendering with camera - Allocates gbuffer (for now, more later probably)
-  - Internally calls RenderTargetPool that returns available cached render targets
-   - Actually this probably isn't the best idea. It might be better to store gbuffer targets with CameraHandlerCore
-     so when it resizes or gets destroyed we can immediately change/destroy them. With a pool I cannot tell when to destroy the gbuffer.
-	  - ALTHOUGH if two cameras have same viewport size them I shouldn't allocate two sets of targets. So maybe a combination of the two.
- - Free(Camera)
- - BeginSceneRendering - Sets the color target and gbuffer targets for rendering
- - ResolveSceneRendering (also ends scene rendering) - possibly resolves MSAA into normal buffer
-   - Allow SceneRenderTargets to have a resolve target. Avoid resolve if they're equal
-
-How to handle MSAA in deferred? - Should be trivial with MSAA textures. I do only plan to support SM4 and higher anyway (maybe even SM5?)
+How will cameras interact with the renderer? The cameras currently available shouldn't have depth buffers
+ - Need to modify RenderWindow so it doesn't create depth buffers
+  - Find all places where I create windows and modify this
+  - Modify render target creation in SceneWindow
+ - What happens when a user creates a camera with a depth buffer?
+   - Print out a warning and ignore it?
+   - Or resolve the gbuffer into it? Probably this, as I want to be able to read the depth buffer from script code if needed
+     - This still isn't perfect as I'd have duplicate buffers when using non-MSAA buffer that require no resolve
+
+Render:
+ - Iterate over all cameras and create their render queues, record whether a camera requires a gbuffer or not
+    - How will "render()" callback signify whether they want a gbuffer or something else? 
+     - Assume they need it? Probably - although it would be nice to be able to customize the render targets
+	   of the render() calls. But I should probably think about that if it ever comes up, and implement it simply for now.
+	 - Potentially restrict cameras to only non-multisampled RGBA8 targets. Then later we can add a special
+	   mechanism for reading the depth buffer from sim thread(as well as reading other gbuffers)
+	    - But I don't think this should be needed (It will probably be enough to signal to the rendering
+		  thread to bind any one of those buffers, as we're only likely to use them from shaders. And shaders
+		  can then even render them out to an outside target if needed.)
+		- ALTHOUGH I do want to be able to set up custom render targets for the camera. So that custom scripts
+		  and shaders can be executed as needed, possibly outputting multiple targets of various formats.
+ - Sort cameras based on render targets and priority as we do now, additionally sort by whether they require gbuffer or not
+ - Add new class RendererTargets
+   - beginSceneRendering
+   - endSceneRendering
+   - resolve(RenderTarget)
+  - Add new class RenderTargetPool
+   - RTHandle handle = find(format, width, height, depth)
+   - RTHandle keeps a shared ptr so that all cameras that use it can hold (once it runs out the render targets are freed)
+
+ - Separate GUI rendering into a separate part to be rendered after gbuffer is resolved?
+
 Will likely need an easy way to determine supported feature set (likely just depending on shader model)
 Consider encapsulating shaders together with methods for setting their parameters (and possibly retrieving output)
  - So that external code doesn't need to know about its internal and do less work