Commit 91e86f4c authored by hybrid's avatar hybrid

Add MRT support for OpenGL and Direct3D9. This patch is heavily based on the...

Add MRT support for OpenGL and Direct3D9. This patch is heavily based on the code from Nadro. This version supports also special render targets for OpenGL, and is already prepared for further MRT extensions such as per-target blend support. The d3d9 version is not yet tested.

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@2808 dfc29bdd-3216-0410-991c-e03cc46cb475
parent 039d42da
......@@ -91,6 +91,12 @@ namespace video
//! Supports Color masks (disabling color planes in output)
EVDF_COLOR_MASK,
//! Supports multiple render targets at once
EVDF_MULTIPLE_RENDER_TARGETS,
//! Supports geometry shaders
EVDF_GEOMETRY_SHADER,
//! Only used for counting the elements of this enum
EVDF_COUNT
};
......
......@@ -104,10 +104,10 @@ namespace video
{
//! Render target is the main color frame buffer
ERT_FRAME_BUFFER=0,
//! Render target is the main color frame buffer
ERT_STEREO_LEFT_BUFFER=0,
//! Render target is a render texture
ERT_RENDER_TEXTURE,
//! Render target is the main color frame buffer
ERT_STEREO_LEFT_BUFFER,
//! Render target is the right color buffer (left is the main buffer)
ERT_STEREO_RIGHT_BUFFER,
//! Render to both stereo buffers at once
......@@ -194,6 +194,29 @@ namespace video
};
struct IRenderTarget
{
IRenderTarget(ITexture* texture,
E_COLOR_PLANE colorMask=ECP_ALL,
E_BLEND_FACTOR blendFunc=EBF_ONE_MINUS_SRC_ALPHA,
bool blendEnable=false) :
RenderTexture(texture),
TargetType(ERT_RENDER_TEXTURE), ColorMask(colorMask),
BlendFunc(blendFunc), BlendEnable(blendFunc) {}
IRenderTarget(E_RENDER_TARGET target,
E_COLOR_PLANE colorMask=ECP_ALL,
E_BLEND_FACTOR blendFunc=EBF_ONE_MINUS_SRC_ALPHA,
bool blendEnable=false) :
RenderTexture(0),
TargetType(target), ColorMask(colorMask),
BlendFunc(blendFunc), BlendEnable(blendEnable) {}
ITexture* RenderTexture;
E_RENDER_TARGET TargetType:8;
E_COLOR_PLANE ColorMask:8;
E_BLEND_FACTOR BlendFunc:8;
bool BlendEnable;
};
//! Interface to driver which is able to perform 2d and 3d graphics functions.
/** This interface is one of the most important interfaces of
the Irrlicht Engine: All rendering and texture manipulation is done with
......@@ -490,6 +513,11 @@ namespace video
bool clearZBuffer=true,
SColor color=video::SColor(0,0,0,0)) =0;
//! Sets new multiple render targets.
virtual bool setRenderTarget(const core::array<video::IRenderTarget>& texture,
bool clearBackBuffer=true, bool clearZBuffer=true,
SColor color=video::SColor(0,0,0,0)) =0;
//! Sets a new viewport.
/** Every rendering operation is done into this new area.
\param area: Rectangle defining the new area of rendering
......
......@@ -57,7 +57,7 @@ namespace video
//! sets a render target
virtual bool setRenderTarget(video::ITexture* texture,
bool clearBackBuffer=false, bool clearZBuffer=false,
bool clearBackBuffer=true, bool clearZBuffer=true,
SColor color=video::SColor(0,0,0,0));
//! sets a viewport
......
......@@ -627,6 +627,8 @@ bool CD3D9Driver::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const
return (Caps.TextureCaps & D3DPTEXTURECAPS_POW2) == 0;
case EVDF_COLOR_MASK:
return (Caps.PrimitiveMiscCaps & D3DPMISCCAPS_COLORWRITEENABLE) != 0;
case EVDF_MULTIPLE_RENDER_TARGETS:
return true;
default:
return false;
};
......@@ -823,6 +825,110 @@ bool CD3D9Driver::setRenderTarget(video::ITexture* texture,
}
//! Sets multiple render targets
bool CD3D9Driver::setRenderTarget(const core::array<video::IRenderTarget*>& targets,
bool clearBackBuffer, bool clearZBuffer, SColor color)
{
if (targets.size()==0)
return setRenderTarget(0, clearBackBuffer, clearZBuffer, color);
u32 maxMultipleRTTs = core::min_(4u, targets.size());
for (u32 i = 0; i < maxMultipleRTTs; ++i)
{
if (targets[i].TargetType != ERT_RENDER_TEXTURE || !targets[i].RenderTexture)
{
maxMultipleRTTs = i;
os::Printer::log("Missing texture for MRT.", ELL_WARNING);
break;
}
// check for right driver type
if (targets[i].RenderTexture->getDriverType() != EDT_DIRECT3D9)
{
maxMultipleRTTs = i;
os::Printer::log("Tried to set a texture not owned by this driver.", ELL_WARNING);
break;
}
// check for valid render target
if (!targets[i].RenderTexture->isRenderTarget())
{
maxMultipleRTTs = i;
os::Printer::log("Tried to set a non render target texture as render target.", ELL_WARNING);
break;
}
// check for valid size
if (targets[0].RenderTexture->getSize() != targets[i].RenderTexture->getSize())
{
maxMultipleRTTs = i;
os::Printer::log("Render target texture has wrong size.", ELL_WARNING);
break;
}
}
if (maxMultipleRTTs==0)
{
os::Printer::log("Fatal Error: No valid MRT found.", ELL_ERROR);
return false;
}
CD3D9Texture* tex = static_cast<CD3D9Texture*>(texture[0].RenderTexture);
// check if we should set the previous RT back
bool ret = true;
// we want to set a new target. so do this.
// store previous target
if (!PrevRenderTarget)
{
if (FAILED(pID3DDevice->GetRenderTarget(0, &PrevRenderTarget)))
{
os::Printer::log("Could not get previous render target.", ELL_ERROR);
return false;
}
}
// set new render target
for (u32 i = 0; i < maxMultipleRTTs; ++i)
{
if (FAILED(pID3DDevice->SetRenderTarget(i, reinterpret_cast<CD3D9Texture*>(texture[i])->getRenderTargetSurface())))
{
os::Printer::log("Error: Could not set render target.", ELL_ERROR);
return false;
}
}
CurrentRendertargetSize = tex->getSize();
if (FAILED(pID3DDevice->SetDepthStencilSurface(tex->DepthSurface->Surface)))
{
os::Printer::log("Error: Could not set new depth buffer.", ELL_ERROR);
}
if (clearBackBuffer || clearZBuffer)
{
DWORD flags = 0;
if (clearBackBuffer)
flags |= D3DCLEAR_TARGET;
if (clearZBuffer)
flags |= D3DCLEAR_ZBUFFER;
pID3DDevice->Clear(0, NULL, flags, color.color, 1.0f, 0);
}
return ret;
}
//! sets a viewport
void CD3D9Driver::setViewPort(const core::rect<s32>& area)
{
......
......@@ -73,7 +73,12 @@ namespace video
//! sets a render target
virtual bool setRenderTarget(video::ITexture* texture,
bool clearBackBuffer=false, bool clearZBuffer=false,
bool clearBackBuffer=true, bool clearZBuffer=true,
SColor color=video::SColor(0,0,0,0));
//! Sets multiple render targets
virtual bool setRenderTarget(const core::array<video::IRenderTarget*>& texture,
bool clearBackBuffer=true, bool clearZBuffer=true,
SColor color=video::SColor(0,0,0,0));
//! sets a viewport
......
......@@ -554,6 +554,14 @@ bool CNullDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuffer
}
//! Sets multiple render targets
bool CNullDriver::setRenderTarget(const core::array<video::IRenderTarget>& texture,
bool clearBackBuffer, bool clearZBuffer, SColor color)
{
return false;
}
//! sets a viewport
void CNullDriver::setViewPort(const core::rect<s32>& area)
{
......
......@@ -98,6 +98,10 @@ namespace video
virtual bool setRenderTarget(video::E_RENDER_TARGET target, bool clearTarget,
bool clearZBuffer, SColor color);
//! Sets multiple render targets
virtual bool setRenderTarget(const core::array<video::IRenderTarget>& texture,
bool clearBackBuffer=true, bool clearZBuffer=true, SColor color=SColor(0,0,0,0));
//! sets a viewport
virtual void setViewPort(const core::rect<s32>& area);
......
......@@ -3356,6 +3356,120 @@ bool COpenGLDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuff
}
//! Sets multiple render targets
bool COpenGLDriver::setRenderTarget(const core::array<video::IRenderTarget>& targets,
bool clearBackBuffer, bool clearZBuffer, SColor color)
{
if (targets.size()==0)
return setRenderTarget(0, clearBackBuffer, clearZBuffer, color);
u32 maxMultipleRTTs = core::min_(4u, targets.size());
// determine common size
core::dimension2du rttSize = CurrentRendertargetSize;
if (targets[0].TargetType==ERT_RENDER_TEXTURE)
{
if (!targets[0].RenderTexture)
{
os::Printer::log("Missing render texture for MRT.", ELL_ERROR);
return false;
}
rttSize=targets[0].RenderTexture->getSize();
}
for (u32 i = 0; i < maxMultipleRTTs; ++i)
{
// check for right driver type
if (targets[i].TargetType==ERT_RENDER_TEXTURE)
{
if (!targets[i].RenderTexture)
{
maxMultipleRTTs=i;
os::Printer::log("Missing render texture for MRT.", ELL_WARNING);
break;
}
if (targets[i].RenderTexture->getDriverType() != EDT_OPENGL)
{
maxMultipleRTTs=i;
os::Printer::log("Tried to set a texture not owned by this driver.", ELL_WARNING);
break;
}
// check for valid render target
if (!targets[i].RenderTexture->isRenderTarget() || !static_cast<COpenGLTexture*>(targets[i].RenderTexture)->isFrameBufferObject())
{
maxMultipleRTTs=i;
os::Printer::log("Tried to set a non FBO-RTT as render target.", ELL_WARNING);
break;
}
// check for valid size
if (rttSize != targets[i].RenderTexture->getSize())
{
maxMultipleRTTs=i;
os::Printer::log("Render target texture has wrong size.", ELL_WARNING);
break;
}
}
}
if (maxMultipleRTTs==0)
{
os::Printer::log("No valid MRTs.", ELL_ERROR);
return false;
}
if (targets[0].TargetType==ERT_RENDER_TEXTURE)
setRenderTarget(targets[0].RenderTexture, false, false, 0x0);
else
setRenderTarget(targets[0].TargetType, false, false, 0x0);
if (maxMultipleRTTs > 1)
{
core::array<GLenum> MRTs;
MRTs.set_used(maxMultipleRTTs);
for(u32 i = 0; i < maxMultipleRTTs; i++)
{
if (targets[0].TargetType==ERT_RENDER_TEXTURE)
{
GLenum attachment = GL_NONE;
#ifdef GL_EXT_framebuffer_object
// attach texture to FrameBuffer Object on Color [i]
attachment = GL_COLOR_ATTACHMENT0_EXT+i;
extGlFramebufferTexture2D(GL_FRAMEBUFFER_EXT, attachment, GL_TEXTURE_2D, static_cast<COpenGLTexture*>(targets[i].RenderTexture)->getOpenGLTextureName(), 0);
#endif
MRTs[i]=attachment;
}
else
{
switch(targets[i].TargetType)
{
case ERT_FRAME_BUFFER:
MRTs[i]=GL_BACK_LEFT;
break;
case ERT_STEREO_BOTH_BUFFERS:
MRTs[i]=GL_BACK;
break;
case ERT_STEREO_RIGHT_BUFFER:
MRTs[i]=GL_BACK_RIGHT;
break;
case ERT_STEREO_LEFT_BUFFER:
MRTs[i]=GL_BACK_LEFT;
break;
default:
MRTs[i]=GL_AUX0+(targets[i].TargetType-ERT_AUX_BUFFER0);
break;
}
}
}
extGlDrawBuffers(maxMultipleRTTs, MRTs.const_pointer());
}
clearBuffers(clearBackBuffer, clearZBuffer, false, color);
return true;
}
// returns the current size of the screen or rendertarget
const core::dimension2d<u32>& COpenGLDriver::getCurrentRenderTargetSize() const
{
......
......@@ -289,6 +289,10 @@ namespace video
virtual bool setRenderTarget(video::ITexture* texture, bool clearBackBuffer,
bool clearZBuffer, SColor color);
//! Sets multiple render targets
virtual bool setRenderTarget(const core::array<video::IRenderTarget>& texture,
bool clearBackBuffer=true, bool clearZBuffer=true, SColor color=SColor(0,0,0,0));
//! Clears the ZBuffer.
virtual void clearZBuffer();
......
......@@ -535,6 +535,10 @@ bool COpenGLExtensionHandler::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const
return true;
case EVDF_ALPHA_TO_COVERAGE:
return FeatureAvailable[IRR_ARB_multisample];
case EVDF_GEOMETRY_SHADER:
return FeatureAvailable[IRR_ARB_geometry_shader4] || FeatureAvailable[IRR_EXT_geometry_shader4] || FeatureAvailable[IRR_NV_geometry_program4] || FeatureAvailable[IRR_NV_geometry_shader4];
case EVDF_MULTIPLE_RENDER_TARGETS:
return FeatureAvailable[IRR_ARB_draw_buffers] || FeatureAvailable[IRR_ATI_draw_buffers];
default:
return false;
};
......
......@@ -535,8 +535,7 @@ static bool checkFBOStatus(COpenGLDriver* Driver);
//! RTT ColorFrameBuffer constructor
COpenGLFBOTexture::COpenGLFBOTexture(const core::dimension2d<u32>& size,
const io::path& name,
COpenGLDriver* driver,
const io::path& name, COpenGLDriver* driver,
const ECOLOR_FORMAT format)
: COpenGLTexture(name, driver), DepthTexture(0), ColorFrameBuffer(0)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment