irrlicht/source/Irrlicht/CD3D9RenderTarget.cpp
cutealien d03881b83a Reworking IRenderTarget interface to avoid constant memory allocations.
setTexture functions for single textures (more or less the usual case) IRenderTarget no longer need memory allocations 
on each call.
Also calling IRenderTarget::setTexture with a nullpointer no longer sets a rendertarget with an array which contains a single nullpointer but clears the array instead.


git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@6243 dfc29bdd-3216-0410-991c-e03cc46cb475
2021-08-26 16:45:20 +00:00

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