Browse Source

Added MRT support.

bkaradzic 12 years ago
parent
commit
877621105d

+ 0 - 2
README.md

@@ -309,11 +309,9 @@ Converts Wavefront .obj mesh file to format optimal for using with bgfx.
 Todo
 Todo
 ----
 ----
 
 
- - Multiple render targets.
  - BlendFuncSeparate and BlendEquationSeparate.
  - BlendFuncSeparate and BlendEquationSeparate.
  - Blit between textures.
  - Blit between textures.
  - Occlusion queries.
  - Occlusion queries.
- - DX11: MSAA.
  - Fullscreen mode.
  - Fullscreen mode.
  - ETC2, PVRTC1/2 decoding fallback for targets that don't support it natively.
  - ETC2, PVRTC1/2 decoding fallback for targets that don't support it natively.
 
 

+ 52 - 38
examples/09-hdr/hdr.cpp

@@ -476,20 +476,26 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 	Mesh mesh;
 	Mesh mesh;
 	mesh.load("meshes/bunny.bin");
 	mesh.load("meshes/bunny.bin");
 
 
-	bgfx::RenderTargetHandle rt = bgfx::createRenderTarget(width, height, BGFX_RENDER_TARGET_COLOR_RGBA8|BGFX_RENDER_TARGET_DEPTH_D16);
+	bgfx::FrameBufferHandle fbh;
+	bgfx::TextureHandle fbtextures[] =
+	{
+		bgfx::createTexture2D(width, height, 1, bgfx::TextureFormat::BGRA8, BGFX_TEXTURE_RT),
+		bgfx::createTexture2D(width, height, 1, bgfx::TextureFormat::D16, BGFX_TEXTURE_RT_BUFFER_ONLY),
+	};
+	fbh = bgfx::createFrameBuffer(BX_COUNTOF(fbtextures), fbtextures, true);
 
 
-	bgfx::RenderTargetHandle lum[5];
-	lum[0] = bgfx::createRenderTarget(128, 128, BGFX_RENDER_TARGET_COLOR_RGBA8);
-	lum[1] = bgfx::createRenderTarget( 64,  64, BGFX_RENDER_TARGET_COLOR_RGBA8);
-	lum[2] = bgfx::createRenderTarget( 16,  16, BGFX_RENDER_TARGET_COLOR_RGBA8);
-	lum[3] = bgfx::createRenderTarget(  4,   4, BGFX_RENDER_TARGET_COLOR_RGBA8);
-	lum[4] = bgfx::createRenderTarget(  1,   1, BGFX_RENDER_TARGET_COLOR_RGBA8);
+	bgfx::FrameBufferHandle lum[5];
+	lum[0] = bgfx::createFrameBuffer(128, 128, bgfx::TextureFormat::BGRA8);
+	lum[1] = bgfx::createFrameBuffer( 64,  64, bgfx::TextureFormat::BGRA8);
+	lum[2] = bgfx::createFrameBuffer( 16,  16, bgfx::TextureFormat::BGRA8);
+	lum[3] = bgfx::createFrameBuffer(  4,   4, bgfx::TextureFormat::BGRA8);
+	lum[4] = bgfx::createFrameBuffer(  1,   1, bgfx::TextureFormat::BGRA8);
 
 
-	bgfx::RenderTargetHandle bright;
-	bright = bgfx::createRenderTarget(width/2, height/2, BGFX_RENDER_TARGET_COLOR_RGBA8);
+	bgfx::FrameBufferHandle bright;
+	bright = bgfx::createFrameBuffer(width/2, height/2, bgfx::TextureFormat::BGRA8);
 
 
-	bgfx::RenderTargetHandle blur;
-	blur = bgfx::createRenderTarget(width/8, height/8, BGFX_RENDER_TARGET_COLOR_RGBA8);
+	bgfx::FrameBufferHandle blur;
+	blur = bgfx::createFrameBuffer(width/8, height/8, bgfx::TextureFormat::BGRA8);
 
 
 	FILE* file = fopen("font/droidsans.ttf", "rb");
 	FILE* file = fopen("font/droidsans.ttf", "rb");
 	uint32_t size = (uint32_t)fsize(file);
 	uint32_t size = (uint32_t)fsize(file);
@@ -511,6 +517,7 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 
 
 	uint32_t oldWidth = 0;
 	uint32_t oldWidth = 0;
 	uint32_t oldHeight = 0;
 	uint32_t oldHeight = 0;
+	uint32_t oldReset = reset;
 
 
 	entry::MouseState mouseState;
 	entry::MouseState mouseState;
 
 
@@ -518,19 +525,27 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 
 
 	while (!entry::processEvents(width, height, debug, reset, &mouseState) )
 	while (!entry::processEvents(width, height, debug, reset, &mouseState) )
 	{
 	{
-		if (oldWidth != width
-		||  oldHeight != height)
+		if (oldWidth  != width
+		||  oldHeight != height
+		||  oldReset  != reset)
 		{
 		{
 			// Recreate variable size render targets when resolution changes.
 			// Recreate variable size render targets when resolution changes.
 			oldWidth = width;
 			oldWidth = width;
 			oldHeight = height;
 			oldHeight = height;
-			bgfx::destroyRenderTarget(rt);
-			bgfx::destroyRenderTarget(bright);
-			bgfx::destroyRenderTarget(blur);
+			oldReset = reset;
+
+			uint32_t msaa = (reset&BGFX_RESET_MSAA_MASK)>>BGFX_RESET_MSAA_SHIFT;
+
+			bgfx::destroyFrameBuffer(fbh);
+			bgfx::destroyFrameBuffer(bright);
+			bgfx::destroyFrameBuffer(blur);
 
 
-			rt = bgfx::createRenderTarget(width, height, BGFX_RENDER_TARGET_COLOR_RGBA8|BGFX_RENDER_TARGET_DEPTH_D16);
-			bright = bgfx::createRenderTarget(width/2, height/2, BGFX_RENDER_TARGET_COLOR_RGBA8);
-			blur = bgfx::createRenderTarget(width/8, height/8, BGFX_RENDER_TARGET_COLOR_RGBA8);
+			fbtextures[0] = bgfx::createTexture2D(width, height, 1, bgfx::TextureFormat::BGRA8, ( (msaa+1)<<BGFX_TEXTURE_RT_MSAA_SHIFT) );
+			fbtextures[1] = bgfx::createTexture2D(width, height, 1, bgfx::TextureFormat::D16, 0|( (msaa+1)<<BGFX_TEXTURE_RT_MSAA_SHIFT) );
+			fbh = bgfx::createFrameBuffer(BX_COUNTOF(fbtextures), fbtextures, true);
+
+			bright = bgfx::createFrameBuffer(width/2, height/2, bgfx::TextureFormat::BGRA8);
+			blur = bgfx::createFrameBuffer(width/8, height/8, bgfx::TextureFormat::BGRA8);
 		}
 		}
 
 
 		imguiBeginFrame(mouseState.m_mx
 		imguiBeginFrame(mouseState.m_mx
@@ -578,28 +593,28 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 
 
 		// Set views.
 		// Set views.
 		bgfx::setViewRectMask(0x1f, 0, 0, width, height);
 		bgfx::setViewRectMask(0x1f, 0, 0, width, height);
-		bgfx::setViewRenderTargetMask(0x3, rt);
+		bgfx::setViewFrameBufferMask(0x3, fbh);
 
 
 		bgfx::setViewRect(2, 0, 0, 128, 128);
 		bgfx::setViewRect(2, 0, 0, 128, 128);
-		bgfx::setViewRenderTarget(2, lum[0]);
+		bgfx::setViewFrameBuffer(2, lum[0]);
 
 
 		bgfx::setViewRect(3, 0, 0, 64, 64);
 		bgfx::setViewRect(3, 0, 0, 64, 64);
-		bgfx::setViewRenderTarget(3, lum[1]);
+		bgfx::setViewFrameBuffer(3, lum[1]);
 
 
 		bgfx::setViewRect(4, 0, 0, 16, 16);
 		bgfx::setViewRect(4, 0, 0, 16, 16);
-		bgfx::setViewRenderTarget(4, lum[2]);
+		bgfx::setViewFrameBuffer(4, lum[2]);
 
 
 		bgfx::setViewRect(5, 0, 0, 4, 4);
 		bgfx::setViewRect(5, 0, 0, 4, 4);
-		bgfx::setViewRenderTarget(5, lum[3]);
+		bgfx::setViewFrameBuffer(5, lum[3]);
 
 
 		bgfx::setViewRect(6, 0, 0, 1, 1);
 		bgfx::setViewRect(6, 0, 0, 1, 1);
-		bgfx::setViewRenderTarget(6, lum[4]);
+		bgfx::setViewFrameBuffer(6, lum[4]);
 
 
 		bgfx::setViewRect(7, 0, 0, width/2, height/2);
 		bgfx::setViewRect(7, 0, 0, width/2, height/2);
-		bgfx::setViewRenderTarget(7, bright);
+		bgfx::setViewFrameBuffer(7, bright);
 
 
 		bgfx::setViewRect(8, 0, 0, width/8, height/8);
 		bgfx::setViewRect(8, 0, 0, width/8, height/8);
-		bgfx::setViewRenderTarget(8, blur);
+		bgfx::setViewFrameBuffer(8, blur);
 
 
 		bgfx::setViewRect(9, 0, 0, width, height);
 		bgfx::setViewRect(9, 0, 0, width, height);
 
 
@@ -657,7 +672,7 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 
 
 		// Calculate luminance.
 		// Calculate luminance.
 		setOffsets2x2Lum(u_offset, 128, 128);
 		setOffsets2x2Lum(u_offset, 128, 128);
-		bgfx::setTexture(0, u_texColor, rt);
+		bgfx::setTexture(0, u_texColor, fbtextures[0]);
 		bgfx::setProgram(lumProgram);
 		bgfx::setProgram(lumProgram);
 		bgfx::setState(BGFX_STATE_RGB_WRITE|BGFX_STATE_ALPHA_WRITE);
 		bgfx::setState(BGFX_STATE_RGB_WRITE|BGFX_STATE_ALPHA_WRITE);
 		screenSpaceQuad(128.0f, 128.0f, s_flipV);
 		screenSpaceQuad(128.0f, 128.0f, s_flipV);
@@ -700,7 +715,7 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 
 
 		// Bright pass treshold is tonemap[3].
 		// Bright pass treshold is tonemap[3].
 		setOffsets4x4Lum(u_offset, width/2, height/2);
 		setOffsets4x4Lum(u_offset, width/2, height/2);
-		bgfx::setTexture(0, u_texColor, rt);
+		bgfx::setTexture(0, u_texColor, fbtextures[0]);
 		bgfx::setTexture(1, u_texLum, lum[4]);
 		bgfx::setTexture(1, u_texLum, lum[4]);
 		bgfx::setProgram(brightProgram);
 		bgfx::setProgram(brightProgram);
 		bgfx::setState(BGFX_STATE_RGB_WRITE|BGFX_STATE_ALPHA_WRITE);
 		bgfx::setState(BGFX_STATE_RGB_WRITE|BGFX_STATE_ALPHA_WRITE);
@@ -715,7 +730,7 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 		bgfx::submit(8);
 		bgfx::submit(8);
 
 
 		// Blur bright pass horizontally, do tonemaping and combine.
 		// Blur bright pass horizontally, do tonemaping and combine.
-		bgfx::setTexture(0, u_texColor, rt);
+		bgfx::setTexture(0, u_texColor, fbtextures[0]);
 		bgfx::setTexture(1, u_texLum, lum[4]);
 		bgfx::setTexture(1, u_texLum, lum[4]);
 		bgfx::setTexture(2, u_texBlur, blur);
 		bgfx::setTexture(2, u_texBlur, blur);
 		bgfx::setProgram(tonemapProgram);
 		bgfx::setProgram(tonemapProgram);
@@ -733,14 +748,13 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 	// Cleanup.
 	// Cleanup.
 	mesh.unload();
 	mesh.unload();
 
 
-	bgfx::destroyRenderTarget(lum[0]);
-	bgfx::destroyRenderTarget(lum[1]);
-	bgfx::destroyRenderTarget(lum[2]);
-	bgfx::destroyRenderTarget(lum[3]);
-	bgfx::destroyRenderTarget(lum[4]);
-	bgfx::destroyRenderTarget(bright);
-	bgfx::destroyRenderTarget(blur);
-	bgfx::destroyRenderTarget(rt);
+	for (uint32_t ii = 0; ii < BX_COUNTOF(lum); ++ii)
+	{
+		bgfx::destroyFrameBuffer(lum[ii]);
+	}
+	bgfx::destroyFrameBuffer(bright);
+	bgfx::destroyFrameBuffer(blur);
+	bgfx::destroyFrameBuffer(fbh);
 
 
 	bgfx::destroyProgram(meshProgram);
 	bgfx::destroyProgram(meshProgram);
 	bgfx::destroyProgram(skyProgram);
 	bgfx::destroyProgram(skyProgram);

+ 17 - 10
examples/14-shadowvolumes/shadowvolumes.cpp

@@ -104,7 +104,7 @@ static uint32_t s_viewMask = 0;
 
 
 static bgfx::UniformHandle u_texColor;
 static bgfx::UniformHandle u_texColor;
 static bgfx::UniformHandle u_texStencil;
 static bgfx::UniformHandle u_texStencil;
-static bgfx::RenderTargetHandle s_stencilRt;
+static bgfx::FrameBufferHandle s_stencilFb;
 
 
 inline uint32_t uint32_max(uint32_t _a, uint32_t _b)
 inline uint32_t uint32_max(uint32_t _a, uint32_t _b)
 {
 {
@@ -1256,7 +1256,7 @@ struct Model
 			{
 			{
 				bgfx::setTexture(0, u_texColor, m_texture);
 				bgfx::setTexture(0, u_texColor, m_texture);
 			}
 			}
-			bgfx::setTexture(7, u_texStencil, s_stencilRt);
+			bgfx::setTexture(7, u_texStencil, s_stencilFb);
 
 
 			// Apply render state
 			// Apply render state
 			::setRenderState(_renderState);
 			::setRenderState(_renderState);
@@ -1994,7 +1994,12 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 	mem = loadTexture("fieldstone-rgba.dds");
 	mem = loadTexture("fieldstone-rgba.dds");
 	bgfx::TextureHandle fieldstoneTex = bgfx::createTexture(mem);
 	bgfx::TextureHandle fieldstoneTex = bgfx::createTexture(mem);
 
 
-	s_stencilRt  = bgfx::createRenderTarget(viewState.m_width, viewState.m_height, BGFX_RENDER_TARGET_COLOR_RGBA8 | BGFX_RENDER_TARGET_DEPTH_D16);
+	bgfx::TextureHandle fbtextures[] =
+	{
+		bgfx::createTexture2D(viewState.m_width, viewState.m_height, 1, bgfx::TextureFormat::BGRA8, BGFX_TEXTURE_U_CLAMP|BGFX_TEXTURE_V_CLAMP|BGFX_TEXTURE_RT),
+		bgfx::createTexture2D(viewState.m_width, viewState.m_height, 1, bgfx::TextureFormat::D16),
+	};
+	s_stencilFb  = bgfx::createFrameBuffer(BX_COUNTOF(fbtextures), fbtextures, true);
 
 
 	u_texColor   = bgfx::createUniform("u_texColor",   bgfx::UniformType::Uniform1iv);
 	u_texColor   = bgfx::createUniform("u_texColor",   bgfx::UniformType::Uniform1iv);
 	u_texStencil = bgfx::createUniform("u_texStencil", bgfx::UniformType::Uniform1iv);
 	u_texStencil = bgfx::createUniform("u_texStencil", bgfx::UniformType::Uniform1iv);
@@ -2184,9 +2189,11 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 			oldWidth = viewState.m_width;
 			oldWidth = viewState.m_width;
 			oldHeight = viewState.m_height;
 			oldHeight = viewState.m_height;
 
 
-			bgfx::destroyRenderTarget(s_stencilRt);
+			bgfx::destroyFrameBuffer(s_stencilFb);
 
 
-			s_stencilRt = bgfx::createRenderTarget(viewState.m_width, viewState.m_height, BGFX_RENDER_TARGET_COLOR_RGBA8 | BGFX_RENDER_TARGET_DEPTH_D16);
+			fbtextures[0] = bgfx::createTexture2D(viewState.m_width, viewState.m_height, 1, bgfx::TextureFormat::BGRA8, BGFX_TEXTURE_U_CLAMP|BGFX_TEXTURE_V_CLAMP|BGFX_TEXTURE_RT);
+			fbtextures[1] = bgfx::createTexture2D(viewState.m_width, viewState.m_height, 1, bgfx::TextureFormat::D16);
+			s_stencilFb = bgfx::createFrameBuffer(BX_COUNTOF(fbtextures), fbtextures, true);
 		}
 		}
 
 
 		// Time.
 		// Time.
@@ -2640,7 +2647,7 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 		if (settings_useStencilTexture)
 		if (settings_useStencilTexture)
 		{
 		{
 			bgfx::setViewClear(VIEWID_RANGE1_RT_PASS1, BGFX_CLEAR_DEPTH_BIT, 0x00000000, 1.0f, 0);
 			bgfx::setViewClear(VIEWID_RANGE1_RT_PASS1, BGFX_CLEAR_DEPTH_BIT, 0x00000000, 1.0f, 0);
-			bgfx::setViewRenderTarget(VIEWID_RANGE1_RT_PASS1, s_stencilRt);
+			bgfx::setViewFrameBuffer(VIEWID_RANGE1_RT_PASS1, s_stencilFb);
 
 
 			const RenderState& renderState = s_renderStates[RenderState::ShadowVolume_UsingStencilTexture_BuildDepth];
 			const RenderState& renderState = s_renderStates[RenderState::ShadowVolume_UsingStencilTexture_BuildDepth];
 
 
@@ -2672,7 +2679,7 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 
 
 			if (settings_useStencilTexture)
 			if (settings_useStencilTexture)
 			{
 			{
-				bgfx::setViewRenderTarget(viewId, s_stencilRt);
+				bgfx::setViewFrameBuffer(viewId, s_stencilFb);
 
 
 				bgfx::setViewClear(viewId
 				bgfx::setViewClear(viewId
 						, BGFX_CLEAR_COLOR_BIT
 						, BGFX_CLEAR_COLOR_BIT
@@ -2683,8 +2690,8 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 			}
 			}
 			else
 			else
 			{
 			{
-				const bgfx::RenderTargetHandle invalidRt = BGFX_INVALID_HANDLE;
-				bgfx::setViewRenderTarget(viewId, invalidRt);
+				const bgfx::FrameBufferHandle invalid = BGFX_INVALID_HANDLE;
+				bgfx::setViewFrameBuffer(viewId, invalid);
 
 
 				bgfx::setViewClear(viewId
 				bgfx::setViewClear(viewId
 						, BGFX_CLEAR_STENCIL_BIT
 						, BGFX_CLEAR_STENCIL_BIT
@@ -2926,7 +2933,7 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 
 
 	bgfx::destroyUniform(u_texColor);
 	bgfx::destroyUniform(u_texColor);
 	bgfx::destroyUniform(u_texStencil);
 	bgfx::destroyUniform(u_texStencil);
-	bgfx::destroyRenderTarget(s_stencilRt);
+	bgfx::destroyFrameBuffer(s_stencilFb);
 
 
 	bgfx::destroyTexture(figureTex);
 	bgfx::destroyTexture(figureTex);
 	bgfx::destroyTexture(fieldstoneTex);
 	bgfx::destroyTexture(fieldstoneTex);

+ 12 - 6
examples/15-shadowmaps-simple/shadowmaps_simple.cpp

@@ -71,7 +71,7 @@ static const uint16_t s_planeIndices[s_numPlaneIndices] =
 static const char* s_shaderPath = NULL;
 static const char* s_shaderPath = NULL;
 static bool s_flipV = false;
 static bool s_flipV = false;
 static float s_texelHalf = 0.0f;
 static float s_texelHalf = 0.0f;
-static bgfx::RenderTargetHandle s_rtShadowMap;
+bgfx::FrameBufferHandle s_shadowMapFB;
 static bgfx::UniformHandle u_shadowMap;
 static bgfx::UniformHandle u_shadowMap;
 
 
 static void shaderFilePath(char* _out, const char* _name)
 static void shaderFilePath(char* _out, const char* _name)
@@ -365,7 +365,7 @@ struct Mesh
 			bgfx::setVertexBuffer(group.m_vbh);
 			bgfx::setVertexBuffer(group.m_vbh);
 
 
 			// Set shadow map.
 			// Set shadow map.
-			bgfx::setTexture(4, u_shadowMap, s_rtShadowMap);
+			bgfx::setTexture(4, u_shadowMap, s_shadowMapFB);
 
 
 			// Set render states.
 			// Set render states.
 			bgfx::setState(0
 			bgfx::setState(0
@@ -455,7 +455,13 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 
 
 	// Render targets.
 	// Render targets.
 	uint16_t shadowMapSize = 512;
 	uint16_t shadowMapSize = 512;
-	s_rtShadowMap = bgfx::createRenderTarget(shadowMapSize, shadowMapSize, BGFX_RENDER_TARGET_COLOR_RGBA8 | BGFX_RENDER_TARGET_DEPTH_D16);
+
+	bgfx::TextureHandle fbtextures[] =
+	{
+		bgfx::createTexture2D(shadowMapSize, shadowMapSize, 1, bgfx::TextureFormat::BGRA8, BGFX_TEXTURE_RT),
+		bgfx::createTexture2D(shadowMapSize, shadowMapSize, 1, bgfx::TextureFormat::D16, BGFX_TEXTURE_RT_BUFFER_ONLY),
+	};
+	s_shadowMapFB = bgfx::createFrameBuffer(BX_COUNTOF(fbtextures), fbtextures, true);
 
 
 	// Set view and projection matrices.
 	// Set view and projection matrices.
 	float view[16];
 	float view[16];
@@ -583,9 +589,9 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 		bgfx::setViewTransform(RENDER_SHADOW_PASS_ID, lightView, lightProj);
 		bgfx::setViewTransform(RENDER_SHADOW_PASS_ID, lightView, lightProj);
 		bgfx::setViewTransform(RENDER_SCENE_PASS_ID, view, proj);
 		bgfx::setViewTransform(RENDER_SCENE_PASS_ID, view, proj);
 
 
-		bgfx::setViewRenderTarget(RENDER_SHADOW_PASS_ID, s_rtShadowMap);
+		bgfx::setViewFrameBuffer(RENDER_SHADOW_PASS_ID, s_shadowMapFB);
 
 
-		// Clear backbuffer and shadowmap rendertarget at beginning.
+		// Clear backbuffer and shadowmap framebuffer at beginning.
 		bgfx::setViewClearMask(0x3, BGFX_CLEAR_COLOR_BIT | BGFX_CLEAR_DEPTH_BIT, 0x303030ff, 1.0f, 0);
 		bgfx::setViewClearMask(0x3, BGFX_CLEAR_COLOR_BIT | BGFX_CLEAR_DEPTH_BIT, 0x303030ff, 1.0f, 0);
 		bgfx::submitMask(0x3);
 		bgfx::submitMask(0x3);
 
 
@@ -653,7 +659,7 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 	bgfx::destroyProgram(progPackDepth);
 	bgfx::destroyProgram(progPackDepth);
 	bgfx::destroyProgram(progDraw);
 	bgfx::destroyProgram(progDraw);
 
 
-	bgfx::destroyRenderTarget(s_rtShadowMap);
+	bgfx::destroyFrameBuffer(s_shadowMapFB);
 
 
 	bgfx::destroyUniform(u_shadowMap);
 	bgfx::destroyUniform(u_shadowMap);
 	bgfx::destroyUniform(u_lightPos);
 	bgfx::destroyUniform(u_lightPos);

+ 66 - 45
examples/16-shadowmaps/shadowmaps.cpp

@@ -256,8 +256,8 @@ static float s_texelHalf = 0.0f;
 
 
 static bgfx::UniformHandle u_texColor;
 static bgfx::UniformHandle u_texColor;
 static bgfx::UniformHandle u_shadowMap[ShadowMapRenderTargets::Count];
 static bgfx::UniformHandle u_shadowMap[ShadowMapRenderTargets::Count];
-static bgfx::RenderTargetHandle s_rtShadowMap[ShadowMapRenderTargets::Count];
-static bgfx::RenderTargetHandle s_rtBlur;
+static bgfx::FrameBufferHandle s_rtShadowMap[ShadowMapRenderTargets::Count];
+static bgfx::FrameBufferHandle s_rtBlur;
 
 
 static void shaderFilePath(char* _out, const char* _name)
 static void shaderFilePath(char* _out, const char* _name)
 {
 {
@@ -1580,14 +1580,14 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 	float lightMtx[16];
 	float lightMtx[16];
 	float shadowMapMtx[ShadowMapRenderTargets::Count][16];
 	float shadowMapMtx[ShadowMapRenderTargets::Count][16];
 	s_uniforms.setPtrs(&defaultMaterial
 	s_uniforms.setPtrs(&defaultMaterial
-			         , &pointLight
-			         , color
-			         , lightMtx
-			         , &shadowMapMtx[ShadowMapRenderTargets::First][0]
-			         , &shadowMapMtx[ShadowMapRenderTargets::Second][0]
-			         , &shadowMapMtx[ShadowMapRenderTargets::Third][0]
-			         , &shadowMapMtx[ShadowMapRenderTargets::Fourth][0]
-			         );
+					 , &pointLight
+					 , color
+					 , lightMtx
+					 , &shadowMapMtx[ShadowMapRenderTargets::First][0]
+					 , &shadowMapMtx[ShadowMapRenderTargets::Second][0]
+					 , &shadowMapMtx[ShadowMapRenderTargets::Third][0]
+					 , &shadowMapMtx[ShadowMapRenderTargets::Fourth][0]
+					 );
 	s_uniforms.submitConstUniforms();
 	s_uniforms.submitConstUniforms();
 
 
 	// Settings.
 	// Settings.
@@ -2087,9 +2087,14 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 	s_uniforms.m_shadowMapTexelSize = 1.0f / currentShadowMapSizef;
 	s_uniforms.m_shadowMapTexelSize = 1.0f / currentShadowMapSizef;
 	for (uint8_t ii = 0; ii < ShadowMapRenderTargets::Count; ++ii)
 	for (uint8_t ii = 0; ii < ShadowMapRenderTargets::Count; ++ii)
 	{
 	{
-		s_rtShadowMap[ii] = bgfx::createRenderTarget(currentShadowMapSize, currentShadowMapSize, BGFX_RENDER_TARGET_COLOR_RGBA8 | BGFX_RENDER_TARGET_DEPTH_D24S8);
+		bgfx::TextureHandle fbtextures[] =
+		{
+			bgfx::createTexture2D(currentShadowMapSize, currentShadowMapSize, 1, bgfx::TextureFormat::BGRA8, BGFX_TEXTURE_RT),
+			bgfx::createTexture2D(currentShadowMapSize, currentShadowMapSize, 1, bgfx::TextureFormat::D24S8),
+		};
+		s_rtShadowMap[ii] = bgfx::createFrameBuffer(BX_COUNTOF(fbtextures), fbtextures, true);
 	}
 	}
-	s_rtBlur = bgfx::createRenderTarget(currentShadowMapSize, currentShadowMapSize, BGFX_RENDER_TARGET_COLOR_RGBA8);
+	s_rtBlur = bgfx::createFrameBuffer(currentShadowMapSize, currentShadowMapSize, bgfx::TextureFormat::BGRA8);
 
 
 	// Setup camera.
 	// Setup camera.
 	float initialPos[3] = { 0.0f, 60.0f, -105.0f };
 	float initialPos[3] = { 0.0f, 60.0f, -105.0f };
@@ -2590,8 +2595,8 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 
 
 		// Reset render targets.
 		// Reset render targets.
 		const uint32_t viewMask = (uint32_t(1) << (RENDERVIEW_DRAWDEPTH_3_ID+1) ) - 1;
 		const uint32_t viewMask = (uint32_t(1) << (RENDERVIEW_DRAWDEPTH_3_ID+1) ) - 1;
-		const bgfx::RenderTargetHandle invalidRt = BGFX_INVALID_HANDLE;
-		bgfx::setViewRenderTargetMask(viewMask, invalidRt);
+		const bgfx::FrameBufferHandle invalidRt = BGFX_INVALID_HANDLE;
+		bgfx::setViewFrameBufferMask(viewMask, invalidRt);
 
 
 		// Determine on-screen rectangle size where depth buffer will be drawn.
 		// Determine on-screen rectangle size where depth buffer will be drawn.
 		const uint16_t depthRectHeight = uint16_t(float(viewState.m_height) / 2.5f);
 		const uint16_t depthRectHeight = uint16_t(float(viewState.m_height) / 2.5f);
@@ -2631,10 +2636,10 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 			bgfx::setViewTransform(RENDERVIEW_DRAWSCENE_1_ID, viewState.m_view, viewState.m_proj);
 			bgfx::setViewTransform(RENDERVIEW_DRAWSCENE_1_ID, viewState.m_view, viewState.m_proj);
 			bgfx::setViewTransform(RENDERVIEW_DRAWDEPTH_0_ID, screenView, screenProj);
 			bgfx::setViewTransform(RENDERVIEW_DRAWDEPTH_0_ID, screenView, screenProj);
 
 
-			bgfx::setViewRenderTarget(RENDERVIEW_SHADOWMAP_0_ID, s_rtShadowMap[0]);
-			bgfx::setViewRenderTarget(RENDERVIEW_SHADOWMAP_1_ID, s_rtShadowMap[0]);
-			bgfx::setViewRenderTarget(RENDERVIEW_VBLUR_0_ID, s_rtBlur);
-			bgfx::setViewRenderTarget(RENDERVIEW_HBLUR_0_ID, s_rtShadowMap[0]);
+			bgfx::setViewFrameBuffer(RENDERVIEW_SHADOWMAP_0_ID, s_rtShadowMap[0]);
+			bgfx::setViewFrameBuffer(RENDERVIEW_SHADOWMAP_1_ID, s_rtShadowMap[0]);
+			bgfx::setViewFrameBuffer(RENDERVIEW_VBLUR_0_ID, s_rtBlur);
+			bgfx::setViewFrameBuffer(RENDERVIEW_HBLUR_0_ID, s_rtShadowMap[0]);
 		}
 		}
 		else if (LightType::PointLight == settings.m_lightType)
 		else if (LightType::PointLight == settings.m_lightType)
 		{
 		{
@@ -2694,13 +2699,13 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 			bgfx::setViewTransform(RENDERVIEW_DRAWSCENE_1_ID, viewState.m_view, viewState.m_proj);
 			bgfx::setViewTransform(RENDERVIEW_DRAWSCENE_1_ID, viewState.m_view, viewState.m_proj);
 			bgfx::setViewTransform(RENDERVIEW_DRAWDEPTH_0_ID, screenView, screenProj);
 			bgfx::setViewTransform(RENDERVIEW_DRAWDEPTH_0_ID, screenView, screenProj);
 
 
-			bgfx::setViewRenderTarget(RENDERVIEW_SHADOWMAP_0_ID, s_rtShadowMap[0]);
-			bgfx::setViewRenderTarget(RENDERVIEW_SHADOWMAP_1_ID, s_rtShadowMap[0]);
-			bgfx::setViewRenderTarget(RENDERVIEW_SHADOWMAP_2_ID, s_rtShadowMap[0]);
-			bgfx::setViewRenderTarget(RENDERVIEW_SHADOWMAP_3_ID, s_rtShadowMap[0]);
-			bgfx::setViewRenderTarget(RENDERVIEW_SHADOWMAP_4_ID, s_rtShadowMap[0]);
-			bgfx::setViewRenderTarget(RENDERVIEW_VBLUR_0_ID, s_rtBlur);
-			bgfx::setViewRenderTarget(RENDERVIEW_HBLUR_0_ID, s_rtShadowMap[0]);
+			bgfx::setViewFrameBuffer(RENDERVIEW_SHADOWMAP_0_ID, s_rtShadowMap[0]);
+			bgfx::setViewFrameBuffer(RENDERVIEW_SHADOWMAP_1_ID, s_rtShadowMap[0]);
+			bgfx::setViewFrameBuffer(RENDERVIEW_SHADOWMAP_2_ID, s_rtShadowMap[0]);
+			bgfx::setViewFrameBuffer(RENDERVIEW_SHADOWMAP_3_ID, s_rtShadowMap[0]);
+			bgfx::setViewFrameBuffer(RENDERVIEW_SHADOWMAP_4_ID, s_rtShadowMap[0]);
+			bgfx::setViewFrameBuffer(RENDERVIEW_VBLUR_0_ID, s_rtBlur);
+			bgfx::setViewFrameBuffer(RENDERVIEW_HBLUR_0_ID, s_rtShadowMap[0]);
 		}
 		}
 		else // LightType::DirectionalLight == settings.m_lightType
 		else // LightType::DirectionalLight == settings.m_lightType
 		{
 		{
@@ -2768,18 +2773,18 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 			bgfx::setViewTransform(RENDERVIEW_DRAWDEPTH_2_ID, screenView, screenProj);
 			bgfx::setViewTransform(RENDERVIEW_DRAWDEPTH_2_ID, screenView, screenProj);
 			bgfx::setViewTransform(RENDERVIEW_DRAWDEPTH_3_ID, screenView, screenProj);
 			bgfx::setViewTransform(RENDERVIEW_DRAWDEPTH_3_ID, screenView, screenProj);
 
 
-			bgfx::setViewRenderTarget(RENDERVIEW_SHADOWMAP_1_ID, s_rtShadowMap[0]);
-			bgfx::setViewRenderTarget(RENDERVIEW_SHADOWMAP_2_ID, s_rtShadowMap[1]);
-			bgfx::setViewRenderTarget(RENDERVIEW_SHADOWMAP_3_ID, s_rtShadowMap[2]);
-			bgfx::setViewRenderTarget(RENDERVIEW_SHADOWMAP_4_ID, s_rtShadowMap[3]);
-			bgfx::setViewRenderTarget(RENDERVIEW_VBLUR_0_ID, s_rtBlur);         //vblur
-			bgfx::setViewRenderTarget(RENDERVIEW_HBLUR_0_ID, s_rtShadowMap[0]); //hblur
-			bgfx::setViewRenderTarget(RENDERVIEW_VBLUR_1_ID, s_rtBlur);         //vblur
-			bgfx::setViewRenderTarget(RENDERVIEW_HBLUR_1_ID, s_rtShadowMap[1]); //hblur
-			bgfx::setViewRenderTarget(RENDERVIEW_VBLUR_2_ID, s_rtBlur);         //vblur
-			bgfx::setViewRenderTarget(RENDERVIEW_HBLUR_2_ID, s_rtShadowMap[2]); //hblur
-			bgfx::setViewRenderTarget(RENDERVIEW_VBLUR_3_ID, s_rtBlur);         //vblur
-			bgfx::setViewRenderTarget(RENDERVIEW_HBLUR_3_ID, s_rtShadowMap[3]); //hblur
+			bgfx::setViewFrameBuffer(RENDERVIEW_SHADOWMAP_1_ID, s_rtShadowMap[0]);
+			bgfx::setViewFrameBuffer(RENDERVIEW_SHADOWMAP_2_ID, s_rtShadowMap[1]);
+			bgfx::setViewFrameBuffer(RENDERVIEW_SHADOWMAP_3_ID, s_rtShadowMap[2]);
+			bgfx::setViewFrameBuffer(RENDERVIEW_SHADOWMAP_4_ID, s_rtShadowMap[3]);
+			bgfx::setViewFrameBuffer(RENDERVIEW_VBLUR_0_ID, s_rtBlur);         //vblur
+			bgfx::setViewFrameBuffer(RENDERVIEW_HBLUR_0_ID, s_rtShadowMap[0]); //hblur
+			bgfx::setViewFrameBuffer(RENDERVIEW_VBLUR_1_ID, s_rtBlur);         //vblur
+			bgfx::setViewFrameBuffer(RENDERVIEW_HBLUR_1_ID, s_rtShadowMap[1]); //hblur
+			bgfx::setViewFrameBuffer(RENDERVIEW_VBLUR_2_ID, s_rtBlur);         //vblur
+			bgfx::setViewFrameBuffer(RENDERVIEW_HBLUR_2_ID, s_rtShadowMap[2]); //hblur
+			bgfx::setViewFrameBuffer(RENDERVIEW_VBLUR_3_ID, s_rtBlur);         //vblur
+			bgfx::setViewFrameBuffer(RENDERVIEW_HBLUR_3_ID, s_rtShadowMap[3]); //hblur
 		}
 		}
 
 
 		// Clear backbuffer at beginning.
 		// Clear backbuffer at beginning.
@@ -3236,20 +3241,36 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 			currentShadowMapSizef = float(int16_t(currentShadowMapSize) );
 			currentShadowMapSizef = float(int16_t(currentShadowMapSize) );
 			s_uniforms.m_shadowMapTexelSize = 1.0f / currentShadowMapSizef;
 			s_uniforms.m_shadowMapTexelSize = 1.0f / currentShadowMapSizef;
 
 
-			bgfx::destroyRenderTarget(s_rtShadowMap[0]);
-			s_rtShadowMap[0] = bgfx::createRenderTarget(currentShadowMapSize, currentShadowMapSize, BGFX_RENDER_TARGET_COLOR_RGBA8 | BGFX_RENDER_TARGET_DEPTH_D24S8);
+			{
+				bgfx::destroyFrameBuffer(s_rtShadowMap[0]);
+
+				bgfx::TextureHandle fbtextures[] =
+				{
+					bgfx::createTexture2D(currentShadowMapSize, currentShadowMapSize, 1, bgfx::TextureFormat::BGRA8, BGFX_TEXTURE_RT),
+					bgfx::createTexture2D(currentShadowMapSize, currentShadowMapSize, 1, bgfx::TextureFormat::D24S8),
+				};
+				s_rtShadowMap[0] = bgfx::createFrameBuffer(BX_COUNTOF(fbtextures), fbtextures, true);
+			}
 
 
 			if (LightType::DirectionalLight == settings.m_lightType)
 			if (LightType::DirectionalLight == settings.m_lightType)
 			{
 			{
 				for (uint8_t ii = 1; ii < ShadowMapRenderTargets::Count; ++ii)
 				for (uint8_t ii = 1; ii < ShadowMapRenderTargets::Count; ++ii)
 				{
 				{
-					bgfx::destroyRenderTarget(s_rtShadowMap[ii]);
-					s_rtShadowMap[ii] = bgfx::createRenderTarget(currentShadowMapSize, currentShadowMapSize, BGFX_RENDER_TARGET_COLOR_RGBA8 | BGFX_RENDER_TARGET_DEPTH_D24S8);
+					{
+						bgfx::destroyFrameBuffer(s_rtShadowMap[ii]);
+
+						bgfx::TextureHandle fbtextures[] =
+						{
+							bgfx::createTexture2D(currentShadowMapSize, currentShadowMapSize, 1, bgfx::TextureFormat::BGRA8, BGFX_TEXTURE_RT),
+							bgfx::createTexture2D(currentShadowMapSize, currentShadowMapSize, 1, bgfx::TextureFormat::D24S8),
+						};
+						s_rtShadowMap[ii] = bgfx::createFrameBuffer(BX_COUNTOF(fbtextures), fbtextures, true);
+					}
 				}
 				}
 			}
 			}
 
 
-			bgfx::destroyRenderTarget(s_rtBlur);
-			s_rtBlur = bgfx::createRenderTarget(currentShadowMapSize, currentShadowMapSize, BGFX_RENDER_TARGET_COLOR_RGBA8);
+			bgfx::destroyFrameBuffer(s_rtBlur);
+			s_rtBlur = bgfx::createFrameBuffer(currentShadowMapSize, currentShadowMapSize, bgfx::TextureFormat::BGRA8);
 		}
 		}
 
 
 		// Advance to next frame. Rendering thread will be kicked to
 		// Advance to next frame. Rendering thread will be kicked to
@@ -3271,9 +3292,9 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 
 
 	for (uint8_t ii = 0; ii < ShadowMapRenderTargets::Count; ++ii)
 	for (uint8_t ii = 0; ii < ShadowMapRenderTargets::Count; ++ii)
 	{
 	{
-		bgfx::destroyRenderTarget(s_rtShadowMap[ii]);
+		bgfx::destroyFrameBuffer(s_rtShadowMap[ii]);
 	}
 	}
-	bgfx::destroyRenderTarget(s_rtBlur);
+	bgfx::destroyFrameBuffer(s_rtBlur);
 
 
 	s_programs.destroy();
 	s_programs.destroy();
 
 

+ 4 - 4
examples/common/entry/entry.cpp

@@ -148,10 +148,10 @@ namespace entry
 
 
 	static const InputBinding s_camBindings[] = 
 	static const InputBinding s_camBindings[] = 
 	{
 	{
-		{ entry::Key::KeyW,  entry::Modifier::None,      0, cmd, "move forward"         },
-		{ entry::Key::KeyA,  entry::Modifier::None,      0, cmd, "move left"            },
-		{ entry::Key::KeyS,  entry::Modifier::None,      0, cmd, "move backward"        },
-		{ entry::Key::KeyD,  entry::Modifier::None,      0, cmd, "move right"           },
+		{ entry::Key::KeyW,  entry::Modifier::None,      0, cmd, "move forward"  },
+		{ entry::Key::KeyA,  entry::Modifier::None,      0, cmd, "move left"     },
+		{ entry::Key::KeyS,  entry::Modifier::None,      0, cmd, "move backward" },
+		{ entry::Key::KeyD,  entry::Modifier::None,      0, cmd, "move right"    },
 
 
 		INPUT_BINDING_END
 		INPUT_BINDING_END
 	};
 	};

+ 64 - 68
include/bgfx.h

@@ -171,57 +171,37 @@
 #define BGFX_TEXTURE_U_CLAMP             UINT32_C(0x00000002)
 #define BGFX_TEXTURE_U_CLAMP             UINT32_C(0x00000002)
 #define BGFX_TEXTURE_U_SHIFT             0
 #define BGFX_TEXTURE_U_SHIFT             0
 #define BGFX_TEXTURE_U_MASK              UINT32_C(0x00000003)
 #define BGFX_TEXTURE_U_MASK              UINT32_C(0x00000003)
-#define BGFX_TEXTURE_V_MIRROR            UINT32_C(0x00000010)
-#define BGFX_TEXTURE_V_CLAMP             UINT32_C(0x00000020)
-#define BGFX_TEXTURE_V_SHIFT             4
-#define BGFX_TEXTURE_V_MASK              UINT32_C(0x00000030)
-#define BGFX_TEXTURE_W_MIRROR            UINT32_C(0x00000100)
-#define BGFX_TEXTURE_W_CLAMP             UINT32_C(0x00000200)
-#define BGFX_TEXTURE_W_SHIFT             8
-#define BGFX_TEXTURE_W_MASK              UINT32_C(0x00000300)
-#define BGFX_TEXTURE_MIN_POINT           UINT32_C(0x00001000)
-#define BGFX_TEXTURE_MIN_ANISOTROPIC     UINT32_C(0x00002000)
-#define BGFX_TEXTURE_MIN_SHIFT           12
-#define BGFX_TEXTURE_MIN_MASK            UINT32_C(0x00003000)
-#define BGFX_TEXTURE_MAG_POINT           UINT32_C(0x00010000)
-#define BGFX_TEXTURE_MAG_ANISOTROPIC     UINT32_C(0x00020000)
-#define BGFX_TEXTURE_MAG_SHIFT           16
-#define BGFX_TEXTURE_MAG_MASK            UINT32_C(0x00030000)
-#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_V_MIRROR            UINT32_C(0x00000004)
+#define BGFX_TEXTURE_V_CLAMP             UINT32_C(0x00000008)
+#define BGFX_TEXTURE_V_SHIFT             2
+#define BGFX_TEXTURE_V_MASK              UINT32_C(0x0000000c)
+#define BGFX_TEXTURE_W_MIRROR            UINT32_C(0x00000010)
+#define BGFX_TEXTURE_W_CLAMP             UINT32_C(0x00000020)
+#define BGFX_TEXTURE_W_SHIFT             4
+#define BGFX_TEXTURE_W_MASK              UINT32_C(0x00000030)
+#define BGFX_TEXTURE_MIN_POINT           UINT32_C(0x00000040)
+#define BGFX_TEXTURE_MIN_ANISOTROPIC     UINT32_C(0x00000080)
+#define BGFX_TEXTURE_MIN_SHIFT           6
+#define BGFX_TEXTURE_MIN_MASK            UINT32_C(0x000000c0)
+#define BGFX_TEXTURE_MAG_POINT           UINT32_C(0x00000100)
+#define BGFX_TEXTURE_MAG_ANISOTROPIC     UINT32_C(0x00000200)
+#define BGFX_TEXTURE_MAG_SHIFT           8
+#define BGFX_TEXTURE_MAG_MASK            UINT32_C(0x00000300)
+#define BGFX_TEXTURE_MIP_POINT           UINT32_C(0x00000400)
+#define BGFX_TEXTURE_MIP_SHIFT           10
+#define BGFX_TEXTURE_MIP_MASK            UINT32_C(0x00000400)
+#define BGFX_TEXTURE_RT                  UINT32_C(0x00001000)
+#define BGFX_TEXTURE_RT_MSAA_X2          UINT32_C(0x00002000)
+#define BGFX_TEXTURE_RT_MSAA_X4          UINT32_C(0x00003000)
+#define BGFX_TEXTURE_RT_MSAA_X8          UINT32_C(0x00004000)
+#define BGFX_TEXTURE_RT_MSAA_X16         UINT32_C(0x00005000)
+#define BGFX_TEXTURE_RT_MSAA_SHIFT       12
+#define BGFX_TEXTURE_RT_MSAA_MASK        UINT32_C(0x00007000)
+#define BGFX_TEXTURE_RT_BUFFER_ONLY      UINT32_C(0x00008000)
+#define BGFX_TEXTURE_RT_MASK             UINT32_C(0x0000f000)
 #define BGFX_TEXTURE_RESERVED_SHIFT      24
 #define BGFX_TEXTURE_RESERVED_SHIFT      24
 #define BGFX_TEXTURE_RESERVED_MASK       UINT32_C(0xff000000)
 #define BGFX_TEXTURE_RESERVED_MASK       UINT32_C(0xff000000)
 
 
-///
-#define BGFX_RENDER_TARGET_NONE          UINT32_C(0x00000000)
-#define BGFX_RENDER_TARGET_COLOR_RGBA8   UINT32_C(0x00000001)
-#define BGFX_RENDER_TARGET_COLOR_RGB10A2 UINT32_C(0x00000002)
-#define BGFX_RENDER_TARGET_COLOR_RGBA16  UINT32_C(0x00000003)
-#define BGFX_RENDER_TARGET_COLOR_RGBA16F UINT32_C(0x00000004)
-#define BGFX_RENDER_TARGET_COLOR_R16F    UINT32_C(0x00000005)
-#define BGFX_RENDER_TARGET_COLOR_R32F    UINT32_C(0x00000006)
-#define BGFX_RENDER_TARGET_COLOR_SHIFT   0
-#define BGFX_RENDER_TARGET_COLOR_MASK    UINT32_C(0x000000ff)
-
-#define BGFX_RENDER_TARGET_DEPTH_D16     UINT32_C(0x00000100)
-#define BGFX_RENDER_TARGET_DEPTH_D24     UINT32_C(0x00000200)
-#define BGFX_RENDER_TARGET_DEPTH_D24S8   UINT32_C(0x00000300)
-#define BGFX_RENDER_TARGET_DEPTH_D32     UINT32_C(0x00000400)
-#define BGFX_RENDER_TARGET_DEPTH_D16F    UINT32_C(0x00000500)
-#define BGFX_RENDER_TARGET_DEPTH_D24F    UINT32_C(0x00000600)
-#define BGFX_RENDER_TARGET_DEPTH_D32F    UINT32_C(0x00000700)
-#define BGFX_RENDER_TARGET_DEPTH_D0S8    UINT32_C(0x00000800)
-#define BGFX_RENDER_TARGET_DEPTH_SHIFT   8
-#define BGFX_RENDER_TARGET_DEPTH_MASK    UINT32_C(0x0000ff00)
-
-#define BGFX_RENDER_TARGET_MSAA_X2       UINT32_C(0x00010000)
-#define BGFX_RENDER_TARGET_MSAA_X4       UINT32_C(0x00020000)
-#define BGFX_RENDER_TARGET_MSAA_X8       UINT32_C(0x00030000)
-#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_RESET_NONE                  UINT32_C(0x00000000)
 #define BGFX_RESET_NONE                  UINT32_C(0x00000000)
 #define BGFX_RESET_FULLSCREEN            UINT32_C(0x00000001)
 #define BGFX_RESET_FULLSCREEN            UINT32_C(0x00000001)
@@ -297,7 +277,6 @@ namespace bgfx
 			MinimumRequiredSpecs,
 			MinimumRequiredSpecs,
 			InvalidShader,
 			InvalidShader,
 			UnableToInitialize,
 			UnableToInitialize,
-			UnableToCreateRenderTarget,
 			UnableToCreateTexture,
 			UnableToCreateTexture,
 		};
 		};
 	};
 	};
@@ -428,7 +407,7 @@ namespace bgfx
 	BGFX_HANDLE(FragmentShaderHandle);
 	BGFX_HANDLE(FragmentShaderHandle);
 	BGFX_HANDLE(IndexBufferHandle);
 	BGFX_HANDLE(IndexBufferHandle);
 	BGFX_HANDLE(ProgramHandle);
 	BGFX_HANDLE(ProgramHandle);
-	BGFX_HANDLE(RenderTargetHandle);
+	BGFX_HANDLE(FrameBufferHandle);
 	BGFX_HANDLE(TextureHandle);
 	BGFX_HANDLE(TextureHandle);
 	BGFX_HANDLE(UniformHandle);
 	BGFX_HANDLE(UniformHandle);
 	BGFX_HANDLE(VertexBufferHandle);
 	BGFX_HANDLE(VertexBufferHandle);
@@ -500,8 +479,9 @@ namespace bgfx
 		/// internally decompresses texture into supported format.
 		/// internally decompresses texture into supported format.
 		uint64_t emulated;
 		uint64_t emulated;
 
 
-		uint16_t maxTextureSize; ///< Maximum texture size.
-		uint16_t maxDrawCalls;   ///< Maximum draw calls.
+		uint16_t maxTextureSize;   ///< Maximum texture size.
+		uint16_t maxDrawCalls;     ///< Maximum draw calls.
+		uint8_t  maxFBAttachments; ///< Maximum frame buffer attachments.
 	};
 	};
 
 
 	struct TransientIndexBuffer
 	struct TransientIndexBuffer
@@ -981,11 +961,26 @@ namespace bgfx
 	/// Destroy texture.
 	/// Destroy texture.
 	void destroyTexture(TextureHandle _handle);
 	void destroyTexture(TextureHandle _handle);
 
 
-	/// Create render target.
-	RenderTargetHandle createRenderTarget(uint16_t _width, uint16_t _height, uint32_t _flags = BGFX_RENDER_TARGET_COLOR_RGBA8, uint32_t _textureFlags = BGFX_TEXTURE_U_CLAMP|BGFX_TEXTURE_V_CLAMP);
+	/// Create frame buffer (simple).
+	///
+	/// @param _width Texture width.
+	/// @param _height Texture height.
+	/// @param _format Texture format.
+	/// @param _textureFlags Texture flags.
+	///
+	FrameBufferHandle createFrameBuffer(uint16_t _width, uint16_t _height, TextureFormat::Enum _format, uint32_t _textureFlags = BGFX_TEXTURE_U_CLAMP|BGFX_TEXTURE_V_CLAMP);
+
+	/// Create frame buffer.
+	///
+	/// @param _num Number of texture attachments.
+	/// @param _handles Texture attachments.
+	/// @param _destroyTextures Destroy textures when frame buffer is
+	///   destroyed.
+	///
+	FrameBufferHandle createFrameBuffer(uint8_t _num, TextureHandle* _handles, bool _destroyTextures = false);
 
 
-	/// Destroy render target.
-	void destroyRenderTarget(RenderTargetHandle _handle);
+	/// Destroy frame buffer.
+	void destroyFrameBuffer(FrameBufferHandle _handle);
 
 
 	/// Create shader uniform parameter.
 	/// Create shader uniform parameter.
 	///
 	///
@@ -1092,23 +1087,23 @@ namespace bgfx
 	/// Set multiple views into sequential mode.
 	/// Set multiple views into sequential mode.
 	void setViewSeqMask(uint32_t _viewMask, bool _enabled);
 	void setViewSeqMask(uint32_t _viewMask, bool _enabled);
 
 
-	/// Set view render target.
+	/// Set view frame buffer.
 	///
 	///
 	/// @param _id View id.
 	/// @param _id View id.
-	/// @param _handle Render target handle. Passing BGFX_INVALID_HANDLE as
-	///   render target handle will draw primitives from this view into
-	///   default backbuffer.
+	/// @param _handle Frame buffer handle. Passing BGFX_INVALID_HANDLE as
+	///   frame buffer handle will draw primitives from this view into
+	///   default back buffer.
 	///
 	///
-	void setViewRenderTarget(uint8_t _id, RenderTargetHandle _handle);
+	void setViewFrameBuffer(uint8_t _id, FrameBufferHandle _handle);
 
 
-	/// Set view render target for multiple views.
+	/// Set view frame buffer for multiple views.
 	///
 	///
 	/// @param _viewMask View mask.
 	/// @param _viewMask View mask.
-	/// @param _handle Render target handle. Passing BGFX_INVALID_HANDLE as
-	///   render target handle will draw primitives from this view into
-	///   default backbuffer.
+	/// @param _handle Frame buffer handle. Passing BGFX_INVALID_HANDLE as
+	///   frame buffer handle will draw primitives from this view into
+	///   default back buffer.
 	///
 	///
-	void setViewRenderTargetMask(uint32_t _viewMask, RenderTargetHandle _handle);
+	void setViewFrameBufferMask(uint32_t _viewMask, FrameBufferHandle _handle);
 
 
 	/// Set view view and projection matrices, all draw primitives in this
 	/// Set view view and projection matrices, all draw primitives in this
 	/// view will use these matrices.
 	/// view will use these matrices.
@@ -1239,7 +1234,8 @@ namespace bgfx
 	///
 	///
 	/// @param _stage Texture unit.
 	/// @param _stage Texture unit.
 	/// @param _sampler Program sampler.
 	/// @param _sampler Program sampler.
-	/// @param _handle Render target handle.
+	/// @param _handle Frame buffer handle.
+	/// @param _attachment Attachment index.
 	/// @param _flags Texture sampling mode. Default value UINT32_MAX uses
 	/// @param _flags Texture sampling mode. Default value UINT32_MAX uses
 	///   texture sampling settings from the texture.
 	///   texture sampling settings from the texture.
 	///
 	///
@@ -1249,7 +1245,7 @@ namespace bgfx
 	///   BGFX_TEXTURE_[MIN/MAG/MIP]_[POINT/ANISOTROPIC] - Point or anisotropic
 	///   BGFX_TEXTURE_[MIN/MAG/MIP]_[POINT/ANISOTROPIC] - Point or anisotropic
 	///     sampling.
 	///     sampling.
 	///
 	///
-	void setTexture(uint8_t _stage, UniformHandle _sampler, RenderTargetHandle _handle, bool _depth = false, uint32_t _flags = UINT32_MAX);
+	void setTexture(uint8_t _stage, UniformHandle _sampler, FrameBufferHandle _handle, uint8_t _attachment = 0, uint32_t _flags = UINT32_MAX);
 
 
 	/// Submit primitive for rendering into single view.
 	/// Submit primitive for rendering into single view.
 	///
 	///

+ 60 - 42
src/bgfx.cpp

@@ -709,6 +709,7 @@ namespace bgfx
 			;
 			;
 		g_caps.emulated = 0;
 		g_caps.emulated = 0;
 		g_caps.maxDrawCalls = BGFX_CONFIG_MAX_DRAW_CALLS;
 		g_caps.maxDrawCalls = BGFX_CONFIG_MAX_DRAW_CALLS;
+		g_caps.maxFBAttachments = 1;
 
 
 		if (NULL != _allocator)
 		if (NULL != _allocator)
 		{
 		{
@@ -898,7 +899,7 @@ namespace bgfx
 		BX_TRACE("Multithreaded renderer is disabled.");
 		BX_TRACE("Multithreaded renderer is disabled.");
 #endif // BGFX_CONFIG_MULTITHREADED
 #endif // BGFX_CONFIG_MULTITHREADED
 
 
-		memset(m_rt, 0xff, sizeof(m_rt) );
+		memset(m_fb, 0xff, sizeof(m_fb) );
 		memset(m_clear, 0, sizeof(m_clear) );
 		memset(m_clear, 0, sizeof(m_clear) );
 		memset(m_rect, 0, sizeof(m_rect) );
 		memset(m_rect, 0, sizeof(m_rect) );
 		memset(m_scissor, 0, sizeof(m_scissor) );
 		memset(m_scissor, 0, sizeof(m_scissor) );
@@ -991,7 +992,7 @@ namespace bgfx
 		CHECK_HANDLE_LEAK(m_fragmentShaderHandle);
 		CHECK_HANDLE_LEAK(m_fragmentShaderHandle);
 		CHECK_HANDLE_LEAK(m_programHandle);
 		CHECK_HANDLE_LEAK(m_programHandle);
 		CHECK_HANDLE_LEAK(m_textureHandle);
 		CHECK_HANDLE_LEAK(m_textureHandle);
-		CHECK_HANDLE_LEAK(m_renderTargetHandle);
+		CHECK_HANDLE_LEAK(m_frameBufferHandle);
 		CHECK_HANDLE_LEAK(m_uniformHandle);
 		CHECK_HANDLE_LEAK(m_uniformHandle);
 
 
 #	undef CHECK_HANDLE_LEAK
 #	undef CHECK_HANDLE_LEAK
@@ -1050,9 +1051,9 @@ namespace bgfx
 			m_textureHandle.free(_frame->m_freeTextureHandle[ii].idx);
 			m_textureHandle.free(_frame->m_freeTextureHandle[ii].idx);
 		}
 		}
 
 
-		for (uint16_t ii = 0, num = _frame->m_numFreeRenderTargetHandles; ii < num; ++ii)
+		for (uint16_t ii = 0, num = _frame->m_numFreeFrameBufferHandles; ii < num; ++ii)
 		{
 		{
-			m_renderTargetHandle.free(_frame->m_freeRenderTargetHandle[ii].idx);
+			m_frameBufferHandle.free(_frame->m_freeFrameBufferHandle[ii].idx);
 		}
 		}
 
 
 		for (uint16_t ii = 0, num = _frame->m_numFreeUniformHandles; ii < num; ++ii)
 		for (uint16_t ii = 0, num = _frame->m_numFreeUniformHandles; ii < num; ++ii)
@@ -1089,7 +1090,7 @@ namespace bgfx
 		freeDynamicBuffers();
 		freeDynamicBuffers();
 		m_submit->m_resolution = m_resolution;
 		m_submit->m_resolution = m_resolution;
 		m_submit->m_debug = m_debug;
 		m_submit->m_debug = m_debug;
-		memcpy(m_submit->m_rt, m_rt, sizeof(m_rt) );
+		memcpy(m_submit->m_fb, m_fb, sizeof(m_fb) );
 		memcpy(m_submit->m_clear, m_clear, sizeof(m_clear) );
 		memcpy(m_submit->m_clear, m_clear, sizeof(m_clear) );
 		memcpy(m_submit->m_rect, m_rect, sizeof(m_rect) );
 		memcpy(m_submit->m_rect, m_rect, sizeof(m_rect) );
 		memcpy(m_submit->m_scissor, m_scissor, sizeof(m_scissor) );
 		memcpy(m_submit->m_scissor, m_scissor, sizeof(m_scissor) );
@@ -1533,12 +1534,11 @@ namespace bgfx
 					uint8_t mip;
 					uint8_t mip;
 					_cmdbuf.read(mip);
 					_cmdbuf.read(mip);
 
 
-					_cmdbuf.skip(sizeof(Rect)
-						+ sizeof(uint16_t)
-						+ sizeof(uint16_t)
-						+ sizeof(uint16_t)
-						+ sizeof(Memory*)
-						);
+					_cmdbuf.skip<Rect>();
+					_cmdbuf.skip<uint16_t>();
+					_cmdbuf.skip<uint16_t>();
+					_cmdbuf.skip<uint16_t>();
+					_cmdbuf.skip<Memory*>();
 
 
 					uint32_t key = (handle.idx<<16)
 					uint32_t key = (handle.idx<<16)
 						| (side<<8)
 						| (side<<8)
@@ -1558,33 +1558,30 @@ namespace bgfx
 				}
 				}
 				break;
 				break;
 
 
-			case CommandBuffer::CreateRenderTarget:
+			case CommandBuffer::CreateFrameBuffer:
 				{
 				{
-					RenderTargetHandle handle;
+					FrameBufferHandle handle;
 					_cmdbuf.read(handle);
 					_cmdbuf.read(handle);
 
 
-					uint16_t width;
-					_cmdbuf.read(width);
-
-					uint16_t height;
-					_cmdbuf.read(height);
-
-					uint32_t flags;
-					_cmdbuf.read(flags);
+					uint8_t num;
+					_cmdbuf.read(num);
 
 
-					uint32_t textureFlags;
-					_cmdbuf.read(textureFlags);
+					TextureHandle textureHandles[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS];
+					for (uint32_t ii = 0; ii < num; ++ii)
+					{
+						_cmdbuf.read(textureHandles[ii]);
+					}
 
 
-					rendererCreateRenderTarget(handle, width, height, flags, textureFlags);
+					rendererCreateFrameBuffer(handle, num, textureHandles);
 				}
 				}
 				break;
 				break;
 
 
-			case CommandBuffer::DestroyRenderTarget:
+			case CommandBuffer::DestroyFrameBuffer:
 				{
 				{
-					RenderTargetHandle handle;
+					FrameBufferHandle handle;
 					_cmdbuf.read(handle);
 					_cmdbuf.read(handle);
 
 
-					rendererDestroyRenderTarget(handle);
+					rendererDestroyFrameBuffer(handle);
 				}
 				}
 				break;
 				break;
 
 
@@ -1647,7 +1644,7 @@ namespace bgfx
 				break;
 				break;
 
 
 			default:
 			default:
-				BX_CHECK(false, "WTF!");
+				BX_CHECK(false, "Invalid command: %d", command);
 				break;
 				break;
 			}
 			}
 		} while (!end);
 		} while (!end);
@@ -1876,11 +1873,10 @@ namespace bgfx
 		_width   = bx::uint32_max(1, _width);
 		_width   = bx::uint32_max(1, _width);
 		_height  = bx::uint32_max(1, _height);
 		_height  = bx::uint32_max(1, _height);
 		_depth   = bx::uint32_max(1, _depth);
 		_depth   = bx::uint32_max(1, _depth);
-		_numMips = bx::uint32_max(1, _numMips);
 
 
-		uint32_t width = _width;
+		uint32_t width  = _width;
 		uint32_t height = _height;
 		uint32_t height = _height;
-		uint32_t depth = _depth;
+		uint32_t depth  = _depth;
 
 
 		uint32_t bpp = getBitsPerPixel(_format);
 		uint32_t bpp = getBitsPerPixel(_format);
 		uint32_t size = 0;
 		uint32_t size = 0;
@@ -1918,6 +1914,8 @@ namespace bgfx
 	{
 	{
 		BGFX_CHECK_MAIN_THREAD();
 		BGFX_CHECK_MAIN_THREAD();
 
 
+		_numMips = bx::uint32_max(1, _numMips);
+
 #if BGFX_CONFIG_DEBUG
 #if BGFX_CONFIG_DEBUG
 		if (NULL != _mem)
 		if (NULL != _mem)
 		{
 		{
@@ -1958,6 +1956,8 @@ namespace bgfx
 		BGFX_CHECK_MAIN_THREAD();
 		BGFX_CHECK_MAIN_THREAD();
 		BX_CHECK(0 != (g_caps.supported & BGFX_CAPS_TEXTURE_3D), "Texture3D is not supported! Use bgfx::getCaps to check backend renderer capabilities.");
 		BX_CHECK(0 != (g_caps.supported & BGFX_CAPS_TEXTURE_3D), "Texture3D is not supported! Use bgfx::getCaps to check backend renderer capabilities.");
 
 
+		_numMips = bx::uint32_max(1, _numMips);
+
 #if BGFX_CONFIG_DEBUG
 #if BGFX_CONFIG_DEBUG
 		if (NULL != _mem)
 		if (NULL != _mem)
 		{
 		{
@@ -1997,6 +1997,8 @@ namespace bgfx
 	{
 	{
 		BGFX_CHECK_MAIN_THREAD();
 		BGFX_CHECK_MAIN_THREAD();
 
 
+		_numMips = bx::uint32_max(1, _numMips);
+
 #if BGFX_CONFIG_DEBUG
 #if BGFX_CONFIG_DEBUG
 		if (NULL != _mem)
 		if (NULL != _mem)
 		{
 		{
@@ -2085,17 +2087,33 @@ namespace bgfx
 		}
 		}
 	}
 	}
 
 
-	RenderTargetHandle createRenderTarget(uint16_t _width, uint16_t _height, uint32_t _flags, uint32_t _textureFlags)
+	FrameBufferHandle createFrameBuffer(uint16_t _width, uint16_t _height, TextureFormat::Enum _format, uint32_t _textureFlags)
+	{
+		_textureFlags |= _textureFlags&BGFX_TEXTURE_RT_MSAA_MASK ? 0 : BGFX_TEXTURE_RT;
+		TextureHandle th = createTexture2D(_width, _height, 1, _format, _textureFlags);
+		return createFrameBuffer(1, &th, true);
+	}
+
+	FrameBufferHandle createFrameBuffer(uint8_t _num, TextureHandle* _handles, bool _destroyTextures)
 	{
 	{
 		BGFX_CHECK_MAIN_THREAD();
 		BGFX_CHECK_MAIN_THREAD();
-		BX_WARN(0 != _width && 0 != _height, "Render target resolution width or height cannot be 0 (width %d, height %d).", _width, _height);
-		return s_ctx->createRenderTarget(bx::uint16_max(1, _width), bx::uint16_max(1, _height), _flags, _textureFlags);
+		BX_CHECK(NULL != _handles, "_handles can't be NULL");
+		FrameBufferHandle handle = s_ctx->createFrameBuffer(_num, _handles);
+		if (_destroyTextures)
+		{
+			for (uint32_t ii = 0; ii < _num; ++ii)
+			{
+				destroyTexture(_handles[ii]);
+			}
+		}
+
+		return handle;
 	}
 	}
 
 
-	void destroyRenderTarget(RenderTargetHandle _handle)
+	void destroyFrameBuffer(FrameBufferHandle _handle)
 	{
 	{
 		BGFX_CHECK_MAIN_THREAD();
 		BGFX_CHECK_MAIN_THREAD();
-		s_ctx->destroyRenderTarget(_handle);
+		s_ctx->destroyFrameBuffer(_handle);
 	}
 	}
 
 
 	UniformHandle createUniform(const char* _name, UniformType::Enum _type, uint16_t _num)
 	UniformHandle createUniform(const char* _name, UniformType::Enum _type, uint16_t _num)
@@ -2164,16 +2182,16 @@ namespace bgfx
 		s_ctx->setViewSeqMask(_viewMask, _enabled);
 		s_ctx->setViewSeqMask(_viewMask, _enabled);
 	}
 	}
 
 
-	void setViewRenderTarget(uint8_t _id, RenderTargetHandle _handle)
+	void setViewFrameBuffer(uint8_t _id, FrameBufferHandle _handle)
 	{
 	{
 		BGFX_CHECK_MAIN_THREAD();
 		BGFX_CHECK_MAIN_THREAD();
-		s_ctx->setViewRenderTarget(_id, _handle);
+		s_ctx->setViewFrameBuffer(_id, _handle);
 	}
 	}
 
 
-	void setViewRenderTargetMask(uint32_t _mask, RenderTargetHandle _handle)
+	void setViewFrameBufferMask(uint32_t _mask, FrameBufferHandle _handle)
 	{
 	{
 		BGFX_CHECK_MAIN_THREAD();
 		BGFX_CHECK_MAIN_THREAD();
-		s_ctx->setViewRenderTargetMask(_mask, _handle);
+		s_ctx->setViewFrameBufferMask(_mask, _handle);
 	}
 	}
 
 
 	void setViewTransform(uint8_t _id, const void* _view, const void* _proj, uint8_t _other)
 	void setViewTransform(uint8_t _id, const void* _view, const void* _proj, uint8_t _other)
@@ -2293,10 +2311,10 @@ namespace bgfx
 		s_ctx->setTexture(_stage, _sampler, _handle, _flags);
 		s_ctx->setTexture(_stage, _sampler, _handle, _flags);
 	}
 	}
 
 
-	void setTexture(uint8_t _stage, UniformHandle _sampler, RenderTargetHandle _handle, bool _depth, uint32_t _flags)
+	void setTexture(uint8_t _stage, UniformHandle _sampler, FrameBufferHandle _handle, uint8_t _attachment, uint32_t _flags)
 	{
 	{
 		BGFX_CHECK_MAIN_THREAD();
 		BGFX_CHECK_MAIN_THREAD();
-		s_ctx->setTexture(_stage, _sampler, _handle, _depth, _flags);
+		s_ctx->setTexture(_stage, _sampler, _handle, _attachment, _flags);
 	}
 	}
 
 
 	uint32_t submit(uint8_t _id, int32_t _depth)
 	uint32_t submit(uint8_t _id, int32_t _depth)

+ 115 - 54
src/bgfx_p.h

@@ -139,8 +139,6 @@ namespace stl
 
 
 #define BGFX_SAMPLER_DEFAULT_FLAGS      UINT32_C(0x10000000)
 #define BGFX_SAMPLER_DEFAULT_FLAGS      UINT32_C(0x10000000)
 #define BGFX_SAMPLER_TEXTURE            UINT32_C(0x00000000)
 #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)
 #define BGFX_SAMPLER_TYPE_MASK          UINT32_C(0xc0000000)
 
 
 #if BGFX_CONFIG_RENDERER_DIRECT3D9
 #if BGFX_CONFIG_RENDERER_DIRECT3D9
@@ -512,7 +510,7 @@ namespace bgfx
 			CreateProgram,
 			CreateProgram,
 			CreateTexture,
 			CreateTexture,
 			UpdateTexture,
 			UpdateTexture,
-			CreateRenderTarget,
+			CreateFrameBuffer,
 			CreateUniform,
 			CreateUniform,
 			UpdateViewName,
 			UpdateViewName,
 			End,
 			End,
@@ -526,7 +524,7 @@ namespace bgfx
 			DestroyFragmentShader,
 			DestroyFragmentShader,
 			DestroyProgram,
 			DestroyProgram,
 			DestroyTexture,
 			DestroyTexture,
-			DestroyRenderTarget,
+			DestroyFrameBuffer,
 			DestroyUniform,
 			DestroyUniform,
 			SaveScreenShot,
 			SaveScreenShot,
 		};
 		};
@@ -542,6 +540,7 @@ namespace bgfx
 		template<typename Type>
 		template<typename Type>
 		void write(const Type& _in)
 		void write(const Type& _in)
 		{
 		{
+			align(BX_ALIGNOF(Type) );
 			write(reinterpret_cast<const uint8_t*>(&_in), sizeof(Type) );
 			write(reinterpret_cast<const uint8_t*>(&_in), sizeof(Type) );
 		}
 		}
 
 
@@ -555,6 +554,7 @@ namespace bgfx
 		template<typename Type>
 		template<typename Type>
 		void read(Type& _in)
 		void read(Type& _in)
 		{
 		{
+			align(BX_ALIGNOF(Type) );
 			read(reinterpret_cast<uint8_t*>(&_in), sizeof(Type) );
 			read(reinterpret_cast<uint8_t*>(&_in), sizeof(Type) );
 		}
 		}
 
 
@@ -566,6 +566,20 @@ namespace bgfx
 			return result;
 			return result;
 		}
 		}
 
 
+		template<typename Type>
+		void skip()
+		{
+			align(BX_ALIGNOF(Type) );
+			skip(sizeof(Type) );
+		}
+
+		void align(uint32_t _alignment)
+		{
+			const uint32_t mask = _alignment-1;
+			const uint32_t pos = (m_pos+mask) & (~mask);
+			m_pos = pos;
+		}
+
 		void reset()
 		void reset()
 		{
 		{
 			m_pos = 0;
 			m_pos = 0;
@@ -1176,23 +1190,6 @@ namespace bgfx
 			}
 			}
 		}
 		}
 
 
-		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 = 0
-						| (_depth ? BGFX_SAMPLER_RENDERTARGET_DEPTH : BGFX_SAMPLER_RENDERTARGET_COLOR)
-						| ( (_flags&BGFX_SAMPLER_TYPE_MASK) ? BGFX_SAMPLER_DEFAULT_FLAGS : _flags)
-						;
-
-			if (isValid(_sampler) )
-			{
-				uint32_t stage = _stage;
-				setUniform(_sampler, &stage);
-			}
-		}
-
 		void discard()
 		void discard()
 		{
 		{
 			m_discard = false;
 			m_discard = false;
@@ -1287,10 +1284,10 @@ namespace bgfx
 			++m_numFreeTextureHandles;
 			++m_numFreeTextureHandles;
 		}
 		}
 
 
-		void free(RenderTargetHandle _handle)
+		void free(FrameBufferHandle _handle)
 		{
 		{
-			m_freeRenderTargetHandle[m_numFreeRenderTargetHandles] = _handle;
-			++m_numFreeRenderTargetHandles;
+			m_freeFrameBufferHandle[m_numFreeFrameBufferHandles] = _handle;
+			++m_numFreeFrameBufferHandles;
 		}
 		}
 
 
 		void free(UniformHandle _handle)
 		void free(UniformHandle _handle)
@@ -1309,13 +1306,13 @@ namespace bgfx
 			m_numFreeFragmentShaderHandles = 0;
 			m_numFreeFragmentShaderHandles = 0;
 			m_numFreeProgramHandles = 0;
 			m_numFreeProgramHandles = 0;
 			m_numFreeTextureHandles = 0;
 			m_numFreeTextureHandles = 0;
-			m_numFreeRenderTargetHandles = 0;
+			m_numFreeFrameBufferHandles = 0;
 			m_numFreeUniformHandles = 0;
 			m_numFreeUniformHandles = 0;
 		}
 		}
 
 
 		SortKey m_key;
 		SortKey m_key;
 
 
-		RenderTargetHandle m_rt[BGFX_CONFIG_MAX_VIEWS];
+		FrameBufferHandle m_fb[BGFX_CONFIG_MAX_VIEWS];
 		Clear m_clear[BGFX_CONFIG_MAX_VIEWS];
 		Clear m_clear[BGFX_CONFIG_MAX_VIEWS];
 		Rect m_rect[BGFX_CONFIG_MAX_VIEWS];
 		Rect m_rect[BGFX_CONFIG_MAX_VIEWS];
 		Rect m_scissor[BGFX_CONFIG_MAX_VIEWS];
 		Rect m_scissor[BGFX_CONFIG_MAX_VIEWS];
@@ -1356,7 +1353,7 @@ namespace bgfx
 		uint16_t m_numFreeFragmentShaderHandles;
 		uint16_t m_numFreeFragmentShaderHandles;
 		uint16_t m_numFreeProgramHandles;
 		uint16_t m_numFreeProgramHandles;
 		uint16_t m_numFreeTextureHandles;
 		uint16_t m_numFreeTextureHandles;
-		uint16_t m_numFreeRenderTargetHandles;
+		uint16_t m_numFreeFrameBufferHandles;
 		uint16_t m_numFreeUniformHandles;
 		uint16_t m_numFreeUniformHandles;
 
 
 		IndexBufferHandle m_freeIndexBufferHandle[BGFX_CONFIG_MAX_INDEX_BUFFERS];
 		IndexBufferHandle m_freeIndexBufferHandle[BGFX_CONFIG_MAX_INDEX_BUFFERS];
@@ -1366,7 +1363,7 @@ namespace bgfx
 		FragmentShaderHandle m_freeFragmentShaderHandle[BGFX_CONFIG_MAX_FRAGMENT_SHADERS];
 		FragmentShaderHandle m_freeFragmentShaderHandle[BGFX_CONFIG_MAX_FRAGMENT_SHADERS];
 		ProgramHandle m_freeProgramHandle[BGFX_CONFIG_MAX_PROGRAMS];
 		ProgramHandle m_freeProgramHandle[BGFX_CONFIG_MAX_PROGRAMS];
 		TextureHandle m_freeTextureHandle[BGFX_CONFIG_MAX_TEXTURES];
 		TextureHandle m_freeTextureHandle[BGFX_CONFIG_MAX_TEXTURES];
-		RenderTargetHandle m_freeRenderTargetHandle[BGFX_CONFIG_MAX_RENDER_TARGETS];
+		FrameBufferHandle m_freeFrameBufferHandle[BGFX_CONFIG_MAX_FRAME_BUFFERS];
 		UniformHandle m_freeUniformHandle[BGFX_CONFIG_MAX_UNIFORMS];
 		UniformHandle m_freeUniformHandle[BGFX_CONFIG_MAX_UNIFORMS];
 		TextVideoMem* m_textVideoMem;
 		TextVideoMem* m_textVideoMem;
 
 
@@ -1601,7 +1598,7 @@ namespace bgfx
 			m_resolution.m_height = bx::uint32_max(1, _height);
 			m_resolution.m_height = bx::uint32_max(1, _height);
 			m_resolution.m_flags = _flags;
 			m_resolution.m_flags = _flags;
 
 
-			memset(m_rt, 0xff, sizeof(m_rt) );
+			memset(m_fb, 0xff, sizeof(m_fb) );
 		}
 		}
 
 
 		BGFX_API_FUNC(void setDebug(uint32_t _debug) )
 		BGFX_API_FUNC(void setDebug(uint32_t _debug) )
@@ -2185,6 +2182,9 @@ namespace bgfx
 			BX_WARN(isValid(handle), "Failed to allocate texture handle.");
 			BX_WARN(isValid(handle), "Failed to allocate texture handle.");
 			if (isValid(handle) )
 			if (isValid(handle) )
 			{
 			{
+				TextureRef& ref = m_textureRef[handle.idx];
+				ref.m_refCount = 1;
+
 				CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::CreateTexture);
 				CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::CreateTexture);
 				cmdbuf.write(handle);
 				cmdbuf.write(handle);
 				cmdbuf.write(_mem);
 				cmdbuf.write(_mem);
@@ -2196,9 +2196,31 @@ namespace bgfx
 
 
 		BGFX_API_FUNC(void destroyTexture(TextureHandle _handle) )
 		BGFX_API_FUNC(void destroyTexture(TextureHandle _handle) )
 		{
 		{
-			CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::DestroyTexture);
-			cmdbuf.write(_handle);
-			m_submit->free(_handle);
+			if (!isValid(_handle) )
+			{
+				BX_WARN(false, "Passing invalid texture handle to bgfx::destroyTexture");
+				return;
+			}
+
+			textureDecRef(_handle);
+		}
+
+		void textureIncRef(TextureHandle _handle)
+		{
+			TextureRef& ref = m_textureRef[_handle.idx];
+			++ref.m_refCount;
+		}
+
+		void textureDecRef(TextureHandle _handle)
+		{
+			TextureRef& ref = m_textureRef[_handle.idx];
+			int32_t refs = --ref.m_refCount;
+			if (0 == refs)
+			{
+				CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::DestroyTexture);
+				cmdbuf.write(_handle);
+				m_submit->free(_handle);
+			}
 		}
 		}
 
 
 		BGFX_API_FUNC(void updateTexture(TextureHandle _handle, uint8_t _side, uint8_t _mip, uint16_t _x, uint16_t _y, uint16_t _z, uint16_t _width, uint16_t _height, uint16_t _depth, uint16_t _pitch, const Memory* _mem) )
 		BGFX_API_FUNC(void updateTexture(TextureHandle _handle, uint8_t _side, uint8_t _mip, uint16_t _x, uint16_t _y, uint16_t _z, uint16_t _width, uint16_t _height, uint16_t _depth, uint16_t _pitch, const Memory* _mem) )
@@ -2219,29 +2241,48 @@ namespace bgfx
 			cmdbuf.write(_mem);
 			cmdbuf.write(_mem);
 		}
 		}
 
 
-		BGFX_API_FUNC(RenderTargetHandle createRenderTarget(uint16_t _width, uint16_t _height, uint32_t _flags, uint32_t _textureFlags) )
+		BGFX_API_FUNC(FrameBufferHandle createFrameBuffer(uint8_t _num, TextureHandle* _handles) )
 		{
 		{
-			RenderTargetHandle handle = { m_renderTargetHandle.alloc() };
+			FrameBufferHandle handle = { m_frameBufferHandle.alloc() };
 			BX_WARN(isValid(handle), "Failed to allocate render target handle.");
 			BX_WARN(isValid(handle), "Failed to allocate render target handle.");
 
 
 			if (isValid(handle) )
 			if (isValid(handle) )
 			{
 			{
-				CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::CreateRenderTarget);
+				CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::CreateFrameBuffer);
 				cmdbuf.write(handle);
 				cmdbuf.write(handle);
-				cmdbuf.write(_width);
-				cmdbuf.write(_height);
-				cmdbuf.write(_flags);
-				cmdbuf.write(_textureFlags);
+				cmdbuf.write(_num);
+
+				FrameBufferRef& ref = m_frameBufferRef[handle.idx];
+				memset(ref.m_th, 0xff, sizeof(ref.m_th) );
+				for (uint32_t ii = 0; ii < _num; ++ii)
+				{
+					TextureHandle handle = _handles[ii];
+
+					cmdbuf.write(handle);
+
+					ref.m_th[ii] = handle;
+					textureIncRef(handle);
+				}
 			}
 			}
 
 
 			return handle;
 			return handle;
 		}
 		}
 
 
-		BGFX_API_FUNC(void destroyRenderTarget(RenderTargetHandle _handle) )
+		BGFX_API_FUNC(void destroyFrameBuffer(FrameBufferHandle _handle) )
 		{
 		{
-			CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::DestroyRenderTarget);
+			CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::DestroyFrameBuffer);
 			cmdbuf.write(_handle);
 			cmdbuf.write(_handle);
 			m_submit->free(_handle);
 			m_submit->free(_handle);
+
+			FrameBufferRef& ref = m_frameBufferRef[_handle.idx];
+			for (uint32_t ii = 0; ii < BX_COUNTOF(ref.m_th); ++ii)
+			{
+				TextureHandle th = ref.m_th[ii];
+				if (isValid(th) )
+				{
+					textureDecRef(th);
+				}
+			}
 		}
 		}
 
 
 		BGFX_API_FUNC(UniformHandle createUniform(const char* _name, UniformType::Enum _type, uint16_t _num) )
 		BGFX_API_FUNC(UniformHandle createUniform(const char* _name, UniformType::Enum _type, uint16_t _num) )
@@ -2394,19 +2435,19 @@ namespace bgfx
 			}
 			}
 		}
 		}
 
 
-		BGFX_API_FUNC(void setViewRenderTarget(uint8_t _id, RenderTargetHandle _handle) )
+		BGFX_API_FUNC(void setViewFrameBuffer(uint8_t _id, FrameBufferHandle _handle) )
 		{
 		{
-			m_rt[_id] = _handle;
+			m_fb[_id] = _handle;
 		}
 		}
 
 
-		BGFX_API_FUNC(void setViewRenderTargetMask(uint32_t _viewMask, RenderTargetHandle _handle) )
+		BGFX_API_FUNC(void setViewFrameBufferMask(uint32_t _viewMask, FrameBufferHandle _handle) )
 		{
 		{
 			for (uint32_t view = 0, viewMask = _viewMask, ntz = bx::uint32_cnttz(_viewMask); 0 != viewMask; viewMask >>= 1, view += 1, ntz = bx::uint32_cnttz(viewMask) )
 			for (uint32_t view = 0, viewMask = _viewMask, ntz = bx::uint32_cnttz(_viewMask); 0 != viewMask; viewMask >>= 1, view += 1, ntz = bx::uint32_cnttz(viewMask) )
 			{
 			{
 				viewMask >>= ntz;
 				viewMask >>= ntz;
 				view += ntz;
 				view += ntz;
 
 
-				m_rt[view] = _handle;
+				m_fb[view] = _handle;
 			}
 			}
 		}
 		}
 
 
@@ -2540,9 +2581,17 @@ namespace bgfx
 			m_submit->setTexture(_stage, _sampler, _handle, _flags);
 			m_submit->setTexture(_stage, _sampler, _handle, _flags);
 		}
 		}
 
 
-		BGFX_API_FUNC(void setTexture(uint8_t _stage, UniformHandle _sampler, RenderTargetHandle _handle, bool _depth, uint32_t _flags) )
+		BGFX_API_FUNC(void setTexture(uint8_t _stage, UniformHandle _sampler, FrameBufferHandle _handle, uint8_t _attachment, uint32_t _flags) )
 		{
 		{
-			m_submit->setTexture(_stage, _sampler, _handle, _depth, _flags);
+			BX_CHECK(_attachment < g_caps.maxFBAttachments, "Frame buffer attachment index %d is invalid.", _attachment);
+			TextureHandle textureHandle = BGFX_INVALID_HANDLE;
+			if (isValid(_handle) )
+			{
+				textureHandle = m_frameBufferRef[_handle.idx].m_th[_attachment];
+				BX_CHECK(isValid(textureHandle), "Frame buffer texture %d is invalid.", _attachment);
+			}
+
+			m_submit->setTexture(_stage, _sampler, textureHandle, _flags);
 		}
 		}
 
 
 		BGFX_API_FUNC(uint32_t submit(uint8_t _id, int32_t _depth) )
 		BGFX_API_FUNC(uint32_t submit(uint8_t _id, int32_t _depth) )
@@ -2596,8 +2645,8 @@ namespace bgfx
 		void rendererUpdateTexture(TextureHandle _handle, uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem);
 		void rendererUpdateTexture(TextureHandle _handle, uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem);
 		void rendererUpdateTextureEnd();
 		void rendererUpdateTextureEnd();
 		void rendererDestroyTexture(TextureHandle _handle);
 		void rendererDestroyTexture(TextureHandle _handle);
-		void rendererCreateRenderTarget(RenderTargetHandle _handle, uint16_t _width, uint16_t _height, uint32_t _flags, uint32_t _textureFlags);
-		void rendererDestroyRenderTarget(RenderTargetHandle _handle);
+		void rendererCreateFrameBuffer(FrameBufferHandle _handle, uint8_t _num, const TextureHandle* _textureHandles);
+		void rendererDestroyFrameBuffer(FrameBufferHandle _handle);
 		void rendererCreateUniform(UniformHandle _handle, UniformType::Enum _type, uint16_t _num, const char* _name);
 		void rendererCreateUniform(UniformHandle _handle, UniformType::Enum _type, uint16_t _num, const char* _name);
 		void rendererDestroyUniform(UniformHandle _handle);
 		void rendererDestroyUniform(UniformHandle _handle);
 		void rendererSaveScreenShot(const char* _filePath);
 		void rendererSaveScreenShot(const char* _filePath);
@@ -2685,19 +2734,19 @@ namespace bgfx
 		bx::HandleAllocT<BGFX_CONFIG_MAX_FRAGMENT_SHADERS> m_fragmentShaderHandle;
 		bx::HandleAllocT<BGFX_CONFIG_MAX_FRAGMENT_SHADERS> m_fragmentShaderHandle;
 		bx::HandleAllocT<BGFX_CONFIG_MAX_PROGRAMS> m_programHandle;
 		bx::HandleAllocT<BGFX_CONFIG_MAX_PROGRAMS> m_programHandle;
 		bx::HandleAllocT<BGFX_CONFIG_MAX_TEXTURES> m_textureHandle;
 		bx::HandleAllocT<BGFX_CONFIG_MAX_TEXTURES> m_textureHandle;
-		bx::HandleAllocT<BGFX_CONFIG_MAX_RENDER_TARGETS> m_renderTargetHandle;
+		bx::HandleAllocT<BGFX_CONFIG_MAX_FRAME_BUFFERS> m_frameBufferHandle;
 		bx::HandleAllocT<BGFX_CONFIG_MAX_UNIFORMS> m_uniformHandle;
 		bx::HandleAllocT<BGFX_CONFIG_MAX_UNIFORMS> m_uniformHandle;
 
 
 		struct FragmentShaderRef
 		struct FragmentShaderRef
 		{
 		{
-			int32_t m_refCount;
 			uint32_t m_inputHash;
 			uint32_t m_inputHash;
+			int16_t m_refCount;
 		};
 		};
 		
 		
 		struct VertexShaderRef
 		struct VertexShaderRef
 		{
 		{
-			int32_t m_refCount;
 			uint32_t m_outputHash;
 			uint32_t m_outputHash;
+			int16_t m_refCount;
 		};
 		};
 
 
 		struct ProgramRef
 		struct ProgramRef
@@ -2708,9 +2757,19 @@ namespace bgfx
 
 
 		struct UniformRef
 		struct UniformRef
 		{
 		{
-			int32_t m_refCount;
 			UniformType::Enum m_type;
 			UniformType::Enum m_type;
 			uint16_t m_num;
 			uint16_t m_num;
+			int16_t m_refCount;
+		};
+
+		struct TextureRef
+		{
+			int16_t m_refCount;
+		};
+
+		struct FrameBufferRef
+		{
+			TextureHandle m_th[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS];
 		};
 		};
 
 
 		typedef stl::unordered_map<stl::string, UniformHandle> UniformHashMap;
 		typedef stl::unordered_map<stl::string, UniformHandle> UniformHashMap;
@@ -2719,9 +2778,11 @@ namespace bgfx
 		VertexShaderRef m_vertexShaderRef[BGFX_CONFIG_MAX_VERTEX_SHADERS];
 		VertexShaderRef m_vertexShaderRef[BGFX_CONFIG_MAX_VERTEX_SHADERS];
 		FragmentShaderRef m_fragmentShaderRef[BGFX_CONFIG_MAX_FRAGMENT_SHADERS];
 		FragmentShaderRef m_fragmentShaderRef[BGFX_CONFIG_MAX_FRAGMENT_SHADERS];
 		ProgramRef m_programRef[BGFX_CONFIG_MAX_PROGRAMS];
 		ProgramRef m_programRef[BGFX_CONFIG_MAX_PROGRAMS];
+		TextureRef m_textureRef[BGFX_CONFIG_MAX_TEXTURES];
+		FrameBufferRef m_frameBufferRef[BGFX_CONFIG_MAX_FRAME_BUFFERS];
 		VertexDeclRef m_declRef;
 		VertexDeclRef m_declRef;
 
 
-		RenderTargetHandle m_rt[BGFX_CONFIG_MAX_VIEWS];
+		FrameBufferHandle m_fb[BGFX_CONFIG_MAX_VIEWS];
 		Clear m_clear[BGFX_CONFIG_MAX_VIEWS];
 		Clear m_clear[BGFX_CONFIG_MAX_VIEWS];
 		Rect m_rect[BGFX_CONFIG_MAX_VIEWS];
 		Rect m_rect[BGFX_CONFIG_MAX_VIEWS];
 		Rect m_scissor[BGFX_CONFIG_MAX_VIEWS];
 		Rect m_scissor[BGFX_CONFIG_MAX_VIEWS];

+ 7 - 3
src/config.h

@@ -188,9 +188,13 @@
 #	define BGFX_CONFIG_MAX_TEXTURES (4<<10)
 #	define BGFX_CONFIG_MAX_TEXTURES (4<<10)
 #endif // BGFX_CONFIG_MAX_TEXTURES
 #endif // BGFX_CONFIG_MAX_TEXTURES
 
 
-#ifndef BGFX_CONFIG_MAX_RENDER_TARGETS
-#	define BGFX_CONFIG_MAX_RENDER_TARGETS 64
-#endif // BGFX_CONFIG_MAX_RENDER_TARGETS
+#ifndef BGFX_CONFIG_MAX_FRAME_BUFFERS
+#	define BGFX_CONFIG_MAX_FRAME_BUFFERS 64
+#endif // BGFX_CONFIG_MAX_FRAME_BUFFERS
+
+#ifndef BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS
+#	define BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS 4
+#endif // BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS
 
 
 #ifndef BGFX_CONFIG_MAX_UNIFORMS
 #ifndef BGFX_CONFIG_MAX_UNIFORMS
 #	define BGFX_CONFIG_MAX_UNIFORMS 512
 #	define BGFX_CONFIG_MAX_UNIFORMS 512

+ 42 - 0
src/image.cpp

@@ -47,6 +47,43 @@ namespace bgfx
 		8,  // D0S8
 		8,  // D0S8
 	};
 	};
 
 
+	static const char* s_textureFormatName[TextureFormat::Count] =
+	{
+		"BC1",       // BC1
+		"BC2",       // BC2
+		"BC3",       // BC3
+		"BC4",       // BC4
+		"BC5",       // BC5
+		"ETC1",      // ETC1
+		"ETC2",      // ETC2
+		"ETC2A",     // ETC2A
+		"ETC2A1",    // ETC2A1
+		"PTC12",     // PTC12
+		"PTC14",     // PTC14
+		"PTC12A",    // PTC12A
+		"PTC14A",    // PTC14A
+		"PTC22",     // PTC22
+		"PTC24",     // PTC24
+		"<unknown>", // Unknown
+		"L8",        // L8
+		"BGRA8",     // BGRA8
+		"RGBA16",    // RGBA16
+		"RGBA16F",   // RGBA16F
+		"R5G6B5",    // R5G6B5
+		"RGBA4",     // RGBA4
+		"RGB5A1",    // RGB5A1
+		"RGB10A2",   // RGB10A2
+		"<unknown>", // UnknownDepth
+		"D16",       // D16
+		"D24",       // D24
+		"D24S8",     // D24S8
+		"D32",       // D32
+		"D16F",      // D16F
+		"D24F",      // D24F
+		"D32F",      // D32F
+		"D0S8",      // D0S8
+	};
+
 	bool isCompressed(TextureFormat::Enum _format)
 	bool isCompressed(TextureFormat::Enum _format)
 	{
 	{
 		return _format < TextureFormat::Unknown;
 		return _format < TextureFormat::Unknown;
@@ -71,6 +108,11 @@ namespace bgfx
 		return s_bitsPerPixel[_format];
 		return s_bitsPerPixel[_format];
 	}
 	}
 
 
+	const char* getName(TextureFormat::Enum _format)
+	{
+		return s_textureFormatName[_format];
+	}
+
 	void imageSolid(uint32_t _width, uint32_t _height, uint32_t _solid, void* _dst)
 	void imageSolid(uint32_t _width, uint32_t _height, uint32_t _solid, void* _dst)
 	{
 	{
 		uint32_t* dst = (uint32_t*)_dst;
 		uint32_t* dst = (uint32_t*)_dst;

+ 3 - 0
src/image.h

@@ -51,6 +51,9 @@ namespace bgfx
 	///
 	///
 	uint32_t getBitsPerPixel(TextureFormat::Enum _format);
 	uint32_t getBitsPerPixel(TextureFormat::Enum _format);
 
 
+	///
+	const char* getName(TextureFormat::Enum _format);
+
 	///
 	///
 	void imageSolid(uint32_t _width, uint32_t _height, uint32_t _solid, void* _dst);
 	void imageSolid(uint32_t _width, uint32_t _height, uint32_t _solid, void* _dst);
 
 

+ 171 - 155
src/renderer_d3d11.cpp

@@ -187,6 +187,8 @@ namespace bgfx
 	struct TextureFormatInfo
 	struct TextureFormatInfo
 	{
 	{
 		DXGI_FORMAT m_fmt;
 		DXGI_FORMAT m_fmt;
+		DXGI_FORMAT m_fmtSrv;
+		DXGI_FORMAT m_fmtDsv;
 	};
 	};
 
 
 #ifndef DXGI_FORMAT_B4G4R4A4_UNORM
 #ifndef DXGI_FORMAT_B4G4R4A4_UNORM
@@ -198,39 +200,39 @@ namespace bgfx
 
 
 	static const TextureFormatInfo s_textureFormat[TextureFormat::Count] =
 	static const TextureFormatInfo s_textureFormat[TextureFormat::Count] =
 	{
 	{
-		{ DXGI_FORMAT_BC1_UNORM          }, // BC1 
-		{ DXGI_FORMAT_BC2_UNORM          }, // BC2
-		{ DXGI_FORMAT_BC3_UNORM          }, // BC3
-		{ DXGI_FORMAT_BC4_UNORM          }, // BC4
-		{ DXGI_FORMAT_BC5_UNORM          }, // BC5
-		{ DXGI_FORMAT_UNKNOWN            }, // ETC1
-		{ DXGI_FORMAT_UNKNOWN            }, // ETC2
-		{ DXGI_FORMAT_UNKNOWN            }, // ETC2A
-		{ DXGI_FORMAT_UNKNOWN            }, // ETC2A1
-		{ DXGI_FORMAT_UNKNOWN            }, // PTC12
-		{ DXGI_FORMAT_UNKNOWN            }, // PTC14
-		{ DXGI_FORMAT_UNKNOWN            }, // PTC12A
-		{ DXGI_FORMAT_UNKNOWN            }, // PTC14A
-		{ DXGI_FORMAT_UNKNOWN            }, // PTC22
-		{ DXGI_FORMAT_UNKNOWN            }, // PTC24
-		{ DXGI_FORMAT_UNKNOWN            }, // Unknown
-		{ DXGI_FORMAT_R8_UNORM           }, // L8
-		{ DXGI_FORMAT_B8G8R8A8_UNORM     }, // BGRA8
-		{ DXGI_FORMAT_R16G16B16A16_UNORM }, // RGBA16
-		{ DXGI_FORMAT_R16G16B16A16_FLOAT }, // RGBA16F
-		{ DXGI_FORMAT_B5G6R5_UNORM       }, // R5G6B5
-		{ DXGI_FORMAT_B4G4R4A4_UNORM     }, // RGBA4
-		{ DXGI_FORMAT_B5G5R5A1_UNORM     }, // RGB5A1
-		{ DXGI_FORMAT_R10G10B10A2_UNORM  }, // RGB10A2
-		{ DXGI_FORMAT_UNKNOWN            }, // UnknownDepth
-		{ DXGI_FORMAT_D16_UNORM          }, // D16
-		{ DXGI_FORMAT_D24_UNORM_S8_UINT  }, // D24
-		{ DXGI_FORMAT_D24_UNORM_S8_UINT  }, // D24S8
-		{ DXGI_FORMAT_D24_UNORM_S8_UINT  }, // D32
-		{ DXGI_FORMAT_D32_FLOAT,         }, // D16F
-		{ DXGI_FORMAT_D32_FLOAT,         }, // D24F
-		{ DXGI_FORMAT_D32_FLOAT,         }, // D32F
-		{ DXGI_FORMAT_D24_UNORM_S8_UINT  }, // D0S8
+		{ DXGI_FORMAT_BC1_UNORM,          DXGI_FORMAT_BC1_UNORM,             DXGI_FORMAT_UNKNOWN           }, // BC1 
+		{ DXGI_FORMAT_BC2_UNORM,          DXGI_FORMAT_BC2_UNORM,             DXGI_FORMAT_UNKNOWN           }, // BC2
+		{ DXGI_FORMAT_BC3_UNORM,          DXGI_FORMAT_BC3_UNORM,             DXGI_FORMAT_UNKNOWN           }, // BC3
+		{ DXGI_FORMAT_BC4_UNORM,          DXGI_FORMAT_BC4_UNORM,             DXGI_FORMAT_UNKNOWN           }, // BC4
+		{ DXGI_FORMAT_BC5_UNORM,          DXGI_FORMAT_BC5_UNORM,             DXGI_FORMAT_UNKNOWN           }, // BC5
+		{ DXGI_FORMAT_UNKNOWN,            DXGI_FORMAT_UNKNOWN,               DXGI_FORMAT_UNKNOWN           }, // ETC1
+		{ DXGI_FORMAT_UNKNOWN,            DXGI_FORMAT_UNKNOWN,               DXGI_FORMAT_UNKNOWN           }, // ETC2
+		{ DXGI_FORMAT_UNKNOWN,            DXGI_FORMAT_UNKNOWN,               DXGI_FORMAT_UNKNOWN           }, // ETC2A
+		{ DXGI_FORMAT_UNKNOWN,            DXGI_FORMAT_UNKNOWN,               DXGI_FORMAT_UNKNOWN           }, // ETC2A1
+		{ DXGI_FORMAT_UNKNOWN,            DXGI_FORMAT_UNKNOWN,               DXGI_FORMAT_UNKNOWN           }, // PTC12
+		{ DXGI_FORMAT_UNKNOWN,            DXGI_FORMAT_UNKNOWN,               DXGI_FORMAT_UNKNOWN           }, // PTC14
+		{ DXGI_FORMAT_UNKNOWN,            DXGI_FORMAT_UNKNOWN,               DXGI_FORMAT_UNKNOWN           }, // PTC12A
+		{ DXGI_FORMAT_UNKNOWN,            DXGI_FORMAT_UNKNOWN,               DXGI_FORMAT_UNKNOWN           }, // PTC14A
+		{ DXGI_FORMAT_UNKNOWN,            DXGI_FORMAT_UNKNOWN,               DXGI_FORMAT_UNKNOWN           }, // PTC22
+		{ DXGI_FORMAT_UNKNOWN,            DXGI_FORMAT_UNKNOWN,               DXGI_FORMAT_UNKNOWN           }, // PTC24
+		{ DXGI_FORMAT_UNKNOWN,            DXGI_FORMAT_UNKNOWN,               DXGI_FORMAT_UNKNOWN           }, // Unknown
+		{ DXGI_FORMAT_R8_UNORM,           DXGI_FORMAT_R8_UNORM,              DXGI_FORMAT_UNKNOWN           }, // L8
+		{ DXGI_FORMAT_B8G8R8A8_UNORM,     DXGI_FORMAT_B8G8R8A8_UNORM,        DXGI_FORMAT_UNKNOWN           }, // BGRA8
+		{ DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM,    DXGI_FORMAT_UNKNOWN           }, // RGBA16
+		{ DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT,    DXGI_FORMAT_UNKNOWN           }, // RGBA16F
+		{ DXGI_FORMAT_B5G6R5_UNORM,       DXGI_FORMAT_B5G6R5_UNORM,          DXGI_FORMAT_UNKNOWN           }, // R5G6B5
+		{ DXGI_FORMAT_B4G4R4A4_UNORM,     DXGI_FORMAT_B4G4R4A4_UNORM,        DXGI_FORMAT_UNKNOWN           }, // RGBA4
+		{ DXGI_FORMAT_B5G5R5A1_UNORM,     DXGI_FORMAT_B5G5R5A1_UNORM,        DXGI_FORMAT_UNKNOWN           }, // RGB5A1
+		{ DXGI_FORMAT_R10G10B10A2_UNORM,  DXGI_FORMAT_R10G10B10A2_UNORM,     DXGI_FORMAT_UNKNOWN           }, // RGB10A2
+		{ DXGI_FORMAT_UNKNOWN,            DXGI_FORMAT_UNKNOWN,               DXGI_FORMAT_UNKNOWN           }, // UnknownDepth
+		{ DXGI_FORMAT_R16_TYPELESS,       DXGI_FORMAT_R16_UNORM,             DXGI_FORMAT_D16_UNORM         }, // D16
+		{ DXGI_FORMAT_R24G8_TYPELESS,     DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_D24_UNORM_S8_UINT }, // D24
+		{ DXGI_FORMAT_R24G8_TYPELESS,     DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_D24_UNORM_S8_UINT }, // D24S8
+		{ DXGI_FORMAT_R24G8_TYPELESS,     DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_D24_UNORM_S8_UINT }, // D32
+		{ DXGI_FORMAT_R32_TYPELESS,       DXGI_FORMAT_R32_FLOAT,             DXGI_FORMAT_D32_FLOAT         }, // D16F
+		{ DXGI_FORMAT_R32_TYPELESS,       DXGI_FORMAT_R32_FLOAT,             DXGI_FORMAT_D32_FLOAT         }, // D24F
+		{ DXGI_FORMAT_R32_TYPELESS,       DXGI_FORMAT_R32_FLOAT,             DXGI_FORMAT_D32_FLOAT         }, // D32F
+		{ DXGI_FORMAT_R24G8_TYPELESS,     DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_D24_UNORM_S8_UINT }, // D0S8
 	};
 	};
 
 
 	static const D3D11_INPUT_ELEMENT_DESC s_attrib[Attrib::Count] =
 	static const D3D11_INPUT_ELEMENT_DESC s_attrib[Attrib::Count] =
@@ -352,9 +354,12 @@ namespace bgfx
 			: m_captureTexture(NULL)
 			: m_captureTexture(NULL)
 			, m_captureResolve(NULL)
 			, m_captureResolve(NULL)
 			, m_wireframe(false)
 			, m_wireframe(false)
+			, m_flags(BGFX_RESET_NONE)
 			, m_vsChanges(0)
 			, m_vsChanges(0)
 			, m_fsChanges(0)
 			, m_fsChanges(0)
+			, m_rtMsaa(false)
 		{
 		{
+			m_fbh.idx = invalidHandle;
 		}
 		}
 
 
 		void init()
 		void init()
@@ -513,12 +518,13 @@ namespace bgfx
 								| BGFX_CAPS_TEXTURE_FORMAT_BC5
 								| BGFX_CAPS_TEXTURE_FORMAT_BC5
 								| BGFX_CAPS_INSTANCING
 								| BGFX_CAPS_INSTANCING
 								| BGFX_CAPS_TEXTURE_3D
 								| BGFX_CAPS_TEXTURE_3D
-								| BGFX_CAPS_TEXTURE_DEPTH_MASK
 								| BGFX_CAPS_VERTEX_ATTRIB_HALF
 								| BGFX_CAPS_VERTEX_ATTRIB_HALF
 								| BGFX_CAPS_FRAGMENT_DEPTH
 								| BGFX_CAPS_FRAGMENT_DEPTH
 								);
 								);
-			g_caps.maxTextureSize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
+			g_caps.maxTextureSize   = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
+			g_caps.maxFBAttachments = bx::uint32_min(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS);
 
 
+			updateMsaa();
 			postReset();
 			postReset();
 		}
 		}
 
 
@@ -555,11 +561,6 @@ namespace bgfx
 				m_textures[ii].destroy();
 				m_textures[ii].destroy();
 			}
 			}
 
 
- 			for (uint32_t ii = 0; ii < BX_COUNTOF(m_renderTargets); ++ii)
- 			{
- 				m_renderTargets[ii].destroy();
- 			}
-
 			for (uint32_t ii = 0; ii < BX_COUNTOF(m_uniforms); ++ii)
 			for (uint32_t ii = 0; ii < BX_COUNTOF(m_uniforms); ++ii)
 			{
 			{
 				m_uniforms[ii].destroy();
 				m_uniforms[ii].destroy();
@@ -744,13 +745,13 @@ namespace bgfx
 			}
 			}
 		}
 		}
 
 
-		void setRenderTarget(RenderTargetHandle _rt, bool _msaa = true)
+		void setFrameBuffer(FrameBufferHandle _fbh, bool _msaa = true)
 		{
 		{
 			BX_UNUSED(_msaa);
 			BX_UNUSED(_msaa);
-			if (!isValid(_rt) )
+			if (!isValid(_fbh) )
 			{
 			{
 				m_deviceCtx->OMSetRenderTargets(1, &m_backBufferColor, m_backBufferDepthStencil);
 				m_deviceCtx->OMSetRenderTargets(1, &m_backBufferColor, m_backBufferDepthStencil);
-				
+
 				m_currentColor = m_backBufferColor;
 				m_currentColor = m_backBufferColor;
 				m_currentDepthStencil = m_backBufferDepthStencil;
 				m_currentDepthStencil = m_backBufferDepthStencil;
 			}
 			}
@@ -758,12 +759,23 @@ namespace bgfx
 			{
 			{
 				invalidateTextureStage();
 				invalidateTextureStage();
 
 
-				RenderTarget& renderTarget = m_renderTargets[_rt.idx];
-				m_deviceCtx->OMSetRenderTargets(1, &renderTarget.m_rtv, renderTarget.m_dsv);
+				FrameBuffer& frameBuffer = m_frameBuffers[_fbh.idx];
+				m_deviceCtx->OMSetRenderTargets(frameBuffer.m_num, frameBuffer.m_rtv, frameBuffer.m_dsv);
 
 
-				m_currentColor = renderTarget.m_rtv;
-				m_currentDepthStencil = renderTarget.m_dsv;
+				m_currentColor = frameBuffer.m_rtv[0];
+				m_currentDepthStencil = frameBuffer.m_dsv;
+			}
+
+			if (isValid(m_fbh)
+			&&  m_fbh.idx != _fbh.idx
+			&&  m_rtMsaa)
+			{
+				FrameBuffer& frameBuffer = m_frameBuffers[m_fbh.idx];
+				frameBuffer.resolve();
 			}
 			}
+
+			m_fbh = _fbh;
+			m_rtMsaa = _msaa;
 		}
 		}
 
 
 		void clear(const Clear& _clear)
 		void clear(const Clear& _clear)
@@ -1200,7 +1212,7 @@ namespace bgfx
 		Program m_program[BGFX_CONFIG_MAX_PROGRAMS];
 		Program m_program[BGFX_CONFIG_MAX_PROGRAMS];
 		Texture m_textures[BGFX_CONFIG_MAX_TEXTURES];
 		Texture m_textures[BGFX_CONFIG_MAX_TEXTURES];
 		VertexDecl m_vertexDecls[BGFX_CONFIG_MAX_VERTEX_DECLS];
 		VertexDecl m_vertexDecls[BGFX_CONFIG_MAX_VERTEX_DECLS];
-		RenderTarget m_renderTargets[BGFX_CONFIG_MAX_RENDER_TARGETS];
+		FrameBuffer m_frameBuffers[BGFX_CONFIG_MAX_FRAME_BUFFERS];
 		UniformBuffer m_uniforms[BGFX_CONFIG_MAX_UNIFORMS];
 		UniformBuffer m_uniforms[BGFX_CONFIG_MAX_UNIFORMS];
 		UniformBuffer m_predefinedUniforms[PredefinedUniform::Count];
 		UniformBuffer m_predefinedUniforms[PredefinedUniform::Count];
 		UniformRegistry m_uniformReg;
 		UniformRegistry m_uniformReg;
@@ -1212,7 +1224,6 @@ namespace bgfx
 		StateCacheT<ID3D11SamplerState> m_samplerStateCache;
 		StateCacheT<ID3D11SamplerState> m_samplerStateCache;
 
 
 		TextVideoMem m_textVideoMem;
 		TextVideoMem m_textVideoMem;
-		RenderTargetHandle m_rt;
 
 
 		TextureStage m_textureStage;
 		TextureStage m_textureStage;
 
 
@@ -1223,6 +1234,9 @@ namespace bgfx
 
 
 		uint32_t m_vsChanges;
 		uint32_t m_vsChanges;
 		uint32_t m_fsChanges;
 		uint32_t m_fsChanges;
+
+		FrameBufferHandle m_fbh;
+		bool m_rtMsaa;
 	};
 	};
 
 
 	static RendererContext* s_renderCtx;
 	static RendererContext* s_renderCtx;
@@ -1398,8 +1412,8 @@ namespace bgfx
 		uint32_t width = s_renderCtx->m_scd.BufferDesc.Width;
 		uint32_t width = s_renderCtx->m_scd.BufferDesc.Width;
 		uint32_t height = s_renderCtx->m_scd.BufferDesc.Height;
 		uint32_t height = s_renderCtx->m_scd.BufferDesc.Height;
 
 
-		RenderTargetHandle rt = BGFX_INVALID_HANDLE;
-		s_renderCtx->setRenderTarget(rt, false);
+		FrameBufferHandle fbh = BGFX_INVALID_HANDLE;
+		s_renderCtx->setFrameBuffer(fbh, false);
 
 
 		D3D11_VIEWPORT vp;
 		D3D11_VIEWPORT vp;
 		vp.TopLeftX = 0;
 		vp.TopLeftX = 0;
@@ -1686,6 +1700,7 @@ namespace bgfx
 
 
 		if (imageParse(imageContainer, _mem->data, _mem->size) )
 		if (imageParse(imageContainer, _mem->data, _mem->size) )
 		{
 		{
+			m_flags = _flags;
 			m_requestedFormat = (uint8_t)imageContainer.m_format;
 			m_requestedFormat = (uint8_t)imageContainer.m_format;
 			m_textureFormat   = (uint8_t)imageContainer.m_format;
 			m_textureFormat   = (uint8_t)imageContainer.m_format;
 
 
@@ -1699,8 +1714,6 @@ namespace bgfx
 				bpp = 32;
 				bpp = 32;
 			}
 			}
 
 
-			DXGI_FORMAT format = s_textureFormat[m_textureFormat].m_fmt;
-
 			if (imageContainer.m_cubeMap)
 			if (imageContainer.m_cubeMap)
 			{
 			{
 				m_type = TextureCube;
 				m_type = TextureCube;
@@ -1769,7 +1782,14 @@ namespace bgfx
 
 
 			D3D11_SHADER_RESOURCE_VIEW_DESC srvd;
 			D3D11_SHADER_RESOURCE_VIEW_DESC srvd;
 			memset(&srvd, 0, sizeof(srvd) );
 			memset(&srvd, 0, sizeof(srvd) );
-			srvd.Format = format;
+			srvd.Format = s_textureFormat[m_textureFormat].m_fmtSrv;
+
+			const DXGI_FORMAT format = s_textureFormat[m_textureFormat].m_fmt;
+
+			const bool bufferOnly   = 0 != (m_flags&BGFX_TEXTURE_RT_BUFFER_ONLY);
+			const bool renderTarget = 0 != (m_flags&BGFX_TEXTURE_RT_MASK);
+			const uint32_t msaaQuality = bx::uint32_satsub( (m_flags&BGFX_TEXTURE_RT_MSAA_MASK)>>BGFX_TEXTURE_RT_MSAA_SHIFT, 1);
+			const DXGI_SAMPLE_DESC& msaa = s_msaa[msaaQuality];
 
 
 			switch (m_type)
 			switch (m_type)
 			{
 			{
@@ -1780,13 +1800,23 @@ namespace bgfx
 					desc.Width = imageContainer.m_width;
 					desc.Width = imageContainer.m_width;
 					desc.Height = imageContainer.m_height;
 					desc.Height = imageContainer.m_height;
 					desc.MipLevels = imageContainer.m_numMips;
 					desc.MipLevels = imageContainer.m_numMips;
-					desc.Format = srvd.Format;
-					desc.SampleDesc.Count = 1;
-					desc.SampleDesc.Quality = 0;
+					desc.Format = format;
+					desc.SampleDesc = msaa;
 					desc.Usage = kk == 0 ? D3D11_USAGE_DEFAULT : D3D11_USAGE_IMMUTABLE;
 					desc.Usage = kk == 0 ? D3D11_USAGE_DEFAULT : D3D11_USAGE_IMMUTABLE;
-					desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+					desc.BindFlags = bufferOnly ? 0 : D3D11_BIND_SHADER_RESOURCE;
 					desc.CPUAccessFlags = 0;
 					desc.CPUAccessFlags = 0;
 
 
+					if (isDepth( (TextureFormat::Enum)m_textureFormat) )
+					{
+						desc.BindFlags |= D3D11_BIND_DEPTH_STENCIL;
+						desc.Usage = D3D11_USAGE_DEFAULT;
+					}
+					else if (renderTarget)
+					{
+						desc.BindFlags |= D3D11_BIND_RENDER_TARGET;
+						desc.Usage = D3D11_USAGE_DEFAULT;
+					}
+
 					if (imageContainer.m_cubeMap)
 					if (imageContainer.m_cubeMap)
 					{
 					{
 						desc.ArraySize = 6;
 						desc.ArraySize = 6;
@@ -1798,7 +1828,7 @@ namespace bgfx
 					{
 					{
 						desc.ArraySize = 1;
 						desc.ArraySize = 1;
 						desc.MiscFlags = 0;
 						desc.MiscFlags = 0;
-						srvd.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+						srvd.ViewDimension = 1 < msaa.Count ? D3D11_SRV_DIMENSION_TEXTURE2DMS : D3D11_SRV_DIMENSION_TEXTURE2D;
 						srvd.Texture2D.MipLevels = imageContainer.m_numMips;
 						srvd.Texture2D.MipLevels = imageContainer.m_numMips;
 					}
 					}
 
 
@@ -1813,7 +1843,7 @@ namespace bgfx
 					desc.Height = imageContainer.m_height;
 					desc.Height = imageContainer.m_height;
 					desc.Depth = imageContainer.m_depth;
 					desc.Depth = imageContainer.m_depth;
 					desc.MipLevels = imageContainer.m_numMips;
 					desc.MipLevels = imageContainer.m_numMips;
-					desc.Format = srvd.Format;
+					desc.Format = format;
 					desc.Usage = kk == 0 ? D3D11_USAGE_DEFAULT : D3D11_USAGE_IMMUTABLE;
 					desc.Usage = kk == 0 ? D3D11_USAGE_DEFAULT : D3D11_USAGE_IMMUTABLE;
 					desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
 					desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
 					desc.CPUAccessFlags = 0;
 					desc.CPUAccessFlags = 0;
@@ -1827,7 +1857,10 @@ namespace bgfx
 				break;
 				break;
 			}
 			}
 
 
-			DX_CHECK(s_renderCtx->m_device->CreateShaderResourceView(m_ptr, &srvd, &m_srv) );
+			if (!bufferOnly)
+			{
+				DX_CHECK(s_renderCtx->m_device->CreateShaderResourceView(m_ptr, &srvd, &m_srv) );
+			}
 
 
 			if (convert
 			if (convert
 			&&  0 != kk)
 			&&  0 != kk)
@@ -1851,16 +1884,6 @@ namespace bgfx
 		DX_RELEASE(m_ptr, 0);
 		DX_RELEASE(m_ptr, 0);
 	}
 	}
 
 
-	void Texture::commit(uint8_t _stage, uint32_t _flags)
-	{
-		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, uint16_t _pitch, const Memory* _mem)
 	void Texture::update(uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem)
 	{
 	{
 		ID3D11DeviceContext* deviceCtx = s_renderCtx->m_deviceCtx;
 		ID3D11DeviceContext* deviceCtx = s_renderCtx->m_deviceCtx;
@@ -1898,74 +1921,74 @@ namespace bgfx
 		}
 		}
 	}
 	}
 
 
-	void RenderTarget::create(uint16_t _width, uint16_t _height, uint32_t _flags, uint32_t _textureFlags)
+	void Texture::commit(uint8_t _stage, uint32_t _flags)
 	{
 	{
-		m_width = _width;
-		m_height = _height;
-		m_flags = _flags;
-
-		uint32_t colorFormat = (m_flags&BGFX_RENDER_TARGET_COLOR_MASK)>>BGFX_RENDER_TARGET_COLOR_SHIFT;
-		uint32_t depthFormat = (m_flags&BGFX_RENDER_TARGET_DEPTH_MASK)>>BGFX_RENDER_TARGET_DEPTH_SHIFT;
-
-		D3D11_TEXTURE2D_DESC desc;
-		desc.Width = _width;
-		desc.Height = _height;
-		desc.MipLevels = 1;
-		desc.ArraySize = 1;
-		desc.Format = s_colorFormat[colorFormat];
-		desc.SampleDesc.Count = 1;
-		desc.SampleDesc.Quality = 0;
-		desc.Usage = D3D11_USAGE_DEFAULT;
-		desc.BindFlags = D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_RENDER_TARGET;
-		desc.CPUAccessFlags = 0;
-		desc.MiscFlags = 0;
+		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
+			;
+	}
 
 
-		DX_CHECK(s_renderCtx->m_device->CreateTexture2D(&desc, NULL, &m_colorTexture) );
-		DX_CHECK(s_renderCtx->m_device->CreateRenderTargetView(m_colorTexture, NULL, &m_rtv) );
-		DX_CHECK(s_renderCtx->m_device->CreateShaderResourceView(m_colorTexture, NULL, &m_srv) );
+	void Texture::resolve()
+	{
+	}
 
 
-		if (0 < depthFormat)
+	void FrameBuffer::create(uint8_t _num, const TextureHandle* _handles)
+	{
+		for (uint32_t ii = 0; ii < BX_COUNTOF(m_rtv); ++ii)
 		{
 		{
-			D3D11_TEXTURE2D_DESC desc;
-			desc.Width = _width;
-			desc.Height = _height;
-			desc.MipLevels = 1;
-			desc.ArraySize = 1;
-			desc.Format = s_depthFormat[depthFormat];
-			desc.SampleDesc.Count = 1;
-			desc.SampleDesc.Quality = 0;
-			desc.Usage = D3D11_USAGE_DEFAULT;
-			desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
-			desc.CPUAccessFlags = 0;
-			desc.MiscFlags = 0;
-			
-			DX_CHECK(s_renderCtx->m_device->CreateTexture2D(&desc, NULL, &m_depthTexture) );
-			DX_CHECK(s_renderCtx->m_device->CreateDepthStencilView(m_depthTexture, NULL, &m_dsv) );
-//			DX_CHECK(s_renderCtx->m_device->CreateShaderResourceView(m_depthTexture, NULL, &m_srv) );
+			m_rtv[ii] = NULL;
 		}
 		}
+		m_dsv = NULL;
 
 
-		m_sampler = s_renderCtx->getSamplerState(_textureFlags);
+		m_num = 0;
+		for (uint32_t ii = 0; ii < _num; ++ii)
+		{
+			TextureHandle handle = _handles[ii];
+			if (isValid(handle) )
+			{
+				const Texture& texture = s_renderCtx->m_textures[handle.idx];
+				if (isDepth( (TextureFormat::Enum)texture.m_textureFormat) )
+				{
+					BX_CHECK(NULL == m_dsv, "Frame buffer already has depth-stencil attached.");
+
+					const uint32_t msaaQuality = bx::uint32_satsub( (texture.m_flags&BGFX_TEXTURE_RT_MSAA_MASK)>>BGFX_TEXTURE_RT_MSAA_SHIFT, 1);
+					const DXGI_SAMPLE_DESC& msaa = s_msaa[msaaQuality];
+
+					D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
+					dsvDesc.Format = s_textureFormat[texture.m_textureFormat].m_fmtDsv;
+					dsvDesc.ViewDimension = 1 < msaa.Count ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D;
+					dsvDesc.Flags = 0;
+					dsvDesc.Texture2D.MipSlice = 0;
+					DX_CHECK(s_renderCtx->m_device->CreateDepthStencilView(texture.m_ptr, &dsvDesc, &m_dsv) );
+				}
+				else
+				{
+					DX_CHECK(s_renderCtx->m_device->CreateRenderTargetView(texture.m_ptr, NULL, &m_rtv[m_num]) );
+					DX_CHECK(s_renderCtx->m_device->CreateShaderResourceView(texture.m_ptr, NULL, &m_srv[m_num]) );
+					m_num++;
+				}
+			}
+		}
 	}
 	}
 
 
-	void RenderTarget::destroy()
+	void FrameBuffer::destroy()
 	{
 	{
-		DX_RELEASE(m_srv, 0);
-		DX_RELEASE(m_rtv, 0);
-		DX_RELEASE(m_colorTexture, 0);
+		for (uint32_t ii = 0, num = m_num; ii < num; ++ii)
+		{
+			DX_RELEASE(m_srv[ii], 0);
+			DX_RELEASE(m_rtv[ii], 0);
+		}
+
 		DX_RELEASE(m_dsv, 0);
 		DX_RELEASE(m_dsv, 0);
-		DX_RELEASE(m_depthTexture, 0);
 
 
-		m_flags = 0;
+		m_num = 0;
 	}
 	}
 
 
-	void RenderTarget::commit(uint8_t _stage, uint32_t _flags)
+	void FrameBuffer::resolve()
 	{
 	{
-		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)
 	void UniformBuffer::create(UniformType::Enum _type, uint16_t _num, bool _alloc)
@@ -2134,14 +2157,14 @@ namespace bgfx
 		s_renderCtx->m_textures[_handle.idx].destroy();
 		s_renderCtx->m_textures[_handle.idx].destroy();
 	}
 	}
 
 
-	void Context::rendererCreateRenderTarget(RenderTargetHandle _handle, uint16_t _width, uint16_t _height, uint32_t _flags, uint32_t _textureFlags)
+	void Context::rendererCreateFrameBuffer(FrameBufferHandle _handle, uint8_t _num, const TextureHandle* _textureHandles)
 	{
 	{
-		s_renderCtx->m_renderTargets[_handle.idx].create(_width, _height, _flags, _textureFlags);
+		s_renderCtx->m_frameBuffers[_handle.idx].create(_num, _textureHandles);
 	}
 	}
 
 
-	void Context::rendererDestroyRenderTarget(RenderTargetHandle _handle)
+	void Context::rendererDestroyFrameBuffer(FrameBufferHandle _handle)
 	{
 	{
-		s_renderCtx->m_renderTargets[_handle.idx].destroy();
+		s_renderCtx->m_frameBuffers[_handle.idx].destroy();
 	}
 	}
 
 
 	void Context::rendererCreateUniform(UniformHandle _handle, UniformType::Enum _type, uint16_t _num, const char* _name)
 	void Context::rendererCreateUniform(UniformHandle _handle, UniformType::Enum _type, uint16_t _num, const char* _name)
@@ -2224,7 +2247,7 @@ namespace bgfx
 		uint16_t programIdx = invalidHandle;
 		uint16_t programIdx = invalidHandle;
 		SortKey key;
 		SortKey key;
 		uint8_t view = 0xff;
 		uint8_t view = 0xff;
-		RenderTargetHandle rt = BGFX_INVALID_HANDLE;
+		FrameBufferHandle fbh = BGFX_INVALID_HANDLE;
 		float alphaRef = 0.0f;
 		float alphaRef = 0.0f;
 		D3D11_PRIMITIVE_TOPOLOGY primType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
 		D3D11_PRIMITIVE_TOPOLOGY primType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
 		deviceCtx->IASetPrimitiveTopology(primType);
 		deviceCtx->IASetPrimitiveTopology(primType);
@@ -2268,10 +2291,10 @@ namespace bgfx
 					view = key.m_view;
 					view = key.m_view;
 					programIdx = invalidHandle;
 					programIdx = invalidHandle;
 
 
-					if (m_render->m_rt[view].idx != rt.idx)
+					if (m_render->m_fb[view].idx != fbh.idx)
 					{
 					{
-						rt = m_render->m_rt[view];
-						s_renderCtx->setRenderTarget(rt);
+						fbh = m_render->m_fb[view];
+						s_renderCtx->setFrameBuffer(fbh);
 					}
 					}
 
 
 					const Rect& rect = m_render->m_rect[view];
 					const Rect& rect = m_render->m_rect[view];
@@ -2554,19 +2577,6 @@ namespace bgfx
 										texture.commit(stage, sampler.m_flags);
 										texture.commit(stage, sampler.m_flags);
 									}
 									}
 									break;
 									break;
-
-								case BGFX_SAMPLER_RENDERTARGET_COLOR:
-									{
-										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;
-									}
-									break;
 								}
 								}
 							}
 							}
 							else
 							else
@@ -2761,16 +2771,22 @@ namespace bgfx
 					);
 					);
 
 
 				pos = 10;
 				pos = 10;
-				tvm.printf(10, pos++, 0x8e, "      Frame: %7.3f, % 7.3f \x1f, % 7.3f \x1e [ms] / % 6.2f FPS%s"
+				tvm.printf(10, pos++, 0x8e, "       Frame: %7.3f, % 7.3f \x1f, % 7.3f \x1e [ms] / % 6.2f FPS "
 					, double(frameTime)*toMs
 					, double(frameTime)*toMs
 					, double(min)*toMs
 					, double(min)*toMs
 					, double(max)*toMs
 					, double(max)*toMs
 					, freq/frameTime
 					, freq/frameTime
-					, !!(m_resolution.m_flags&BGFX_RESET_VSYNC) ? " (vsync)" : ""
+					);
+
+				const uint32_t msaa = (m_resolution.m_flags&BGFX_RESET_MSAA_MASK)>>BGFX_RESET_MSAA_SHIFT;
+				tvm.printf(10, pos++, 0x8e, " Reset flags: [%c] vsync, [%c] MSAAx%d "
+					, !!(m_resolution.m_flags&BGFX_RESET_VSYNC) ? '\xfe' : ' '
+					, 0 != msaa ? '\xfe' : ' '
+					, 1<<msaa
 					);
 					);
 
 
 				double elapsedCpuMs = double(elapsed)*toMs;
 				double elapsedCpuMs = double(elapsed)*toMs;
-				tvm.printf(10, pos++, 0x8e, " Draw calls: %4d / CPU %3.4f [ms]"
+				tvm.printf(10, pos++, 0x8e, "  Draw calls: %4d / CPU %3.4f [ms]"
 					, m_render->m_num
 					, m_render->m_num
 					, elapsedCpuMs
 					, elapsedCpuMs
 					);
 					);
@@ -2781,16 +2797,16 @@ namespace bgfx
 					);
 					);
 
 
 				double captureMs = double(captureElapsed)*toMs;
 				double captureMs = double(captureElapsed)*toMs;
-				tvm.printf(10, pos++, 0x8e, "    Capture: %3.4f [ms]", captureMs);
-				tvm.printf(10, pos++, 0x8e, "    Indices: %7d", statsNumIndices);
-				tvm.printf(10, pos++, 0x8e, "   DVB size: %7d", m_render->m_vboffset);
-				tvm.printf(10, pos++, 0x8e, "   DIB size: %7d", m_render->m_iboffset);
+				tvm.printf(10, pos++, 0x8e, "     Capture: %3.4f [ms]", captureMs);
+				tvm.printf(10, pos++, 0x8e, "     Indices: %7d", statsNumIndices);
+				tvm.printf(10, pos++, 0x8e, "    DVB size: %7d", m_render->m_vboffset);
+				tvm.printf(10, pos++, 0x8e, "    DIB size: %7d", m_render->m_iboffset);
 
 
 				uint8_t attr[2] = { 0x89, 0x8a };
 				uint8_t attr[2] = { 0x89, 0x8a };
 				uint8_t attrIndex = m_render->m_waitSubmit < m_render->m_waitRender;
 				uint8_t attrIndex = m_render->m_waitSubmit < m_render->m_waitRender;
 
 
-				tvm.printf(10, pos++, attr[attrIndex&1], "Submit wait: %3.4f [ms]", m_render->m_waitSubmit*toMs);
-				tvm.printf(10, pos++, attr[(attrIndex+1)&1], "Render wait: %3.4f [ms]", m_render->m_waitRender*toMs);
+				tvm.printf(10, pos++, attr[attrIndex&1], " Submit wait: %3.4f [ms]", m_render->m_waitSubmit*toMs);
+				tvm.printf(10, pos++, attr[(attrIndex+1)&1], " Render wait: %3.4f [ms]", m_render->m_waitRender*toMs);
 
 
 				min = frameTime;
 				min = frameTime;
 				max = frameTime;
 				max = frameTime;

+ 10 - 22
src/renderer_d3d11.h

@@ -260,6 +260,7 @@ namespace bgfx
 		void destroy();
 		void destroy();
 		void update(uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem);
 		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 commit(uint8_t _stage, uint32_t _flags = BGFX_SAMPLER_DEFAULT_FLAGS);
+		void resolve();
 
 
 		union
 		union
 		{
 		{
@@ -270,41 +271,28 @@ namespace bgfx
 
 
 		ID3D11ShaderResourceView* m_srv;
 		ID3D11ShaderResourceView* m_srv;
 		ID3D11SamplerState* m_sampler;
 		ID3D11SamplerState* m_sampler;
+		uint32_t m_flags;
 		uint8_t m_type;
 		uint8_t m_type;
 		uint8_t m_requestedFormat;
 		uint8_t m_requestedFormat;
 		uint8_t m_textureFormat;
 		uint8_t m_textureFormat;
 		uint8_t m_numMips;
 		uint8_t m_numMips;
 	};
 	};
 
 
-	struct RenderTarget
+	struct FrameBuffer
 	{
 	{
-		RenderTarget()
-			: m_colorTexture(NULL)
- 			, m_depthTexture(NULL)
-			, m_rtv(NULL)
- 			, m_dsv(NULL)
-			, m_srv(NULL)
-			, m_width(0)
-			, m_height(0)
-			, m_flags(0)
-			, m_depthOnly(false)
+		FrameBuffer()
+			: m_num(0)
 		{
 		{
 		}
 		}
 
 
-		void create(uint16_t _width, uint16_t _height, uint32_t _flags, uint32_t _textureFlags);
+		void create(uint8_t _num, const TextureHandle* _handles);
 		void destroy();
 		void destroy();
- 		void commit(uint8_t _stage, uint32_t _flags = BGFX_SAMPLER_DEFAULT_FLAGS);
+		void resolve();
 
 
-		ID3D11Texture2D* m_colorTexture;
-		ID3D11Texture2D* m_depthTexture;
-		ID3D11RenderTargetView* m_rtv;
+		ID3D11RenderTargetView* m_rtv[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS-1];
+		ID3D11ShaderResourceView* m_srv[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS-1];
 		ID3D11DepthStencilView* m_dsv;
 		ID3D11DepthStencilView* m_dsv;
-		ID3D11ShaderResourceView* m_srv;
-		ID3D11SamplerState* m_sampler;
-		uint16_t m_width;
-		uint16_t m_height;
-		uint32_t m_flags;
-		bool m_depthOnly;
+		uint8_t m_num;
 	};
 	};
 
 
 } // namespace bgfx
 } // namespace bgfx

+ 305 - 199
src/renderer_d3d9.cpp

@@ -233,7 +233,7 @@ namespace bgfx
 #if defined(D3D_DISABLE_9EX)
 #if defined(D3D_DISABLE_9EX)
 		{ D3DFMT_UNKNOWN       }, // D0S8
 		{ D3DFMT_UNKNOWN       }, // D0S8
 #else
 #else
-		{ D3DFMT_S8_LOCKABLE   }, // D0S8
+		{ D3DFMT_INTZ /*D3DFMT_S8_LOCKABLE*/   }, // D0S8
 #endif // defined(D3D_DISABLE_9EX)
 #endif // defined(D3D_DISABLE_9EX)
 	};
 	};
 
 
@@ -278,7 +278,7 @@ namespace bgfx
 			, m_instancing(false)
 			, m_instancing(false)
 			, m_rtMsaa(false)
 			, m_rtMsaa(false)
 		{
 		{
-			m_rt.idx = invalidHandle;
+			m_fbh.idx = invalidHandle;
 		}
 		}
 
 
 		void init()
 		void init()
@@ -433,18 +433,21 @@ namespace bgfx
 			BX_TRACE("Max vertex shader constants: %d", m_caps.MaxVertexShaderConst);
 			BX_TRACE("Max vertex shader constants: %d", m_caps.MaxVertexShaderConst);
 			BX_TRACE("Max fragment shader 2.0 instr. slots: %d", m_caps.PS20Caps.NumInstructionSlots);
 			BX_TRACE("Max fragment shader 2.0 instr. slots: %d", m_caps.PS20Caps.NumInstructionSlots);
 			BX_TRACE("Max fragment shader 3.0 instr. slots: %d", m_caps.MaxPixelShader30InstructionSlots);
 			BX_TRACE("Max fragment shader 3.0 instr. slots: %d", m_caps.MaxPixelShader30InstructionSlots);
+			BX_TRACE("Num simultaneous render targets: %d", m_caps.NumSimultaneousRTs);
 
 
 			g_caps.supported |= ( 0
 			g_caps.supported |= ( 0
 								| BGFX_CAPS_TEXTURE_FORMAT_BC1
 								| BGFX_CAPS_TEXTURE_FORMAT_BC1
 								| BGFX_CAPS_TEXTURE_FORMAT_BC2
 								| BGFX_CAPS_TEXTURE_FORMAT_BC2
 								| BGFX_CAPS_TEXTURE_FORMAT_BC3
 								| BGFX_CAPS_TEXTURE_FORMAT_BC3
 								| BGFX_CAPS_TEXTURE_3D
 								| BGFX_CAPS_TEXTURE_3D
-								| BGFX_CAPS_TEXTURE_DEPTH_MASK
 								| BGFX_CAPS_VERTEX_ATTRIB_HALF
 								| BGFX_CAPS_VERTEX_ATTRIB_HALF
 								| BGFX_CAPS_FRAGMENT_DEPTH
 								| BGFX_CAPS_FRAGMENT_DEPTH
 								);
 								);
 			g_caps.maxTextureSize = bx::uint32_min(m_caps.MaxTextureWidth, m_caps.MaxTextureHeight);
 			g_caps.maxTextureSize = bx::uint32_min(m_caps.MaxTextureWidth, m_caps.MaxTextureHeight);
 
 
+			m_caps.NumSimultaneousRTs = bx::uint32_min(m_caps.NumSimultaneousRTs, BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS);
+			g_caps.maxFBAttachments = (uint8_t)m_caps.NumSimultaneousRTs;
+
 #if BGFX_CONFIG_RENDERER_USE_EXTENSIONS
 #if BGFX_CONFIG_RENDERER_USE_EXTENSIONS
 			BX_TRACE("Extended formats:");
 			BX_TRACE("Extended formats:");
 			for (uint32_t ii = 0; ii < ExtendedFormat::Count; ++ii)
 			for (uint32_t ii = 0; ii < ExtendedFormat::Count; ++ii)
@@ -474,6 +477,8 @@ namespace bgfx
 			g_caps.supported |= 0
 			g_caps.supported |= 0
 							 | (D3DFMT_UNKNOWN != s_textureFormat[TextureFormat::BC4].m_fmt ? BGFX_CAPS_TEXTURE_FORMAT_BC4 : 0)
 							 | (D3DFMT_UNKNOWN != s_textureFormat[TextureFormat::BC4].m_fmt ? BGFX_CAPS_TEXTURE_FORMAT_BC4 : 0)
 							 | (D3DFMT_UNKNOWN != s_textureFormat[TextureFormat::BC5].m_fmt ? BGFX_CAPS_TEXTURE_FORMAT_BC5 : 0)
 							 | (D3DFMT_UNKNOWN != s_textureFormat[TextureFormat::BC5].m_fmt ? BGFX_CAPS_TEXTURE_FORMAT_BC5 : 0)
+							 | (s_extendedFormats[ExtendedFormat::Df16].m_supported ? BGFX_CAPS_TEXTURE_FORMAT_D16F : 0)
+							 | (s_extendedFormats[ExtendedFormat::Df24].m_supported ? BGFX_CAPS_TEXTURE_FORMAT_D24F : 0)
 							 ;
 							 ;
 			g_caps.supported |= m_instancing ? BGFX_CAPS_INSTANCING : 0;
 			g_caps.supported |= m_instancing ? BGFX_CAPS_INSTANCING : 0;
 #endif // BGFX_CONFIG_RENDERER_USE_EXTENSIONS
 #endif // BGFX_CONFIG_RENDERER_USE_EXTENSIONS
@@ -565,11 +570,6 @@ namespace bgfx
 				m_vertexDecls[ii].destroy();
 				m_vertexDecls[ii].destroy();
 			}
 			}
 
 
-			for (uint32_t ii = 0; ii < BX_COUNTOF(m_renderTargets); ++ii)
-			{
-				m_renderTargets[ii].destroy();
-			}
-
 #if BGFX_CONFIG_RENDERER_DIRECT3D9EX
 #if BGFX_CONFIG_RENDERER_DIRECT3D9EX
 			if (NULL != m_d3d9ex)
 			if (NULL != m_d3d9ex)
 			{
 			{
@@ -658,41 +658,43 @@ namespace bgfx
 			}
 			}
 		}
 		}
 
 
-		void setRenderTarget(RenderTargetHandle _rt, bool _msaa = true)
+		void setFrameBuffer(FrameBufferHandle _fbh, bool _msaa = true)
 		{
 		{
-			if (!isValid(_rt) )
+			if (!isValid(_fbh) )
 			{
 			{
 				DX_CHECK(m_device->SetRenderTarget(0, m_backBufferColor) );
 				DX_CHECK(m_device->SetRenderTarget(0, m_backBufferColor) );
+				for (uint32_t ii = 1, num = g_caps.maxFBAttachments; ii < num; ++ii)
+				{
+					DX_CHECK(m_device->SetRenderTarget(ii, NULL) );
+				}
 				DX_CHECK(m_device->SetDepthStencilSurface(m_backBufferDepthStencil) );
 				DX_CHECK(m_device->SetDepthStencilSurface(m_backBufferDepthStencil) );
 			}
 			}
 			else
 			else
 			{
 			{
-				RenderTarget& renderTarget = m_renderTargets[_rt.idx];
-				if (NULL != renderTarget.m_rt)
+				const FrameBuffer& frameBuffer = m_frameBuffers[_fbh.idx];
+				for (uint32_t ii = 0, num = frameBuffer.m_num; ii < num; ++ii)
 				{
 				{
-					DX_CHECK(m_device->SetRenderTarget(0, renderTarget.m_rt) );
+					DX_CHECK(m_device->SetRenderTarget(ii, frameBuffer.m_color[ii]) );
 				}
 				}
-				else
+
+				for (uint32_t ii = frameBuffer.m_num, num = g_caps.maxFBAttachments; ii < num; ++ii)
 				{
 				{
-					DX_CHECK(m_device->SetRenderTarget(0, renderTarget.m_color) );
+					DX_CHECK(m_device->SetRenderTarget(ii, NULL) );
 				}
 				}
 
 
-				DX_CHECK(m_device->SetDepthStencilSurface(NULL != renderTarget.m_depth ? renderTarget.m_depth : m_backBufferDepthStencil) );
+				IDirect3DSurface9* depthStencil = frameBuffer.m_depthStencil;
+				DX_CHECK(m_device->SetDepthStencilSurface(NULL != depthStencil ? depthStencil : m_backBufferDepthStencil) );
 			}
 			}
 
 
-			if (isValid(m_rt)
-			&&  m_rt.idx != _rt.idx
+			if (isValid(m_fbh)
+			&&  m_fbh.idx != _fbh.idx
 			&&  m_rtMsaa)
 			&&  m_rtMsaa)
 			{
 			{
-				RenderTarget& renderTarget = m_renderTargets[m_rt.idx];
-				if (!renderTarget.m_depthOnly
-				&&  renderTarget.m_rt != NULL)
-				{
-					renderTarget.resolve();
-				}
+				FrameBuffer& frameBuffer = m_frameBuffers[m_fbh.idx];
+				frameBuffer.resolve();
 			}
 			}
 
 
-			m_rt = _rt;
+			m_fbh = _fbh;
 			m_rtMsaa = _msaa;
 			m_rtMsaa = _msaa;
 		}
 		}
 
 
@@ -781,6 +783,10 @@ namespace bgfx
 			}
 			}
 
 
 			DX_CHECK(m_device->SetRenderTarget(0, m_backBufferColor) );
 			DX_CHECK(m_device->SetRenderTarget(0, m_backBufferColor) );
+			for (uint32_t ii = 1, num = g_caps.maxFBAttachments; ii < num; ++ii)
+			{
+				DX_CHECK(m_device->SetRenderTarget(ii, NULL) );
+			}
 			DX_CHECK(m_device->SetDepthStencilSurface(m_backBufferDepthStencil) );
 			DX_CHECK(m_device->SetDepthStencilSurface(m_backBufferDepthStencil) );
 			DX_CHECK(m_device->SetVertexShader(NULL) );
 			DX_CHECK(m_device->SetVertexShader(NULL) );
 			DX_CHECK(m_device->SetPixelShader(NULL) );
 			DX_CHECK(m_device->SetPixelShader(NULL) );
@@ -802,9 +808,14 @@ namespace bgfx
 				m_vertexBuffers[ii].preReset();
 				m_vertexBuffers[ii].preReset();
 			}
 			}
 
 
-			for (uint32_t ii = 0; ii < BX_COUNTOF(m_renderTargets); ++ii)
+			for (uint32_t ii = 0; ii < BX_COUNTOF(m_frameBuffers); ++ii)
+			{
+				m_frameBuffers[ii].preReset();
+			}
+
+			for (uint32_t ii = 0; ii < BX_COUNTOF(m_textures); ++ii)
 			{
 			{
-				m_renderTargets[ii].preReset();
+				m_textures[ii].preReset();
 			}
 			}
 		}
 		}
 
 
@@ -825,9 +836,14 @@ namespace bgfx
 				m_vertexBuffers[ii].postReset();
 				m_vertexBuffers[ii].postReset();
 			}
 			}
 
 
-			for (uint32_t ii = 0; ii < BX_COUNTOF(m_renderTargets); ++ii)
+			for (uint32_t ii = 0; ii < BX_COUNTOF(m_textures); ++ii)
 			{
 			{
-				m_renderTargets[ii].postReset();
+				m_textures[ii].postReset();
+			}
+
+			for (uint32_t ii = 0; ii < BX_COUNTOF(m_frameBuffers); ++ii)
+			{
+				m_frameBuffers[ii].postReset();
 			}
 			}
 		}
 		}
 
 
@@ -1042,7 +1058,7 @@ namespace bgfx
 		Program m_program[BGFX_CONFIG_MAX_PROGRAMS];
 		Program m_program[BGFX_CONFIG_MAX_PROGRAMS];
 		Texture m_textures[BGFX_CONFIG_MAX_TEXTURES];
 		Texture m_textures[BGFX_CONFIG_MAX_TEXTURES];
 		VertexDeclaration m_vertexDecls[BGFX_CONFIG_MAX_VERTEX_DECLS];
 		VertexDeclaration m_vertexDecls[BGFX_CONFIG_MAX_VERTEX_DECLS];
-		RenderTarget m_renderTargets[BGFX_CONFIG_MAX_RENDER_TARGETS];
+		FrameBuffer m_frameBuffers[BGFX_CONFIG_MAX_FRAME_BUFFERS];
 		UniformRegistry m_uniformReg;
 		UniformRegistry m_uniformReg;
 		void* m_uniforms[BGFX_CONFIG_MAX_UNIFORMS];
 		void* m_uniforms[BGFX_CONFIG_MAX_UNIFORMS];
 
 
@@ -1055,7 +1071,8 @@ namespace bgfx
 		uint8_t m_updateTextureMip;
 		uint8_t m_updateTextureMip;
 
 
 		TextVideoMem m_textVideoMem;
 		TextVideoMem m_textVideoMem;
-		RenderTargetHandle m_rt;
+
+		FrameBufferHandle m_fbh;
 		bool m_rtMsaa;
 		bool m_rtMsaa;
 	};
 	};
 
 
@@ -1363,69 +1380,138 @@ namespace bgfx
 		}
 		}
 	}
 	}
 
 
-	void Texture::createTexture(uint32_t _width, uint32_t _height, uint8_t _numMips, D3DFORMAT _fmt)
+	void Texture::createTexture(uint32_t _width, uint32_t _height, uint8_t _numMips)
 	{
 	{
+		m_width = (uint16_t)_width;
+		m_height = (uint16_t)_height;
+		m_numMips = _numMips;
 		m_type = Texture2D;
 		m_type = Texture2D;
+		const TextureFormat::Enum fmt = (TextureFormat::Enum)m_textureFormat;
+
+		DWORD usage = 0;
+		D3DPOOL pool = s_renderCtx->m_pool;
+
+		const bool renderTarget = 0 != (m_flags&BGFX_TEXTURE_RT_MASK);
+		if (isDepth(fmt) )
+		{
+			usage = D3DUSAGE_DEPTHSTENCIL;
+			pool = D3DPOOL_DEFAULT;
+		}
+		else if (renderTarget)
+		{
+			usage = D3DUSAGE_RENDERTARGET;
+			pool = D3DPOOL_DEFAULT;
+		}
+
+		if (renderTarget)
+		{
+			uint32_t msaaQuality = ( (m_flags&BGFX_TEXTURE_RT_MSAA_MASK)>>BGFX_TEXTURE_RT_MSAA_SHIFT);
+			msaaQuality = bx::uint32_satsub(msaaQuality, 1);
+
+			bool bufferOnly = 0 != (m_flags&BGFX_TEXTURE_RT_BUFFER_ONLY);
+
+			if (0 != msaaQuality
+			||  bufferOnly)
+			{
+				const Msaa& msaa = s_msaa[msaaQuality];
+
+				if (isDepth(fmt) )
+				{
+					DX_CHECK(s_renderCtx->m_device->CreateDepthStencilSurface(
+						  m_width
+						, m_height
+						, s_textureFormat[m_textureFormat].m_fmt
+						, msaa.m_type
+						, msaa.m_quality
+						, FALSE
+						, &m_surface
+						, NULL
+						) );
+				}
+				else
+				{
+					DX_CHECK(s_renderCtx->m_device->CreateRenderTarget(
+						  m_width
+						, m_height
+						, s_textureFormat[m_textureFormat].m_fmt
+						, msaa.m_type
+						, msaa.m_quality
+						, FALSE
+						, &m_surface
+						, NULL
+						) );
+				}
+
+				if (bufferOnly)
+				{
+					// This is render buffer, there is no sampling, no need
+					// to create texture.
+					return;
+				}
+			}
+		}
 
 
 		DX_CHECK(s_renderCtx->m_device->CreateTexture(_width
 		DX_CHECK(s_renderCtx->m_device->CreateTexture(_width
 			, _height
 			, _height
 			, _numMips
 			, _numMips
-			, 0
-			, _fmt
-			, s_renderCtx->m_pool
+			, usage
+			, s_textureFormat[fmt].m_fmt
+			, pool
 			, &m_texture2d
 			, &m_texture2d
 			, NULL
 			, NULL
 			) );
 			) );
 
 
-		BGFX_FATAL(NULL != m_texture2d, Fatal::UnableToCreateTexture, "Failed to create texture (size: %dx%d, mips: %d, fmt: 0x%08x)."
+		BGFX_FATAL(NULL != m_texture2d, Fatal::UnableToCreateTexture, "Failed to create texture (size: %dx%d, mips: %d, fmt: %d)."
 			, _width
 			, _width
 			, _height
 			, _height
 			, _numMips
 			, _numMips
-			, _fmt
+			, getName(fmt)
 			);
 			);
 	}
 	}
 
 
-	void Texture::createVolumeTexture(uint32_t _width, uint32_t _height, uint32_t _depth, uint32_t _numMips, D3DFORMAT _fmt)
+	void Texture::createVolumeTexture(uint32_t _width, uint32_t _height, uint32_t _depth, uint32_t _numMips)
 	{
 	{
 		m_type = Texture3D;
 		m_type = Texture3D;
+		const TextureFormat::Enum fmt = (TextureFormat::Enum)m_textureFormat;
 
 
 		DX_CHECK(s_renderCtx->m_device->CreateVolumeTexture(_width
 		DX_CHECK(s_renderCtx->m_device->CreateVolumeTexture(_width
 			, _height
 			, _height
 			, _depth
 			, _depth
 			, _numMips
 			, _numMips
 			, 0
 			, 0
-			, _fmt
+			, s_textureFormat[fmt].m_fmt
 			, s_renderCtx->m_pool
 			, s_renderCtx->m_pool
 			, &m_texture3d
 			, &m_texture3d
 			, NULL
 			, NULL
 			) );
 			) );
 
 
-		BGFX_FATAL(NULL != m_texture3d, Fatal::UnableToCreateTexture, "Failed to create volume texture (size: %dx%dx%d, mips: %d, fmt: 0x%08x)."
+		BGFX_FATAL(NULL != m_texture3d, Fatal::UnableToCreateTexture, "Failed to create volume texture (size: %dx%dx%d, mips: %d, fmt: %s)."
 			, _width
 			, _width
 			, _height
 			, _height
 			, _depth
 			, _depth
 			, _numMips
 			, _numMips
-			, _fmt
+			, getName(fmt)
 			);
 			);
 	}
 	}
 
 
-	void Texture::createCubeTexture(uint32_t _edge, uint32_t _numMips, D3DFORMAT _fmt)
+	void Texture::createCubeTexture(uint32_t _edge, uint32_t _numMips)
 	{
 	{
 		m_type = TextureCube;
 		m_type = TextureCube;
+		const TextureFormat::Enum fmt = (TextureFormat::Enum)m_textureFormat;
 
 
 		DX_CHECK(s_renderCtx->m_device->CreateCubeTexture(_edge
 		DX_CHECK(s_renderCtx->m_device->CreateCubeTexture(_edge
 			, _numMips
 			, _numMips
 			, 0
 			, 0
-			, _fmt
+			, s_textureFormat[fmt].m_fmt
 			, s_renderCtx->m_pool
 			, s_renderCtx->m_pool
 			, &m_textureCube
 			, &m_textureCube
 			, NULL
 			, NULL
 			) );
 			) );
 
 
-		BGFX_FATAL(NULL != m_textureCube, Fatal::UnableToCreateTexture, "Failed to create cube texture (edge: %d, mips: %d, fmt: 0x%08x)."
+		BGFX_FATAL(NULL != m_textureCube, Fatal::UnableToCreateTexture, "Failed to create cube texture (edge: %d, mips: %d, fmt: %s)."
 			, _edge
 			, _edge
 			, _numMips
 			, _numMips
-			, _fmt
+			, getName(fmt)
 			);
 			);
 	}
 	}
 
 
@@ -1585,19 +1671,22 @@ namespace bgfx
 				bpp = 32;
 				bpp = 32;
 			}
 			}
 
 
-			D3DFORMAT format = s_textureFormat[m_textureFormat].m_fmt;
-
 			if (imageContainer.m_cubeMap)
 			if (imageContainer.m_cubeMap)
 			{
 			{
-				createCubeTexture(imageContainer.m_width, imageContainer.m_numMips, format);
+				createCubeTexture(imageContainer.m_width, imageContainer.m_numMips);
 			}
 			}
 			else if (imageContainer.m_depth > 1)
 			else if (imageContainer.m_depth > 1)
 			{
 			{
-				createVolumeTexture(imageContainer.m_width, imageContainer.m_height, imageContainer.m_depth, imageContainer.m_numMips, format);
+				createVolumeTexture(imageContainer.m_width, imageContainer.m_height, imageContainer.m_depth, imageContainer.m_numMips);
 			}
 			}
 			else
 			else
 			{
 			{
-				createTexture(imageContainer.m_width, imageContainer.m_height, imageContainer.m_numMips, format);
+				createTexture(imageContainer.m_width, imageContainer.m_height, imageContainer.m_numMips);
+			}
+
+			if (0 != (_flags&BGFX_TEXTURE_RT_BUFFER_ONLY) )
+			{
+				return;
 			}
 			}
 
 
 			// For BC4 and B5 in DX9 LockRect returns wrong number of
 			// For BC4 and B5 in DX9 LockRect returns wrong number of
@@ -1740,161 +1829,180 @@ namespace bgfx
 		DX_CHECK(s_renderCtx->m_device->SetTexture(_stage, m_ptr) );
 		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)
+	void Texture::resolve() const
 	{
 	{
-		m_width = _width;
-		m_height = _height;
-		m_flags = _flags;
-		m_textureFlags = (_textureFlags&(BGFX_TEXTURE_MIN_MASK|BGFX_TEXTURE_MAG_MASK) )
-						| BGFX_TEXTURE_U_CLAMP
-						| BGFX_TEXTURE_V_CLAMP
-						;
+		if (NULL != m_surface
+		&&  NULL != m_texture2d)
+		{
+			IDirect3DSurface9* surface;
+			DX_CHECK(m_texture2d->GetSurfaceLevel(0, &surface) );
+			DX_CHECK(s_renderCtx->m_device->StretchRect(m_surface
+				, NULL
+				, surface
+				, NULL
+				, D3DTEXF_LINEAR
+				) );
+			DX_RELEASE(surface, 1);
+		}
+	}
 
 
-		createTextures();
+	void Texture::preReset()
+	{
+		TextureFormat::Enum fmt = (TextureFormat::Enum)m_textureFormat;
+		if (TextureFormat::Unknown != fmt
+		&& (isDepth(fmt) || !!(m_flags&BGFX_TEXTURE_RT_MASK) ) )
+		{
+			DX_RELEASE(m_ptr, 0);
+			DX_RELEASE(m_surface, 0);
+		}
 	}
 	}
 
 
-	void RenderTarget::createTextures()
+	void Texture::postReset()
 	{
 	{
-		if (0 != m_flags)
+		TextureFormat::Enum fmt = (TextureFormat::Enum)m_textureFormat;
+		if (TextureFormat::Unknown != fmt
+		&& (isDepth(fmt) || !!(m_flags&BGFX_TEXTURE_RT_MASK) ) )
 		{
 		{
-			m_msaa = s_msaa[(m_flags&BGFX_RENDER_TARGET_MSAA_MASK)>>BGFX_RENDER_TARGET_MSAA_SHIFT];
-			const uint32_t colorFormat = (m_flags&BGFX_RENDER_TARGET_COLOR_MASK)>>BGFX_RENDER_TARGET_COLOR_SHIFT;
-			const uint32_t depthFormat = (m_flags&BGFX_RENDER_TARGET_DEPTH_MASK)>>BGFX_RENDER_TARGET_DEPTH_SHIFT;
-			m_depthOnly = (0 == colorFormat && 0 < depthFormat);
+			createTexture(m_width, m_height, m_numMips);
+		}
+	}
 
 
-			// CheckDeviceFormat D3DUSAGE_SRGBWRITE
+	void FrameBuffer::create(uint8_t _num, const TextureHandle* _handles)
+	{
+		for (uint32_t ii = 0; ii < BX_COUNTOF(m_color); ++ii)
+		{
+			m_color[ii] = NULL;
+		}
+		m_depthStencil = NULL;
 
 
-			if (m_depthOnly)
+		m_num = 0;
+		m_needResolve = false;
+		for (uint32_t ii = 0; ii < _num; ++ii)
+		{
+			TextureHandle handle = _handles[ii];
+			if (isValid(handle) )
 			{
 			{
-				DX_CHECK(s_renderCtx->m_device->CreateRenderTarget(1
-					, 1
-					, D3DFMT_R5G6B5
-					, D3DMULTISAMPLE_NONE
-					, 0
-					, false
-					, &m_rt
-					, NULL
-					) );
-
-				BGFX_FATAL(m_rt, Fatal::UnableToCreateRenderTarget, "Unable to create 1x1 render target.");
+				const Texture& texture = s_renderCtx->m_textures[handle.idx];
 
 
-				DX_CHECK(s_renderCtx->m_device->CreateTexture(m_width
-					, m_height
-					, 1
-					, D3DUSAGE_DEPTHSTENCIL
-					, s_depthFormat[depthFormat]
-					, D3DPOOL_DEFAULT
-					, &m_depthTexture
-					, NULL
-					) );
-
-				BGFX_FATAL(m_depthTexture, Fatal::UnableToCreateRenderTarget, "Unable to create depth texture.");
-
-				DX_CHECK(m_depthTexture->GetSurfaceLevel(0, &m_depth) );
-			}
-			else
-			{
-				if (D3DMULTISAMPLE_NONE != m_msaa.m_type)
+				if (isDepth( (TextureFormat::Enum)texture.m_textureFormat) )
 				{
 				{
-					DX_CHECK(s_renderCtx->m_device->CreateRenderTarget(m_width
-						, m_height
-						, s_colorFormat[colorFormat]
-						, m_msaa.m_type
-						, m_msaa.m_quality
-						, false
-						, &m_rt
-						, NULL
-						) );
-
-					BGFX_FATAL(m_rt, Fatal::UnableToCreateRenderTarget, "Unable to create MSAA render target.");
+					m_depthHandle = handle;
+					if (NULL != texture.m_surface)
+					{
+						m_depthStencil = texture.m_surface;
+						m_depthStencil->AddRef();
+					}
+					else
+					{
+						DX_CHECK(texture.m_texture2d->GetSurfaceLevel(0, &m_depthStencil) );
+					}
 				}
 				}
-
-				if (0 < colorFormat)
+				else
 				{
 				{
-					DX_CHECK(s_renderCtx->m_device->CreateTexture(m_width
-						, m_height
-						, 1
-						, D3DUSAGE_RENDERTARGET
-						, s_colorFormat[colorFormat]
-						, D3DPOOL_DEFAULT
-						, &m_colorTexture
-						, NULL
-						) );
-
-					BGFX_FATAL(m_colorTexture, Fatal::UnableToCreateRenderTarget, "Unable to create color render target.");
-
-					DX_CHECK(m_colorTexture->GetSurfaceLevel(0, &m_color) );
+					m_colorHandle[m_num] = handle;
+					if (NULL != texture.m_surface)
+					{
+						m_color[m_num] = texture.m_surface;
+						m_color[m_num]->AddRef();
+					}
+					else
+					{
+						DX_CHECK(texture.m_texture2d->GetSurfaceLevel(0, &m_color[m_num]) );
+					}
+					m_num++;
 				}
 				}
 
 
-				if (0 < depthFormat)
-				{
-					DX_CHECK(s_renderCtx->m_device->CreateDepthStencilSurface(m_width
-							, m_height
-							, s_depthFormat[depthFormat]
-							, m_msaa.m_type
-							, m_msaa.m_quality
-							, FALSE
-							, &m_depth
-							, NULL
-							) );
-
-					BGFX_FATAL(m_depth, Fatal::UnableToCreateRenderTarget, "Unable to create depth stencil surface.");
-				}
+				m_needResolve |= (NULL != texture.m_surface) && (NULL != texture.m_texture2d);
 			}
 			}
 		}
 		}
 	}
 	}
 
 
-	void RenderTarget::destroyTextures()
+	void FrameBuffer::destroy()
 	{
 	{
-		if (0 != m_flags)
+		for (uint32_t ii = 0, num = m_num; ii < num; ++ii)
 		{
 		{
-			if (m_depthOnly)
-			{
-				DX_RELEASE(m_rt, 0);
+			m_colorHandle[ii].idx = invalidHandle;
 
 
-				DX_RELEASE(m_depth, 1);
-				DX_RELEASE(m_depthTexture, 0);
-			}
-			else
+			IDirect3DSurface9* ptr = m_color[ii];
+			if (NULL != ptr)
 			{
 			{
-				uint32_t colorFormat = (m_flags&BGFX_RENDER_TARGET_COLOR_MASK)>>BGFX_RENDER_TARGET_COLOR_SHIFT;
-				uint32_t depthFormat = (m_flags&BGFX_RENDER_TARGET_DEPTH_MASK)>>BGFX_RENDER_TARGET_DEPTH_SHIFT;
+				ptr->Release();
+				m_color[ii] = NULL;
+			}
+		}
 
 
-				if (D3DMULTISAMPLE_NONE != m_msaa.m_type)
-				{
-					DX_RELEASE(m_rt, 0);
-				}
+		if (NULL != m_depthStencil)
+		{
+			m_depthStencil->Release();
+			m_depthStencil = NULL;
+		}
 
 
-				if (0 < colorFormat)
-				{
-					DX_RELEASE(m_color, 1);
-					DX_RELEASE(m_colorTexture, 0);
-				}
+		m_num = 0;
+		m_depthHandle.idx = invalidHandle;
+	}
 
 
-				if (0 < depthFormat)
-				{
-					DX_RELEASE(m_depth, 0);
-				}
+	void FrameBuffer::resolve() const
+	{
+		if (m_needResolve)
+		{
+			if (isValid(m_depthHandle) )
+			{
+				const Texture& texture = s_renderCtx->m_textures[m_depthHandle.idx];
+				texture.resolve();
+			}
+
+			for (uint32_t ii = 0, num = m_num; ii < num; ++ii)
+			{
+				const Texture& texture = s_renderCtx->m_textures[m_colorHandle[ii].idx];
+				texture.resolve();
 			}
 			}
 		}
 		}
 	}
 	}
 
 
-	void RenderTarget::commit(uint8_t _stage, uint32_t _textureFlags)
+	void FrameBuffer::preReset()
 	{
 	{
-		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) );
+		for (uint32_t ii = 0, num = m_num; ii < num; ++ii)
+		{
+			m_color[ii]->Release();
+			m_color[ii] = NULL;
+		}
+
+		if (isValid(m_depthHandle) )
+		{
+			m_depthStencil->Release();
+			m_depthStencil = NULL;
+		}
 	}
 	}
 
 
-	void RenderTarget::resolve()
+	void FrameBuffer::postReset()
 	{
 	{
-#if BX_PLATFORM_WINDOWS
-		DX_CHECK(s_renderCtx->m_device->StretchRect(m_rt
-				, NULL
-				, m_color
-				, NULL
-				, D3DTEXF_NONE
-				) );
-#endif // BX_PLATFORM_WINDOWS
+		for (uint32_t ii = 0, num = m_num; ii < num; ++ii)
+		{
+			Texture& texture = s_renderCtx->m_textures[m_colorHandle[ii].idx];
+			if (NULL != texture.m_surface)
+			{
+				m_color[ii] = texture.m_surface;
+				m_color[ii]->AddRef();
+			}
+			else
+			{
+				DX_CHECK(texture.m_texture2d->GetSurfaceLevel(0, &m_color[ii]) );
+			}
+		}
+
+		if (isValid(m_depthHandle) )
+		{
+			Texture& texture = s_renderCtx->m_textures[m_depthHandle.idx];
+			if (NULL != texture.m_surface)
+			{
+				m_depthStencil = texture.m_surface;
+				m_depthStencil->AddRef();
+			}
+			else
+			{
+				DX_CHECK(texture.m_texture2d->GetSurfaceLevel(0, &m_depthStencil) );
+			}
+		}
 	}
 	}
 
 
 	void ConstantBuffer::commit()
 	void ConstantBuffer::commit()
@@ -1971,8 +2079,8 @@ namespace bgfx
 		uint32_t width = s_renderCtx->m_params.BackBufferWidth;
 		uint32_t width = s_renderCtx->m_params.BackBufferWidth;
 		uint32_t height = s_renderCtx->m_params.BackBufferHeight;
 		uint32_t height = s_renderCtx->m_params.BackBufferHeight;
 
 
-		RenderTargetHandle rt = BGFX_INVALID_HANDLE;
-		s_renderCtx->setRenderTarget(rt, false);
+		FrameBufferHandle fbh = BGFX_INVALID_HANDLE;
+		s_renderCtx->setFrameBuffer(fbh, false);
 
 
 		D3DVIEWPORT9 vp;
 		D3DVIEWPORT9 vp;
 		vp.X = 0;
 		vp.X = 0;
@@ -2168,14 +2276,14 @@ namespace bgfx
 		s_renderCtx->m_textures[_handle.idx].destroy();
 		s_renderCtx->m_textures[_handle.idx].destroy();
 	}
 	}
 
 
-	void Context::rendererCreateRenderTarget(RenderTargetHandle _handle, uint16_t _width, uint16_t _height, uint32_t _flags, uint32_t _textureFlags)
+	void Context::rendererCreateFrameBuffer(FrameBufferHandle _handle, uint8_t _num, const TextureHandle* _textureHandles)
 	{
 	{
-		s_renderCtx->m_renderTargets[_handle.idx].create(_width, _height, _flags, _textureFlags);
+		s_renderCtx->m_frameBuffers[_handle.idx].create(_num, _textureHandles);
 	}
 	}
 
 
-	void Context::rendererDestroyRenderTarget(RenderTargetHandle _handle)
+	void Context::rendererDestroyFrameBuffer(FrameBufferHandle _handle)
 	{
 	{
-		s_renderCtx->m_renderTargets[_handle.idx].destroy();
+		s_renderCtx->m_frameBuffers[_handle.idx].destroy();
 	}
 	}
 
 
 	void Context::rendererCreateUniform(UniformHandle _handle, UniformType::Enum _type, uint16_t _num, const char* _name)
 	void Context::rendererCreateUniform(UniformHandle _handle, UniformType::Enum _type, uint16_t _num, const char* _name)
@@ -2260,7 +2368,7 @@ namespace bgfx
 		uint16_t programIdx = invalidHandle;
 		uint16_t programIdx = invalidHandle;
 		SortKey key;
 		SortKey key;
 		uint8_t view = 0xff;
 		uint8_t view = 0xff;
-		RenderTargetHandle rt = BGFX_INVALID_HANDLE;
+		FrameBufferHandle fbh = BGFX_INVALID_HANDLE;
 		float alphaRef = 0.0f;
 		float alphaRef = 0.0f;
 		uint32_t blendFactor = 0;
 		uint32_t blendFactor = 0;
 		D3DPRIMITIVETYPE primType = D3DPT_TRIANGLELIST;
 		D3DPRIMITIVETYPE primType = D3DPT_TRIANGLELIST;
@@ -2306,10 +2414,10 @@ namespace bgfx
 					view = key.m_view;
 					view = key.m_view;
 					programIdx = invalidHandle;
 					programIdx = invalidHandle;
 
 
-					if (m_render->m_rt[view].idx != rt.idx)
+					if (m_render->m_fb[view].idx != fbh.idx)
 					{
 					{
-						rt = m_render->m_rt[view];
-						s_renderCtx->setRenderTarget(rt);
+						fbh = m_render->m_fb[view];
+						s_renderCtx->setFrameBuffer(fbh);
 					}
 					}
 
 
 					const Rect& rect = m_render->m_rect[view];
 					const Rect& rect = m_render->m_rect[view];
@@ -2708,14 +2816,6 @@ namespace bgfx
 								case BGFX_SAMPLER_TEXTURE:
 								case BGFX_SAMPLER_TEXTURE:
 									s_renderCtx->m_textures[sampler.m_idx].commit(stage, sampler.m_flags);
 									s_renderCtx->m_textures[sampler.m_idx].commit(stage, sampler.m_flags);
 									break;
 									break;
-
-								case BGFX_SAMPLER_RENDERTARGET_COLOR:
-									s_renderCtx->m_renderTargets[sampler.m_idx].commit(stage, sampler.m_flags);
-									break;
-
-								case BGFX_SAMPLER_RENDERTARGET_DEPTH:
-//									id = s_renderCtx->m_renderTargets[sampler.m_idx].m_depth.m_id;
-									break;
 								}
 								}
 							}
 							}
 							else
 							else
@@ -2904,36 +3004,42 @@ namespace bgfx
 				tvm.printf(0, pos++, 0x0f, " Device: %s (%s)", identifier.Description, identifier.Driver);
 				tvm.printf(0, pos++, 0x0f, " Device: %s (%s)", identifier.Description, identifier.Driver);
 
 
 				pos = 10;
 				pos = 10;
-				tvm.printf(10, pos++, 0x8e, "      Frame: %7.3f, % 7.3f \x1f, % 7.3f \x1e [ms] / % 6.2f FPS%s"
+				tvm.printf(10, pos++, 0x8e, "       Frame: %7.3f, % 7.3f \x1f, % 7.3f \x1e [ms] / % 6.2f FPS "
 					, double(frameTime)*toMs
 					, double(frameTime)*toMs
 					, double(min)*toMs
 					, double(min)*toMs
 					, double(max)*toMs
 					, double(max)*toMs
 					, freq/frameTime
 					, freq/frameTime
-					, !!(m_resolution.m_flags&BGFX_RESET_VSYNC) ? " (vsync)" : ""
+					);
+
+				const uint32_t msaa = (m_resolution.m_flags&BGFX_RESET_MSAA_MASK)>>BGFX_RESET_MSAA_SHIFT;
+				tvm.printf(10, pos++, 0x8e, " Reset flags: [%c] vsync, [%c] MSAAx%d "
+					, !!(m_resolution.m_flags&BGFX_RESET_VSYNC) ? '\xfe' : ' '
+					, 0 != msaa ? '\xfe' : ' '
+					, 1<<msaa
 					);
 					);
 
 
 				double elapsedCpuMs = double(elapsed)*toMs;
 				double elapsedCpuMs = double(elapsed)*toMs;
-				tvm.printf(10, pos++, 0x8e, " Draw calls: %4d / CPU %3.4f [ms]"
+				tvm.printf(10, pos++, 0x8e, "  Draw calls: %4d / CPU %3.4f [ms]"
 					, m_render->m_num
 					, m_render->m_num
 					, elapsedCpuMs
 					, elapsedCpuMs
 					);
 					);
-				tvm.printf(10, pos++, 0x8e, "      Prims: %7d (#inst: %5d), submitted: %7d"
+				tvm.printf(10, pos++, 0x8e, "       Prims: %7d (#inst: %5d), submitted: %7d"
 					, statsNumPrimsRendered
 					, statsNumPrimsRendered
 					, statsNumInstances
 					, statsNumInstances
 					, statsNumPrimsSubmitted
 					, statsNumPrimsSubmitted
 					);
 					);
 
 
 				double captureMs = double(captureElapsed)*toMs;
 				double captureMs = double(captureElapsed)*toMs;
-				tvm.printf(10, pos++, 0x8e, "    Capture: %3.4f [ms]", captureMs);
-				tvm.printf(10, pos++, 0x8e, "    Indices: %7d", statsNumIndices);
-				tvm.printf(10, pos++, 0x8e, "   DVB size: %7d", m_render->m_vboffset);
-				tvm.printf(10, pos++, 0x8e, "   DIB size: %7d", m_render->m_iboffset);
+				tvm.printf(10, pos++, 0x8e, "     Capture: %3.4f [ms]", captureMs);
+				tvm.printf(10, pos++, 0x8e, "     Indices: %7d", statsNumIndices);
+				tvm.printf(10, pos++, 0x8e, "    DVB size: %7d", m_render->m_vboffset);
+				tvm.printf(10, pos++, 0x8e, "    DIB size: %7d", m_render->m_iboffset);
 
 
 				uint8_t attr[2] = { 0x89, 0x8a };
 				uint8_t attr[2] = { 0x89, 0x8a };
 				uint8_t attrIndex = m_render->m_waitSubmit < m_render->m_waitRender;
 				uint8_t attrIndex = m_render->m_waitSubmit < m_render->m_waitRender;
 
 
-				tvm.printf(10, pos++, attr[attrIndex&1], "Submit wait: %3.4f [ms]", m_render->m_waitSubmit*toMs);
-				tvm.printf(10, pos++, attr[(attrIndex+1)&1], "Render wait: %3.4f [ms]", m_render->m_waitRender*toMs);
+				tvm.printf(10, pos++, attr[attrIndex&1], " Submit wait: %3.4f [ms]", m_render->m_waitSubmit*toMs);
+				tvm.printf(10, pos++, attr[(attrIndex+1)&1], " Render wait: %3.4f [ms]", m_render->m_waitRender*toMs);
 
 
 				min = frameTime;
 				min = frameTime;
 				max = frameTime;
 				max = frameTime;

+ 31 - 47
src/renderer_d3d9.h

@@ -298,12 +298,14 @@ namespace bgfx
 
 
 		Texture()
 		Texture()
 			: m_ptr(NULL)
 			: m_ptr(NULL)
+			, m_surface(NULL)
+			, m_textureFormat(TextureFormat::Unknown)
 		{
 		{
 		}
 		}
 
 
-		void createTexture(uint32_t _width, uint32_t _height, uint8_t _numMips, D3DFORMAT _fmt);
-		void createVolumeTexture(uint32_t _width, uint32_t _height, uint32_t _depth, uint32_t _numMips, D3DFORMAT _fmt);
-		void createCubeTexture(uint32_t _edge, uint32_t _numMips, D3DFORMAT _fmt);
+		void createTexture(uint32_t _width, uint32_t _height, uint8_t _numMips);
+		void createVolumeTexture(uint32_t _width, uint32_t _height, uint32_t _depth, uint32_t _numMips);
+		void createCubeTexture(uint32_t _edge, uint32_t _numMips);
 
 
 		uint8_t* lock(uint8_t _side, uint8_t _lod, uint32_t& _pitch, uint32_t& _slicePitch, const Rect* _rect = NULL);
 		uint8_t* lock(uint8_t _side, uint8_t _lod, uint32_t& _pitch, uint32_t& _slicePitch, const Rect* _rect = NULL);
 		void unlock(uint8_t _side, uint8_t _lod);
 		void unlock(uint8_t _side, uint8_t _lod);
@@ -314,12 +316,18 @@ namespace bgfx
 		void destroy()
 		void destroy()
 		{
 		{
 			DX_RELEASE(m_ptr, 0);
 			DX_RELEASE(m_ptr, 0);
+			DX_RELEASE(m_surface, 0);
+			m_textureFormat = TextureFormat::Unknown;
 		}
 		}
 
 
 		void updateBegin(uint8_t _side, uint8_t _mip);
 		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, uint16_t _pitch, const Memory* _mem);
 		void update(uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem);
 		void updateEnd();
 		void updateEnd();
 		void commit(uint8_t _stage, uint32_t _flags = BGFX_SAMPLER_DEFAULT_FLAGS);
 		void commit(uint8_t _stage, uint32_t _flags = BGFX_SAMPLER_DEFAULT_FLAGS);
+		void resolve() const;
+
+		void preReset();
+		void postReset();
 	
 	
 		union
 		union
 		{
 		{
@@ -329,61 +337,37 @@ namespace bgfx
 			IDirect3DCubeTexture9* m_textureCube;
 			IDirect3DCubeTexture9* m_textureCube;
 		};
 		};
 
 
+		IDirect3DSurface9* m_surface;
 		uint32_t m_flags;
 		uint32_t m_flags;
+		uint16_t m_width;
+		uint16_t m_height;
+		uint8_t m_numMips;
 		uint8_t m_type;
 		uint8_t m_type;
 		uint8_t m_requestedFormat;
 		uint8_t m_requestedFormat;
 		uint8_t m_textureFormat;
 		uint8_t m_textureFormat;
 	};
 	};
 
 
-	struct RenderTarget
+	struct FrameBuffer
 	{
 	{
-		RenderTarget()
-			: m_rt(NULL)
-			, m_colorTexture(NULL)
-			, m_color(NULL)
-			, m_depthTexture(NULL)
-			, m_depth(NULL)
-			, m_width(0)
-			, m_height(0)
-			, m_flags(0)
-			, m_depthOnly(false)
+		FrameBuffer()
+			: m_num(0)
+			, m_needResolve(0)
 		{
 		{
+			m_depthHandle.idx = invalidHandle;
 		}
 		}
 
 
-		void create(uint16_t _width, uint16_t _height, uint32_t _flags, uint32_t _textureFlags);
-		void createTextures();
-		void destroyTextures();
-
-		void destroy()
-		{
-			destroyTextures();
-			m_flags = 0;
-		}
-
-		void preReset()
-		{
-			destroyTextures();
-		}
-
-		void postReset()
-		{
-			createTextures();
-		}
-
-		void commit(uint8_t _stage, uint32_t _textureFlags = BGFX_SAMPLER_DEFAULT_FLAGS);
-		void resolve();
+		void create(uint8_t _num, const TextureHandle* _handles);
+		void destroy();
+		void resolve() const;
+		void preReset();
+		void postReset();
 
 
-		Msaa m_msaa;
-		IDirect3DSurface9* m_rt;
-		IDirect3DTexture9* m_colorTexture;
-		IDirect3DSurface9* m_color;
-		IDirect3DTexture9* m_depthTexture;
-		IDirect3DSurface9* m_depth;
-		uint16_t m_width;
-		uint16_t m_height;
-		uint32_t m_flags;
-		uint32_t m_textureFlags;
-		bool m_depthOnly;
+		IDirect3DSurface9* m_color[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS-1];
+		IDirect3DSurface9* m_depthStencil;
+		TextureHandle m_colorHandle[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS-1];
+		TextureHandle m_depthHandle;
+		uint8_t m_num;
+		bool m_needResolve;
 	};
 	};
 
 
 } // namespace bgfx
 } // namespace bgfx

+ 206 - 334
src/renderer_gl.cpp

@@ -136,46 +136,6 @@ namespace bgfx
 		GL_BACK,
 		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 },
-	};
-
-	struct RenderTargetDepthFormat
-	{
-		GLenum m_internalFmt;
-		GLenum m_attachment;
-	};
-
-	static const RenderTargetDepthFormat s_depthFormat[] =
-	{
-		{ 0,                     0                           }, // ignored
-		{ GL_DEPTH_COMPONENT16,  GL_DEPTH_ATTACHMENT         }, // D16
-		{ GL_DEPTH_COMPONENT24,  GL_DEPTH_ATTACHMENT         }, // D24
-		{ GL_DEPTH24_STENCIL8,   GL_DEPTH_STENCIL_ATTACHMENT }, // D24S8
-		{ GL_DEPTH_COMPONENT32,  GL_DEPTH_ATTACHMENT         }, // D32
-		{ GL_DEPTH_COMPONENT32F, GL_DEPTH_ATTACHMENT         }, // D16F 
-		{ GL_DEPTH_COMPONENT32F, GL_DEPTH_ATTACHMENT         }, // D24F 
-		{ GL_DEPTH_COMPONENT32F, GL_DEPTH_ATTACHMENT         }, // D32F 
-		{ GL_STENCIL_INDEX8,     GL_STENCIL_ATTACHMENT       }, // D0S8
-	};
-
 	static const GLenum s_textureAddress[] =
 	static const GLenum s_textureAddress[] =
 	{
 	{
 		GL_REPEAT,
 		GL_REPEAT,
@@ -580,7 +540,7 @@ namespace bgfx
 			, m_backBufferFbo(0)
 			, m_backBufferFbo(0)
 			, m_msaaBackBufferFbo(0)
 			, m_msaaBackBufferFbo(0)
 		{
 		{
-			m_rt.idx = invalidHandle;
+			m_fbh.idx = invalidHandle;
 			memset(&m_resolution, 0, sizeof(m_resolution) );
 			memset(&m_resolution, 0, sizeof(m_resolution) );
 		}
 		}
 
 
@@ -603,31 +563,28 @@ namespace bgfx
 			}
 			}
 		}
 		}
 
 
-		uint32_t setRenderTarget(RenderTargetHandle _rt, uint32_t _height, bool _msaa = true)
+		uint32_t setFrameBuffer(FrameBufferHandle _fbh, uint32_t _height, bool _msaa = true)
 		{
 		{
-			if (isValid(m_rt)
-			&&  m_rt.idx != _rt.idx
+			if (isValid(m_fbh)
+			&&  m_fbh.idx != _fbh.idx
 			&&  m_rtMsaa)
 			&&  m_rtMsaa)
 			{
 			{
-				RenderTarget& renderTarget = m_renderTargets[m_rt.idx];
-				if (0 != renderTarget.m_fbo[1])
-				{
-					renderTarget.resolve();
-				}
+				FrameBuffer& frameBuffer = m_frameBuffers[m_fbh.idx];
+				frameBuffer.resolve();
 			}
 			}
 
 
-			if (!isValid(_rt) )
+			if (!isValid(_fbh) )
 			{
 			{
 				GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_msaaBackBufferFbo) );
 				GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_msaaBackBufferFbo) );
 			}
 			}
 			else
 			else
 			{
 			{
-				RenderTarget& renderTarget = m_renderTargets[_rt.idx];
-				GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, renderTarget.m_fbo[0]) );
-				_height = renderTarget.m_height;
+				FrameBuffer& frameBuffer = m_frameBuffers[_fbh.idx];
+				GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer.m_fbo[0]) );
+				_height = frameBuffer.m_height;
 			}
 			}
 
 
-			m_rt = _rt;
+			m_fbh = _fbh;
 			m_rtMsaa = _msaa;
 			m_rtMsaa = _msaa;
 
 
 			return _height;
 			return _height;
@@ -910,7 +867,7 @@ namespace bgfx
 		Program m_program[BGFX_CONFIG_MAX_PROGRAMS];
 		Program m_program[BGFX_CONFIG_MAX_PROGRAMS];
 		Texture m_textures[BGFX_CONFIG_MAX_TEXTURES];
 		Texture m_textures[BGFX_CONFIG_MAX_TEXTURES];
 		VertexDecl m_vertexDecls[BGFX_CONFIG_MAX_VERTEX_DECLS];
 		VertexDecl m_vertexDecls[BGFX_CONFIG_MAX_VERTEX_DECLS];
-		RenderTarget m_renderTargets[BGFX_CONFIG_MAX_RENDER_TARGETS];
+		FrameBuffer m_frameBuffers[BGFX_CONFIG_MAX_FRAME_BUFFERS];
 		UniformRegistry m_uniformReg;
 		UniformRegistry m_uniformReg;
 		void* m_uniforms[BGFX_CONFIG_MAX_UNIFORMS];
 		void* m_uniforms[BGFX_CONFIG_MAX_UNIFORMS];
 #if BGFX_CONFIG_RENDERER_OPENGL
 #if BGFX_CONFIG_RENDERER_OPENGL
@@ -923,9 +880,10 @@ namespace bgfx
 #endif // !BGFX_CONFIG_RENDERER_OPENGLES2
 #endif // !BGFX_CONFIG_RENDERER_OPENGLES2
 
 
 		TextVideoMem m_textVideoMem;
 		TextVideoMem m_textVideoMem;
-		RenderTargetHandle m_rt;
 		bool m_rtMsaa;
 		bool m_rtMsaa;
 
 
+		FrameBufferHandle m_fbh;
+
 		Resolution m_resolution;
 		Resolution m_resolution;
 		void* m_capture;
 		void* m_capture;
 		uint32_t m_captureSize;
 		uint32_t m_captureSize;
@@ -1399,44 +1357,101 @@ namespace bgfx
 		}
 		}
 	}
 	}
 
 
-	void Texture::init(GLenum _target, uint8_t _format, uint8_t _numMips, uint32_t _flags)
+	bool Texture::init(GLenum _target, uint32_t _width, uint32_t _height, uint8_t _format, uint8_t _numMips, uint32_t _flags)
 	{
 	{
 		m_target = _target;
 		m_target = _target;
 		m_numMips = _numMips;
 		m_numMips = _numMips;
 		m_flags = _flags;
 		m_flags = _flags;
 		m_currentFlags = UINT32_MAX;
 		m_currentFlags = UINT32_MAX;
+		m_width = _width;
+		m_height = _height;
 		m_requestedFormat = _format;
 		m_requestedFormat = _format;
 		m_textureFormat   = _format;
 		m_textureFormat   = _format;
 
 
-		GL_CHECK(glGenTextures(1, &m_id) );
-		BX_CHECK(0 != m_id, "Failed to generate texture id.");
-		GL_CHECK(glBindTexture(_target, m_id) );
+		const bool bufferOnly = 0 != (m_flags&BGFX_TEXTURE_RT_BUFFER_ONLY);
 
 
-		setSamplerState(_flags);
-
-		const TextureFormatInfo& tfi = s_textureFormat[_format];
-		m_fmt = tfi.m_fmt;
-		m_type = tfi.m_type;
+		if (!bufferOnly)
+		{
+			GL_CHECK(glGenTextures(1, &m_id) );
+			BX_CHECK(0 != m_id, "Failed to generate texture id.");
+			GL_CHECK(glBindTexture(_target, m_id) );
 
 
-		const bool compressed = TextureFormat::Unknown > _format;
-		const bool decompress = !tfi.m_supported && compressed;
+			setSamplerState(_flags);
 
 
-		if (decompress)
-		{
-			m_textureFormat = (uint8_t)TextureFormat::BGRA8;
-			const TextureFormatInfo& tfi = s_textureFormat[TextureFormat::BGRA8];
+			const TextureFormatInfo& tfi = s_textureFormat[_format];
 			m_fmt = tfi.m_fmt;
 			m_fmt = tfi.m_fmt;
 			m_type = tfi.m_type;
 			m_type = tfi.m_type;
-		}
+
+			const bool compressed = TextureFormat::Unknown > _format;
+			const bool decompress = !tfi.m_supported && compressed;
+
+			if (decompress)
+			{
+				m_textureFormat = (uint8_t)TextureFormat::BGRA8;
+				const TextureFormatInfo& tfi = s_textureFormat[TextureFormat::BGRA8];
+				m_fmt = tfi.m_fmt;
+				m_type = tfi.m_type;
+			}
 
 
 #if BGFX_CONFIG_RENDERER_OPENGL
 #if BGFX_CONFIG_RENDERER_OPENGL
-		if (GL_RGBA == m_fmt
-		&&  s_renderCtx->m_textureSwizzleSupport)
+			if (GL_RGBA == m_fmt
+				&&  s_renderCtx->m_textureSwizzleSupport)
+			{
+				GLint swizzleMask[] = { GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA };
+				GL_CHECK(glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask) );
+			}
+#endif // BGFX_CONFIG_RENDERER_OPENGL
+		}
+
+		const bool renderTarget = 0 != (m_flags&BGFX_TEXTURE_RT_MASK);
+
+		if (renderTarget)
 		{
 		{
-			GLint swizzleMask[] = { GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA };
-			GL_CHECK(glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask) );
+			uint32_t msaaQuality = ( (m_flags&BGFX_TEXTURE_RT_MSAA_MASK)>>BGFX_TEXTURE_RT_MSAA_SHIFT);
+			msaaQuality = bx::uint32_satsub(msaaQuality, 1);
+			msaaQuality = bx::uint32_min(s_renderCtx->m_maxMsaa, msaaQuality == 0 ? 0 : 1<<msaaQuality);
+
+			BX_TRACE("%p MSAA %d %s", this, msaaQuality, getName( (TextureFormat::Enum)m_textureFormat) );
+
+			if (0 != msaaQuality
+			||  bufferOnly)
+			{
+				GL_CHECK(glGenRenderbuffers(1, &m_rbo) );
+				BX_CHECK(0 != m_rbo, "Failed to generate renderbuffer id.");
+				GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, m_rbo) );
+
+				if (0 == msaaQuality)
+				{
+					GL_CHECK(glRenderbufferStorage(GL_RENDERBUFFER
+						, s_textureFormat[m_textureFormat].m_internalFmt
+						, _width
+						, _height
+						) );
+				}
+#if BGFX_CONFIG_RENDERER_OPENGL|BGFX_CONFIG_RENDERER_OPENGLES3
+				else
+				{
+					GL_CHECK(glRenderbufferStorageMultisample(GL_RENDERBUFFER
+						, msaaQuality
+						, s_textureFormat[m_textureFormat].m_internalFmt
+						, _width
+						, _height
+						) );
+				}
+#endif // BGFX_CONFIG_RENDERER_OPENGL|BGFX_CONFIG_RENDERER_OPENGLES3
+
+				GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, 0) );
+
+				if (bufferOnly)
+				{
+					// This is render buffer, there is no sampling, no need
+					// to create texture.
+					return false;
+				}
+			}
 		}
 		}
-#endif // BGFX_CONFIG_RENDERER_OPENGL
+
+		return true;
 	}
 	}
 
 
 	void Texture::create(const Memory* _mem, uint32_t _flags)
 	void Texture::create(const Memory* _mem, uint32_t _flags)
@@ -1457,11 +1472,16 @@ namespace bgfx
 				target = GL_TEXTURE_3D;
 				target = GL_TEXTURE_3D;
 			}
 			}
 
 
-			init(target
-				, imageContainer.m_format
-				, numMips
-				, _flags
-				);
+			if (!init(target
+					, imageContainer.m_width
+					, imageContainer.m_height
+					, imageContainer.m_format
+					, numMips
+					, _flags
+					) )
+			{
+				return;
+			}
 
 
 			target = GL_TEXTURE_CUBE_MAP == m_target ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : m_target;
 			target = GL_TEXTURE_CUBE_MAP == m_target ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : m_target;
 
 
@@ -1586,77 +1606,6 @@ namespace bgfx
 		GL_CHECK(glBindTexture(m_target, 0) );
 		GL_CHECK(glBindTexture(m_target, 0) );
 	}
 	}
 
 
-	void Texture::createColor(uint32_t _colorFormat, uint32_t _width, uint32_t _height, GLenum _min, GLenum _mag)
-	{
-		const RenderTargetColorFormat& rtcf = s_colorFormat[_colorFormat];
-		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.");
-		GL_CHECK(glBindTexture(m_target, m_id) );
-
-#if BGFX_CONFIG_RENDERER_OPENGL|BGFX_CONFIG_RENDERER_OPENGLES3
-		GL_CHECK(glTexParameteri(m_target, GL_TEXTURE_MAX_LEVEL, 0) );
-#endif // BGFX_CONFIG_RENDERER_OPENGL|BGFX_CONFIG_RENDERER_OPENGLES3
-
-		GL_CHECK(glTexParameteri(m_target, GL_TEXTURE_MIN_FILTER, _min) );
-		GL_CHECK(glTexParameteri(m_target, GL_TEXTURE_MAG_FILTER, _mag) );
-		GL_CHECK(glTexParameteri(m_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) );
-		GL_CHECK(glTexParameteri(m_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) );
-
-		GL_CHECK(glTexImage2D(m_target
-			, 0
-			, internalFormat
-			, _width
-			, _height
-			, 0
-			, GL_RGBA
-			, type
-			, NULL
-			) );
-
-		GL_CHECK(glBindTexture(m_target, 0) );
-	}
-
-	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.");
-		GL_CHECK(glBindTexture(m_target, m_id) );
-
-#if BGFX_CONFIG_RENDERER_OPENGL|BGFX_CONFIG_RENDERER_OPENGLES3
-		GL_CHECK(glTexParameteri(m_target, GL_TEXTURE_MAX_LEVEL, 0) );
-#endif // BGFX_CONFIG_RENDERER_OPENGL|BGFX_CONFIG_RENDERER_OPENGLES3
-
-//		GL_CHECK(glTexParameteri(m_target, GL_TEXTURE_COMPARE_MODE, GL_NONE) );
-//		GL_CHECK(glTexParameteri(m_target, GL_DEPTH_TEXTURE_MODE, GL_NONE) );
-		GL_CHECK(glTexParameteri(m_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR) );
-		GL_CHECK(glTexParameteri(m_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR) );
-		GL_CHECK(glTexParameteri(m_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) );
-		GL_CHECK(glTexParameteri(m_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) );
-
-		GL_CHECK(glTexImage2D(m_target
-							, 0
-							, GL_DEPTH_COMPONENT
-							, _width
-							, _height
-							, 0
-							, GL_DEPTH_COMPONENT
-							, GL_FLOAT
-							, NULL
-							) );
-
-		GL_CHECK(glBindTexture(m_target, 0) );
-	}
-
 	void Texture::destroy()
 	void Texture::destroy()
 	{
 	{
 		if (0 != m_id)
 		if (0 != m_id)
@@ -1665,6 +1614,12 @@ namespace bgfx
 			GL_CHECK(glDeleteTextures(1, &m_id) );
 			GL_CHECK(glDeleteTextures(1, &m_id) );
 			m_id = 0;
 			m_id = 0;
 		}
 		}
+
+		if (0 != m_rbo)
+		{
+			GL_CHECK(glDeleteRenderbuffers(1, &m_rbo) );
+			m_rbo = 0;
+		}
 	}
 	}
 
 
 	void Texture::update(uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem)
 	void Texture::update(uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem)
@@ -1950,13 +1905,13 @@ namespace bgfx
 					char* entry = strstr(temp, "void main ()");
 					char* entry = strstr(temp, "void main ()");
 					if (NULL != entry)
 					if (NULL != entry)
 					{
 					{
-						const char* brace = strstr(entry, "{");
+						char* brace = strstr(entry, "{");
 						if (NULL != brace)
 						if (NULL != brace)
 						{
 						{
 							const char* end = bx::strmb(brace, '{', '}');
 							const char* end = bx::strmb(brace, '{', '}');
 							if (NULL != end)
 							if (NULL != end)
 							{
 							{
-								strins(temp, "float gl_FragDepth = 0.0;\n");
+								strins(brace+1, "\n  float gl_FragDepth = 0.0;\n");
 							}
 							}
 						}
 						}
 					}
 					}
@@ -2018,136 +1973,94 @@ namespace bgfx
 		}
 		}
 	}
 	}
 
 
-	void RenderTarget::create(uint16_t _width, uint16_t _height, uint32_t _flags, uint32_t _textureFlags)
+	void FrameBuffer::create(uint8_t _num, const TextureHandle* _handles)
 	{
 	{
-		BX_TRACE("Create render target %dx%d 0x%02x", _width, _height, _flags);
-
-		m_width = _width;
-		m_height = _height;
-		uint32_t msaa = (_flags&BGFX_RENDER_TARGET_MSAA_MASK)>>BGFX_RENDER_TARGET_MSAA_SHIFT;
-		m_msaa = bx::uint32_min(s_renderCtx->m_maxMsaa, msaa == 0 ? 0 : 1<<msaa);
-
-		const uint32_t colorFormat = (_flags&BGFX_RENDER_TARGET_COLOR_MASK)>>BGFX_RENDER_TARGET_COLOR_SHIFT;
-		const uint32_t depthFormat = (_flags&BGFX_RENDER_TARGET_DEPTH_MASK)>>BGFX_RENDER_TARGET_DEPTH_SHIFT;
-		const GLenum minFilter = s_textureFilterMin[(_textureFlags&BGFX_TEXTURE_MIN_MASK)>>BGFX_TEXTURE_MIN_SHIFT][0];
-		const GLenum magFilter = s_textureFilterMag[(_textureFlags&BGFX_TEXTURE_MAG_MASK)>>BGFX_TEXTURE_MAG_SHIFT];
-
-		if (0 < colorFormat)
-		{
-			m_color.createColor(colorFormat, _width, _height, minFilter, magFilter);
-		}
-
-#if 0 // GLES can't create texture with depth texture format...
-		if (s_renderCtx->m_depthTextureSupport
-		&&  0 < depthFormat)
-		{
-			m_depth.createDepth(_width, _height);
-		}
-#endif //
+		GL_CHECK(glGenFramebuffers(1, &m_fbo[0]) );
+		GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_fbo[0]) );
 
 
-#if BGFX_CONFIG_RENDERER_OPENGL|BGFX_CONFIG_RENDERER_OPENGLES3
-		if (0 < colorFormat
-		&&  0 != m_msaa)
-		{
-			GL_CHECK(glGenFramebuffers(2, m_fbo) );
-			GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_fbo[0]) );
-
-			GL_CHECK(glGenRenderbuffers(1, &m_colorRbo) );
-			BX_CHECK(0 != m_colorRbo, "Failed to generate color renderbuffer id.");
-			GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, m_colorRbo) );
-			GL_CHECK(glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_msaa, s_colorFormat[colorFormat].m_internalFmt, _width, _height) );
-			GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, 0) );
-
-			GL_CHECK(glFramebufferRenderbuffer(GL_FRAMEBUFFER
-				, GL_COLOR_ATTACHMENT0
-				, GL_RENDERBUFFER
-				, m_colorRbo
-				) );
+		bool needResolve = false;
 
 
-			GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_fbo[1]) );
-		}
-		else
-#endif // BGFX_CONFIG_RENDERER_OPENGL|BGFX_CONFIG_RENDERER_OPENGLES3
+		for (uint32_t ii = 0, colorIdx = 0; ii < _num; ++ii)
 		{
 		{
-			GL_CHECK(glGenFramebuffers(1, m_fbo) );
-			GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_fbo[0]) );
-		}
-
-		if (0 < colorFormat)
-		{
-			GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER
-							, GL_COLOR_ATTACHMENT0
-							, m_color.m_target
-							, m_color.m_id
-							, 0
-							) );
-		}
-
-		BX_CHECK(GL_FRAMEBUFFER_COMPLETE ==  glCheckFramebufferStatus(GL_FRAMEBUFFER)
-			, "glCheckFramebufferStatus failed 0x%08x"
-			, glCheckFramebufferStatus(GL_FRAMEBUFFER)
-			);
-
-		if (0 < depthFormat)
-		{
-			GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_fbo[0]) );
-
-			if (0 < colorFormat)
+			TextureHandle handle = _handles[ii];
+			if (isValid(handle) )
 			{
 			{
-				GL_CHECK(glGenRenderbuffers(1, &m_depthRbo) );
-				BX_CHECK(0 != m_depthRbo, "Failed to generate renderbuffer id.");
-				GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, m_depthRbo) );
+				const Texture& texture = s_renderCtx->m_textures[handle.idx];
 
 
-				const GLenum depthComponent = s_depthFormat[depthFormat].m_internalFmt;
-				const GLenum attachment = s_depthFormat[depthFormat].m_attachment;
-
-#if BGFX_CONFIG_RENDERER_OPENGL|BGFX_CONFIG_RENDERER_OPENGLES3
-				if (0 != m_msaa)
+				GLenum attachment = GL_COLOR_ATTACHMENT0 + colorIdx;
+				if (isDepth( (TextureFormat::Enum)texture.m_textureFormat) )
 				{
 				{
-					GL_CHECK(glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_msaa, depthComponent, _width, _height) );
+					attachment = GL_DEPTH_ATTACHMENT;
 				}
 				}
 				else
 				else
-#endif // BGFX_CONFIG_RENDERER_OPENGL|BGFX_CONFIG_RENDERER_OPENGLES3
 				{
 				{
-					GL_CHECK(glRenderbufferStorage(GL_RENDERBUFFER, depthComponent, _width, _height) );
+					if (0 == colorIdx)
+					{
+						m_width  = texture.m_width;
+						m_height = texture.m_height;
+					}
+
+					++colorIdx;
 				}
 				}
-				GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, 0) );
 
 
-#if BGFX_CONFIG_RENDERER_OPENGLES2
-				if (GL_STENCIL_ATTACHMENT != attachment)
+				if (0 != texture.m_rbo)
 				{
 				{
 					GL_CHECK(glFramebufferRenderbuffer(GL_FRAMEBUFFER
 					GL_CHECK(glFramebufferRenderbuffer(GL_FRAMEBUFFER
-						, GL_DEPTH_ATTACHMENT
+						, attachment
 						, GL_RENDERBUFFER
 						, GL_RENDERBUFFER
-						, m_depthRbo
+						, texture.m_rbo
 						) );
 						) );
 				}
 				}
-
-				if (GL_DEPTH_STENCIL_ATTACHMENT == attachment
-				||  GL_STENCIL_ATTACHMENT == attachment)
+				else
 				{
 				{
-					GL_CHECK(glFramebufferRenderbuffer(GL_FRAMEBUFFER
-						, GL_STENCIL_ATTACHMENT
-						, GL_RENDERBUFFER
-						, m_depthRbo
+					GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER
+						, attachment
+						, texture.m_target
+						, texture.m_id
+						, 0
 						) );
 						) );
 				}
 				}
-#else
-				GL_CHECK(glFramebufferRenderbuffer(GL_FRAMEBUFFER
-					, attachment
-					, GL_RENDERBUFFER
-					, m_depthRbo
-					) );
-#endif // BGFX_CONFIG_RENDERER_OPENGLES2
+				
+				needResolve |= (0 != texture.m_rbo) && (0 != texture.m_id);
 			}
 			}
-			else
+		}
+
+		BX_CHECK(GL_FRAMEBUFFER_COMPLETE ==  glCheckFramebufferStatus(GL_FRAMEBUFFER)
+			, "glCheckFramebufferStatus failed 0x%08x"
+			, glCheckFramebufferStatus(GL_FRAMEBUFFER)
+			);
+
+		if (needResolve)
+		{
+			GL_CHECK(glGenFramebuffers(1, &m_fbo[1]) );
+			GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_fbo[1]) );
+
+			for (uint32_t ii = 0, colorIdx = 0; ii < _num; ++ii)
 			{
 			{
-				GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER
-					, GL_DEPTH_ATTACHMENT
-					, m_depth.m_target
-					, m_depth.m_id
-					, 0
-					) );
+				TextureHandle handle = _handles[ii];
+				if (isValid(handle) )
+				{
+					const Texture& texture = s_renderCtx->m_textures[handle.idx];
+
+					if (0 != texture.m_id)
+					{
+						GLenum attachment = GL_COLOR_ATTACHMENT0 + colorIdx;
+						if (isDepth( (TextureFormat::Enum)texture.m_textureFormat) )
+						{
+							attachment = GL_DEPTH_ATTACHMENT;
+						}
+						else
+						{
+							++colorIdx;
+							GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER
+								, attachment
+								, texture.m_target
+								, texture.m_id
+								, 0
+								) );
+						}
+					}
+				}
 			}
 			}
 
 
 			BX_CHECK(GL_FRAMEBUFFER_COMPLETE ==  glCheckFramebufferStatus(GL_FRAMEBUFFER)
 			BX_CHECK(GL_FRAMEBUFFER_COMPLETE ==  glCheckFramebufferStatus(GL_FRAMEBUFFER)
@@ -2159,35 +2072,20 @@ namespace bgfx
 		GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, s_renderCtx->m_msaaBackBufferFbo) );
 		GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, s_renderCtx->m_msaaBackBufferFbo) );
 	}
 	}
 
 
-	void RenderTarget::destroy()
+	void FrameBuffer::destroy()
 	{
 	{
 		GL_CHECK(glDeleteFramebuffers(0 == m_fbo[1] ? 1 : 2, m_fbo) );
 		GL_CHECK(glDeleteFramebuffers(0 == m_fbo[1] ? 1 : 2, m_fbo) );
 		memset(m_fbo, 0, sizeof(m_fbo) );
 		memset(m_fbo, 0, sizeof(m_fbo) );
-
-		if (0 != m_colorRbo)
-		{
-			GL_CHECK(glDeleteRenderbuffers(1, &m_colorRbo) );
-			m_colorRbo = 0;
-		}
-
-		if (0 != m_depthRbo)
-		{
-			GL_CHECK(glDeleteRenderbuffers(1, &m_depthRbo) );
-			m_depthRbo = 0;
-		}
-
-		m_color.destroy();
-		m_depth.destroy();
 	}
 	}
 
 
-	void RenderTarget::resolve()
+	void FrameBuffer::resolve()
 	{
 	{
 #if BGFX_CONFIG_RENDERER_OPENGL|BGFX_CONFIG_RENDERER_OPENGLES3
 #if BGFX_CONFIG_RENDERER_OPENGL|BGFX_CONFIG_RENDERER_OPENGLES3
-		BX_CHECK(0 != m_fbo[1], "Can resolve without two framebuffers.");
-
-		GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo[0]) );
-		GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[1]) );
-		GL_CHECK(glBlitFramebuffer(0
+		if (0 != m_fbo[1])
+		{
+			GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo[0]) );
+			GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[1]) );
+			GL_CHECK(glBlitFramebuffer(0
 				, 0
 				, 0
 				, m_width
 				, m_width
 				, m_height
 				, m_height
@@ -2198,7 +2096,8 @@ namespace bgfx
 				, GL_COLOR_BUFFER_BIT
 				, GL_COLOR_BUFFER_BIT
 				, GL_LINEAR
 				, GL_LINEAR
 				) );
 				) );
-		GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, s_renderCtx->m_msaaBackBufferFbo) );
+			GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, s_renderCtx->m_msaaBackBufferFbo) );
+		}
 #endif // BGFX_CONFIG_RENDERER_OPENGL|BGFX_CONFIG_RENDERER_OPENGLES3
 #endif // BGFX_CONFIG_RENDERER_OPENGL|BGFX_CONFIG_RENDERER_OPENGLES3
 	}
 	}
 
 
@@ -2510,29 +2409,6 @@ namespace bgfx
 			cmpFormat = (GLint*)alloca(sizeof(GLint)*numCmpFormats);
 			cmpFormat = (GLint*)alloca(sizeof(GLint)*numCmpFormats);
 			GL_CHECK(glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, cmpFormat) );
 			GL_CHECK(glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, cmpFormat) );
 
 
-#if BGFX_CONFIG_DEBUG
-			static const char* s_textureFormatName[TextureFormat::Unknown+1] =
-			{
-				"BC1",
-				"BC2",
-				"BC3",
-				"BC4",
-				"BC5",
-				"ETC1",
-				"ETC2",
-				"ETC2A",
-				"ETC2A1",
-				"PTC12",
-				"PTC14",
-				"PTC12A",
-				"PTC14A",
-				"PTC22",
-				"PTC24",
-				"",
-				// TextureFormat::Count
-			};
-#endif // BGFX_CONFIG_DEBUG
-
 			for (GLint ii = 0; ii < numCmpFormats; ++ii)
 			for (GLint ii = 0; ii < numCmpFormats; ++ii)
 			{
 			{
 				GLint internalFmt = cmpFormat[ii];
 				GLint internalFmt = cmpFormat[ii];
@@ -2546,7 +2422,7 @@ namespace bgfx
 					}
 					}
 				}
 				}
 
 
-				BX_TRACE("  %3d: %8x %s", ii, internalFmt, s_textureFormatName[fmt]);
+				BX_TRACE("  %3d: %8x %s", ii, internalFmt, getName( (TextureFormat::Enum)fmt) );
 			}
 			}
 		}
 		}
 
 
@@ -2735,6 +2611,10 @@ namespace bgfx
 						 ;
 						 ;
 		g_caps.maxTextureSize = glGet(GL_MAX_TEXTURE_SIZE);
 		g_caps.maxTextureSize = glGet(GL_MAX_TEXTURE_SIZE);
 
 
+#if !BGFX_CONFIG_RENDERER_OPENGLES2
+		g_caps.maxFBAttachments = bx::uint32_min(glGet(GL_MAX_COLOR_ATTACHMENTS), BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS);
+#endif // !BGFX_CONFIG_RENDERER_OPENGLES2
+
 		s_renderCtx->m_vaoSupport = !!BGFX_CONFIG_RENDERER_OPENGLES3
 		s_renderCtx->m_vaoSupport = !!BGFX_CONFIG_RENDERER_OPENGLES3
 			|| s_extension[Extension::ARB_vertex_array_object].m_supported
 			|| s_extension[Extension::ARB_vertex_array_object].m_supported
 			|| s_extension[Extension::OES_vertex_array_object].m_supported
 			|| s_extension[Extension::OES_vertex_array_object].m_supported
@@ -3008,14 +2888,14 @@ namespace bgfx
 		s_renderCtx->m_textures[_handle.idx].destroy();
 		s_renderCtx->m_textures[_handle.idx].destroy();
 	}
 	}
 
 
-	void Context::rendererCreateRenderTarget(RenderTargetHandle _handle, uint16_t _width, uint16_t _height, uint32_t _flags, uint32_t _textureFlags)
+	void Context::rendererCreateFrameBuffer(FrameBufferHandle _handle, uint8_t _num, const TextureHandle* _textureHandles)
 	{
 	{
-		s_renderCtx->m_renderTargets[_handle.idx].create(_width, _height, _flags, _textureFlags);
+		s_renderCtx->m_frameBuffers[_handle.idx].create(_num, _textureHandles);
 	}
 	}
 
 
-	void Context::rendererDestroyRenderTarget(RenderTargetHandle _handle)
+	void Context::rendererDestroyFrameBuffer(FrameBufferHandle _handle)
 	{
 	{
-		s_renderCtx->m_renderTargets[_handle.idx].destroy();
+		s_renderCtx->m_frameBuffers[_handle.idx].destroy();
 	}
 	}
 
 
 	void Context::rendererCreateUniform(UniformHandle _handle, UniformType::Enum _type, uint16_t _num, const char* _name)
 	void Context::rendererCreateUniform(UniformHandle _handle, UniformType::Enum _type, uint16_t _num, const char* _name)
@@ -3102,7 +2982,7 @@ namespace bgfx
 		uint16_t programIdx = invalidHandle;
 		uint16_t programIdx = invalidHandle;
 		SortKey key;
 		SortKey key;
 		uint8_t view = 0xff;
 		uint8_t view = 0xff;
-		RenderTargetHandle rt = BGFX_INVALID_HANDLE;
+		FrameBufferHandle fbh = BGFX_INVALID_HANDLE;
 		int32_t height = m_render->m_resolution.m_height;
 		int32_t height = m_render->m_resolution.m_height;
 		float alphaRef = 0.0f;
 		float alphaRef = 0.0f;
 		uint32_t blendFactor = 0;
 		uint32_t blendFactor = 0;
@@ -3150,10 +3030,10 @@ namespace bgfx
 					view = key.m_view;
 					view = key.m_view;
 					programIdx = invalidHandle;
 					programIdx = invalidHandle;
 
 
-					if (m_render->m_rt[view].idx != rt.idx)
+					if (m_render->m_fb[view].idx != fbh.idx)
 					{
 					{
-						rt = m_render->m_rt[view];
-						height = s_renderCtx->setRenderTarget(rt, m_render->m_resolution.m_height);
+						fbh = m_render->m_fb[view];
+						height = s_renderCtx->setFrameBuffer(fbh, m_render->m_resolution.m_height);
 					}
 					}
 
 
 					const Rect& rect = m_render->m_rect[view];
 					const Rect& rect = m_render->m_rect[view];
@@ -3550,20 +3430,6 @@ namespace bgfx
 											texture.commit(stage, sampler.m_flags);
 											texture.commit(stage, sampler.m_flags);
 										}
 										}
 										break;
 										break;
-
-									case BGFX_SAMPLER_RENDERTARGET_COLOR:
-										{
-											RenderTarget& rt = s_renderCtx->m_renderTargets[sampler.m_idx];
-											rt.m_color.commit(stage, sampler.m_flags);
-										}
-										break;
-
-									case BGFX_SAMPLER_RENDERTARGET_DEPTH:
-										{
-											RenderTarget& rt = s_renderCtx->m_renderTargets[sampler.m_idx];
-											rt.m_depth.commit(stage, sampler.m_flags);
-										}
-										break;
 									}
 									}
 								}
 								}
 							}
 							}
@@ -3840,12 +3706,18 @@ namespace bgfx
 				tvm.printf(0, pos++, 0x0f, "GLSL version: %s", s_renderCtx->m_glslVersion);
 				tvm.printf(0, pos++, 0x0f, "GLSL version: %s", s_renderCtx->m_glslVersion);
 
 
 				pos = 10;
 				pos = 10;
-				tvm.printf(10, pos++, 0x8e, "  Frame CPU: %7.3f, % 7.3f \x1f, % 7.3f \x1e [ms] / % 6.2f FPS%s"
+				tvm.printf(10, pos++, 0x8e, "      Frame CPU: %7.3f, % 7.3f \x1f, % 7.3f \x1e [ms] / % 6.2f FPS "
 					, double(frameTime)*toMs
 					, double(frameTime)*toMs
 					, double(min)*toMs
 					, double(min)*toMs
 					, double(max)*toMs
 					, double(max)*toMs
 					, freq/frameTime
 					, freq/frameTime
-					, !!(m_resolution.m_flags&BGFX_RESET_VSYNC) ? " (vsync)" : ""
+					);
+
+				const uint32_t msaa = (m_resolution.m_flags&BGFX_RESET_MSAA_MASK)>>BGFX_RESET_MSAA_SHIFT;
+				tvm.printf(10, pos++, 0x8e, "    Reset flags: [%c] vsync, [%c] MSAAx%d "
+					, !!(m_resolution.m_flags&BGFX_RESET_VSYNC) ? '\xfe' : ' '
+					, 0 != msaa ? '\xfe' : ' '
+					, 1<<msaa
 					);
 					);
 
 
 				double elapsedCpuMs = double(elapsed)*toMs;
 				double elapsedCpuMs = double(elapsed)*toMs;

+ 12 - 16
src/renderer_gl.h

@@ -573,6 +573,7 @@ namespace bgfx
 	{
 	{
 		Texture()
 		Texture()
 			: m_id(0)
 			: m_id(0)
+			, m_rbo(0)
 			, m_target(GL_TEXTURE_2D)
 			, m_target(GL_TEXTURE_2D)
 			, m_fmt(GL_ZERO)
 			, m_fmt(GL_ZERO)
 			, m_type(GL_ZERO)
 			, m_type(GL_ZERO)
@@ -582,21 +583,22 @@ namespace bgfx
 		{
 		{
 		}
 		}
 
 
-		void init(GLenum _target, uint8_t _format, uint8_t _numMips, uint32_t _flags);
+		bool init(GLenum _target, uint32_t _width, uint32_t _height, uint8_t _format, uint8_t _numMips, uint32_t _flags);
 		void create(const Memory* _mem, uint32_t _flags);
 		void create(const Memory* _mem, uint32_t _flags);
-		void createColor(uint32_t _colorFormat, uint32_t _width, uint32_t _height, GLenum _min, GLenum _mag);
-		void createDepth(uint32_t _width, uint32_t _height);
 		void destroy();
 		void destroy();
 		void update(uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem);
 		void update(uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem);
 		void setSamplerState(uint32_t _flags);
 		void setSamplerState(uint32_t _flags);
 		void commit(uint32_t _stage, uint32_t _flags);
 		void commit(uint32_t _stage, uint32_t _flags);
 
 
 		GLuint m_id;
 		GLuint m_id;
+		GLuint m_rbo;
 		GLenum m_target;
 		GLenum m_target;
 		GLenum m_fmt;
 		GLenum m_fmt;
 		GLenum m_type;
 		GLenum m_type;
 		uint32_t m_flags;
 		uint32_t m_flags;
 		uint32_t m_currentFlags;
 		uint32_t m_currentFlags;
+		uint32_t m_width;
+		uint32_t m_height;
 		uint8_t m_numMips;
 		uint8_t m_numMips;
 		uint8_t m_requestedFormat;
 		uint8_t m_requestedFormat;
 		uint8_t m_textureFormat;
 		uint8_t m_textureFormat;
@@ -617,28 +619,22 @@ namespace bgfx
 		uint32_t m_hash;
 		uint32_t m_hash;
 	};
 	};
 
 
-	struct RenderTarget
+	struct FrameBuffer
 	{
 	{
-		RenderTarget()
-			: m_width(0)
-			, m_height(0)
-			, m_msaa(0)
+		FrameBuffer()
+			: m_num(0)
 		{
 		{
 			memset(m_fbo, 0, sizeof(m_fbo) );
 			memset(m_fbo, 0, sizeof(m_fbo) );
 		}
 		}
 
 
-		void create(uint16_t _width, uint16_t _height, uint32_t _flags, uint32_t _textureFlags);
+		void create(uint8_t _num, const TextureHandle* _handles);
 		void destroy();
 		void destroy();
 		void resolve();
 		void resolve();
 
 
-		GLsizei m_width;
-		GLsizei m_height;
-		uint32_t m_msaa;
-		Texture m_color;
-		Texture m_depth;
+		uint8_t m_num;
 		GLuint m_fbo[2];
 		GLuint m_fbo[2];
-		GLuint m_colorRbo;
-		GLuint m_depthRbo;
+		uint32_t m_width;
+		uint32_t m_height;
 	};
 	};
 
 
 	struct Program
 	struct Program

+ 2 - 2
src/renderer_null.cpp

@@ -125,11 +125,11 @@ namespace bgfx
 	{
 	{
 	}
 	}
 
 
-	void Context::rendererCreateRenderTarget(RenderTargetHandle /*_handle*/, uint16_t /*_width*/, uint16_t /*_height*/, uint32_t /*_flags*/, uint32_t /*_textureFlags*/)
+	void Context::rendererCreateFrameBuffer(FrameBufferHandle /*_handle*/, uint8_t /*_num*/, const TextureHandle* /*_textureHandles*/)
 	{
 	{
 	}
 	}
 
 
-	void Context::rendererDestroyRenderTarget(RenderTargetHandle /*_handle*/)
+	void Context::rendererDestroyFrameBuffer(FrameBufferHandle /*_handle*/)
 	{
 	{
 	}
 	}
 
 

+ 61 - 7
tools/shaderc/shaderc.cpp

@@ -441,6 +441,15 @@ void strins(char* _str, const char* _insert)
 	memcpy(_str, _insert, len);
 	memcpy(_str, _insert, len);
 }
 }
 
 
+void strreplace(char* _str, const char* _find, const char* _replace)
+{
+	const size_t len = strlen(_find);
+	for (char* ptr = strstr(_str, _find); NULL != ptr; ptr = strstr(ptr + len, _find) )
+	{
+		memcpy(ptr, _replace, len);
+	}
+}
+
 class LineReader
 class LineReader
 {
 {
 public:
 public:
@@ -1277,6 +1286,25 @@ uint32_t parseInOut(InOut& _inout, const char* _str, const char* _eol)
 	return hash;
 	return hash;
 }
 }
 
 
+void addFragData(Preprocessor& _preprocessor, char* _data, uint32_t _idx, bool _comma)
+{
+	char find[32];
+	bx::snprintf(find, sizeof(find), "gl_FragData[%d]", _idx);
+
+	char replace[32];
+	bx::snprintf(replace, sizeof(replace), "gl_FragData_%d_", _idx);
+
+	strreplace(_data, find, replace);
+
+	_preprocessor.writef(
+		" \\\n\t%sout vec4 gl_FragData_%d_ : SV_TARGET%d"
+		, _comma ? ", " : "  "
+		, _idx
+		, _idx
+		);
+
+}
+
 // c - compute
 // c - compute
 // d - domain
 // d - domain
 // f - fragment
 // f - fragment
@@ -1708,9 +1736,23 @@ int main(int _argc, const char* _argv[])
 
 
 				if (fragment)
 				if (fragment)
 				{
 				{
-					bool hasFragCoord   = NULL != strstr(data, "gl_FragCoord") || hlsl > 3;
-					bool hasFragDepth   = NULL != strstr(data, "gl_FragDepth");
-					bool hasFrontFacing = NULL != strstr(data, "gl_FrontFacing");
+					const bool hasFragCoord   = NULL != strstr(data, "gl_FragCoord") || hlsl > 3;
+					const bool hasFragDepth   = NULL != strstr(data, "gl_FragDepth");
+					const bool hasFrontFacing = NULL != strstr(data, "gl_FrontFacing");
+					const bool hasFragData0   = NULL != strstr(data, "gl_FragData[0]");
+					const bool hasFragData1   = NULL != strstr(data, "gl_FragData[1]");
+					const bool hasFragData2   = NULL != strstr(data, "gl_FragData[2]");
+					const bool hasFragData3   = NULL != strstr(data, "gl_FragData[3]");
+
+					if (!hasFragData0
+					&&  !hasFragData1
+					&&  !hasFragData2
+					&&  !hasFragData3)
+					{
+						// GL errors when both gl_FragColor and gl_FragData is used.
+						// This will trigger the same error with HLSL compiler too.
+						preprocessor.writef("#define gl_FragColor gl_FragData_0_\n");
+					}
 
 
 					preprocessor.writef("#define void_main()");
 					preprocessor.writef("#define void_main()");
 					preprocessor.writef(" \\\n\tvoid main(");
 					preprocessor.writef(" \\\n\tvoid main(");
@@ -1733,10 +1775,22 @@ int main(int _argc, const char* _argv[])
 						}
 						}
 					}
 					}
 
 
-					preprocessor.writef(
-						" \\\n\t%sout vec4 gl_FragColor : SV_TARGET"
-						, arg++ > 0 ? ", " : "  "
-						);
+					addFragData(preprocessor, data, 0, arg++ > 0);
+
+					if (hasFragData1)
+					{
+						addFragData(preprocessor, data, 1, arg++ > 0);
+					}
+
+					if (hasFragData2)
+					{
+						addFragData(preprocessor, data, 2, arg++ > 0);
+					}
+
+					if (hasFragData3)
+					{
+						addFragData(preprocessor, data, 3, arg++ > 0);
+					}
 
 
 					if (hasFragDepth)
 					if (hasFragDepth)
 					{
 					{