irrlicht/source/Irrlicht/CD3D9RenderTarget.cpp

282 lines
6.8 KiB
C++

// Copyright (C) 2015 Patryk Nadrowski
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CD3D9RenderTarget.h"
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#include "IImage.h"
#include "irrMath.h"
#include "irrString.h"
#include "CD3D9Driver.h"
#include "CD3D9Texture.h"
namespace irr
{
namespace video
{
CD3D9RenderTarget::CD3D9RenderTarget(CD3D9Driver* driver) : DepthStencilSurface(0), Driver(driver)
{
#ifdef _DEBUG
setDebugName("CD3D9RenderTarget");
#endif
DriverType = EDT_DIRECT3D9;
Size = Driver->getScreenSize();
}
CD3D9RenderTarget::~CD3D9RenderTarget()
{
for (u32 i = 0; i < Surfaces.size(); ++i)
{
if (Surfaces[i])
Surfaces[i]->Release();
}
if (DepthStencilSurface)
DepthStencilSurface->Release();
for (u32 i = 0; i < Textures.size(); ++i)
{
if (Textures[i])
Textures[i]->drop();
}
if (DepthStencil)
DepthStencil->drop();
}
void CD3D9RenderTarget::setTextures(ITexture* const * textures, u32 numTextures, ITexture* depthStencil, const E_CUBE_SURFACE* cubeSurfaces, u32 numCubeSurfaces)
{
bool needSizeUpdate = false;
// Set color attachments.
if (!Textures.equals(textures, numTextures) || !CubeSurfaces.equals(cubeSurfaces, numCubeSurfaces))
{
needSizeUpdate = true;
CubeSurfaces.set_data(cubeSurfaces, numCubeSurfaces); // TODO: we can probably avoid some memory allocating/de-allocating if _only_ CubeSurfaces change.
if (numTextures > Driver->ActiveRenderTarget.size())
{
core::stringc message = "This GPU supports up to ";
message += Driver->ActiveRenderTarget.size();
message += " textures per render target.";
os::Printer::log(message.c_str(), ELL_WARNING);
}
const u32 size = core::min_(numTextures, static_cast<u32>(Driver->ActiveRenderTarget.size()));
for (u32 i = 0; i < Surfaces.size(); ++i)
{
if (Surfaces[i])
Surfaces[i]->Release();
}
Surfaces.set_used(size);
core::array<ITexture*> prevTextures(Textures);
Textures.set_used(size);
for (u32 i = 0; i < size; ++i)
{
CD3D9Texture* currentTexture = (textures[i] && textures[i]->getDriverType() == DriverType) ? static_cast<CD3D9Texture*>(textures[i]) : 0;
IDirect3DTexture9* textureID = 0;
IDirect3DCubeTexture9* cubeTextureId = 0;
UINT level = 0; // no support for rendering to to other mip-levels so far
if (currentTexture)
{
if (currentTexture->getType() == ETT_2D)
textureID = currentTexture->getDX9Texture();
else if ( currentTexture->getType() == ETT_CUBEMAP )
cubeTextureId = currentTexture->getDX9CubeTexture();
}
if (textureID)
{
Textures[i] = textures[i];
Textures[i]->grab();
IDirect3DSurface9* currentSurface = 0;
textureID->GetSurfaceLevel(level, &currentSurface);
Surfaces[i] = currentSurface;
}
else if ( cubeTextureId )
{
Textures[i] = textures[i];
Textures[i]->grab();
IDirect3DSurface9* currentSurface = 0;
D3DCUBEMAP_FACES face = (D3DCUBEMAP_FACES)CubeSurfaces[i]; // we use same numbering
cubeTextureId->GetCubeMapSurface(face, level, &currentSurface);
Surfaces[i] = currentSurface;
}
else
{
Surfaces[i] = 0;
Textures[i] = 0;
}
}
for (u32 i = 0; i < prevTextures.size(); ++i)
{
if (prevTextures[i])
prevTextures[i]->drop();
}
}
// Set depth and stencil attachments.
if (DepthStencil != depthStencil)
{
if (DepthStencilSurface)
{
DepthStencilSurface->Release();
DepthStencilSurface = 0;
}
if (DepthStencil)
{
DepthStencil->drop();
DepthStencil = 0;
DepthStencilSurface = 0;
}
needSizeUpdate = true;
CD3D9Texture* currentTexture = (depthStencil && depthStencil->getDriverType() == DriverType) ? static_cast<CD3D9Texture*>(depthStencil) : 0;
if (currentTexture)
{
if (currentTexture->getType() == ETT_2D)
{
IDirect3DTexture9* textureID = currentTexture->getDX9Texture();
if (textureID)
{
const ECOLOR_FORMAT textureFormat = depthStencil->getColorFormat();
if (IImage::isDepthFormat(textureFormat))
{
DepthStencil = depthStencil;
DepthStencil->grab();
IDirect3DSurface9* currentSurface = 0;
textureID->GetSurfaceLevel(0, &currentSurface);
DepthStencilSurface = currentSurface;
}
else
{
os::Printer::log("Ignoring depth/stencil texture without depth color format.", ELL_WARNING);
}
}
}
else
os::Printer::log("This driver doesn't support depth/stencil to cubemaps.", ELL_WARNING);
}
}
if (needSizeUpdate)
{
// Set size required for a viewport.
bool sizeDetected = false;
for (u32 i = 0; i < Textures.size(); ++i)
{
if (Textures[i])
{
Size = Textures[i]->getSize();
sizeDetected = true;
break;
}
}
if (!sizeDetected)
{
if (DepthStencil)
Size = DepthStencil->getSize();
else
Size = Driver->getScreenSize();
}
}
}
const core::dimension2d<u32>& CD3D9RenderTarget::getSize() const
{
return Size;
}
IDirect3DSurface9* CD3D9RenderTarget::getSurface(u32 id) const
{
return (id < Surfaces.size()) ? Surfaces[id] : 0;
}
u32 CD3D9RenderTarget::getSurfaceCount() const
{
return Surfaces.size();
}
IDirect3DSurface9* CD3D9RenderTarget::getDepthStencilSurface() const
{
return DepthStencilSurface;
}
void CD3D9RenderTarget::releaseSurfaces()
{
for (u32 i = 0; i < Surfaces.size(); ++i)
{
if (Surfaces[i])
{
Surfaces[i]->Release();
Surfaces[i] = 0;
}
}
if (DepthStencilSurface)
{
DepthStencilSurface->Release();
DepthStencilSurface = 0;
}
}
void CD3D9RenderTarget::generateSurfaces()
{
for (u32 i = 0; i < Surfaces.size(); ++i)
{
if (!Surfaces[i] && Textures[i])
{
IDirect3DTexture9* currentTexture = static_cast<CD3D9Texture*>(Textures[i])->getDX9Texture();
if ( currentTexture )
{
IDirect3DSurface9* currentSurface = 0;
currentTexture->GetSurfaceLevel(0, &currentSurface);
Surfaces[i] = currentSurface;
}
}
}
if (!DepthStencilSurface && DepthStencil)
{
IDirect3DTexture9* currentTexture = static_cast<CD3D9Texture*>(DepthStencil)->getDX9Texture();
if ( currentTexture )
{
IDirect3DSurface9* currentSurface = 0;
currentTexture->GetSurfaceLevel(0, &currentSurface);
DepthStencilSurface = currentSurface;
}
}
}
}
}
#endif