#include "BsMultiRenderTexture.h" #include "BsTexture.h" #include "BsException.h" #include "BsDebug.h" #include "BsCoreThread.h" #include "BsTextureManager.h" #include "BsFrameAlloc.h" #include "BsResources.h" namespace BansheeEngine { MultiRenderTextureProperties::MultiRenderTextureProperties(const MULTI_RENDER_TEXTURE_DESC& desc) { for (size_t i = 0; i < desc.colorSurfaces.size(); i++) { HTexture texture = desc.colorSurfaces[i].texture; if (texture != nullptr) { const TextureProperties& texProps = texture->getProperties(); construct(&texProps); break; } } } MultiRenderTextureProperties::MultiRenderTextureProperties(const MULTI_RENDER_TEXTURE_CORE_DESC& desc) { for (size_t i = 0; i < desc.colorSurfaces.size(); i++) { SPtr texture = desc.colorSurfaces[i].texture; if (texture != nullptr) { const TextureProperties& texProps = texture->getProperties(); construct(&texProps); break; } } } void MultiRenderTextureProperties::construct(const TextureProperties* props) { if (props == nullptr) return; mWidth = props->getWidth(); mHeight = props->getWidth(); mColorDepth = PixelUtil::getNumElemBits(props->getFormat()); mActive = true; mHwGamma = props->isHardwareGammaEnabled(); mMultisampleCount = props->getMultisampleCount(); mIsWindow = false; mRequiresTextureFlipping = requiresTextureFlipping(); } MultiRenderTextureCore::MultiRenderTextureCore(const MULTI_RENDER_TEXTURE_CORE_DESC& desc) :mDesc(desc) { } MultiRenderTextureCore::~MultiRenderTextureCore() { for (auto iter = mColorSurfaces.begin(); iter != mColorSurfaces.end(); ++iter) { if (*iter != nullptr) TextureCore::releaseView(*iter); } if (mDepthStencilSurface != nullptr) TextureCore::releaseView(mDepthStencilSurface); } void MultiRenderTextureCore::initialize() { RenderTargetCore::initialize(); mColorSurfaces.resize(BS_MAX_MULTIPLE_RENDER_TARGETS); for (size_t i = 0; i < mDesc.colorSurfaces.size(); i++) { if (mDesc.colorSurfaces[i].texture != nullptr) { if (i >= BS_MAX_MULTIPLE_RENDER_TARGETS) { LOGWRN("Render texture index is larger than the maximum number of supported render targets. Index: " + toString((int)i) + ". Max. number of render targets: " + toString(BS_MAX_MULTIPLE_RENDER_TARGETS)); continue; } SPtr texture = mDesc.colorSurfaces[i].texture; if (texture->getProperties().getUsage() != TU_RENDERTARGET) BS_EXCEPT(InvalidParametersException, "Provided texture is not created with render target usage."); mColorSurfaces[i] = TextureCore::requestView(texture, mDesc.colorSurfaces[i].mipLevel, 1, mDesc.colorSurfaces[i].face, 1, GVU_RENDERTARGET); } } if (mDesc.depthStencilSurface.texture != nullptr) { SPtr texture = mDesc.depthStencilSurface.texture; if (texture->getProperties().getUsage() != TU_DEPTHSTENCIL) BS_EXCEPT(InvalidParametersException, "Provided texture is not created with depth stencil usage."); mDepthStencilSurface = TextureCore::requestView(texture, mDesc.depthStencilSurface.mipLevel, 1, mDesc.depthStencilSurface.face, 1, GVU_DEPTHSTENCIL); } throwIfBuffersDontMatch(); } void MultiRenderTextureCore::syncToCore(const CoreSyncData& data) { MultiRenderTextureProperties& props = const_cast(getProperties()); props = data.getData(); } const MultiRenderTextureProperties& MultiRenderTextureCore::getProperties() const { return static_cast(getPropertiesInternal()); } void MultiRenderTextureCore::throwIfBuffersDontMatch() const { TextureViewPtr firstSurfaceDesc = nullptr; for(size_t i = 0; i < mColorSurfaces.size(); i++) { if(mColorSurfaces[i] == nullptr) continue; if(firstSurfaceDesc == nullptr) { firstSurfaceDesc = mColorSurfaces[i]; continue; } const TextureProperties& curTexProps = mColorSurfaces[i]->getTexture()->getProperties(); const TextureProperties& firstTexProps = firstSurfaceDesc->getTexture()->getProperties(); if (curTexProps.getWidth() != firstTexProps.getWidth() || curTexProps.getHeight() != firstTexProps.getHeight() || curTexProps.getMultisampleCount() != firstTexProps.getMultisampleCount()) { String errorInfo = "\nWidth: " + toString(curTexProps.getWidth()) + "/" + toString(firstTexProps.getWidth()); errorInfo += "\nHeight: " + toString(curTexProps.getHeight()) + "/" + toString(firstTexProps.getHeight()); errorInfo += "\nMultisample Count: " + toString(curTexProps.getMultisampleCount()) + "/" + toString(firstTexProps.getMultisampleCount()); BS_EXCEPT(InvalidParametersException, "Provided texture and depth stencil buffer don't match!" + errorInfo); } } if (firstSurfaceDesc != nullptr) { const TextureProperties& firstTexProps = firstSurfaceDesc->getTexture()->getProperties(); if (firstTexProps.getTextureType() != TEX_TYPE_2D) BS_EXCEPT(NotImplementedException, "Render textures are currently only implemented for 2D surfaces."); if ((firstSurfaceDesc->getFirstArraySlice() + firstSurfaceDesc->getNumArraySlices()) >= firstTexProps.getNumFaces()) { BS_EXCEPT(InvalidParametersException, "Provided number of faces is out of range. Face: " + toString(firstSurfaceDesc->getFirstArraySlice() + firstSurfaceDesc->getNumArraySlices()) + ". Max num faces: " + toString(firstTexProps.getNumFaces())); } if (firstSurfaceDesc->getMostDetailedMip() >= firstTexProps.getNumMipmaps()) { BS_EXCEPT(InvalidParametersException, "Provided number of mip maps is out of range. Mip level: " + toString(firstSurfaceDesc->getMostDetailedMip()) + ". Max num mipmaps: " + toString(firstTexProps.getNumMipmaps())); } if (mDepthStencilSurface == nullptr) return; const TextureProperties& depthTexProps = mDepthStencilSurface->getTexture()->getProperties(); if (depthTexProps.getWidth() != firstTexProps.getWidth() || depthTexProps.getHeight() != firstTexProps.getHeight() || depthTexProps.getMultisampleCount() != firstTexProps.getMultisampleCount()) { String errorInfo = "\nWidth: " + toString(depthTexProps.getWidth()) + "/" + toString(firstTexProps.getWidth()); errorInfo += "\nHeight: " + toString(depthTexProps.getHeight()) + "/" + toString(firstTexProps.getHeight()); errorInfo += "\nMultisample Count: " + toString(depthTexProps.getMultisampleCount()) + "/" + toString(firstTexProps.getMultisampleCount()); BS_EXCEPT(InvalidParametersException, "Provided texture and depth stencil buffer don't match!" + errorInfo); } } } void MultiRenderTextureCore::copyToMemory(PixelData &dst, FrameBuffer buffer) { throw std::exception("The method or operation is not implemented."); } MultiRenderTexture::MultiRenderTexture(const MULTI_RENDER_TEXTURE_DESC& desc) :mDesc(desc) { for (UINT32 i = 0; i < (UINT32)desc.colorSurfaces.size(); i++) { if (desc.colorSurfaces[i].texture != nullptr) mBindableColorTex.push_back(desc.colorSurfaces[i].texture); } if (desc.depthStencilSurface.texture != nullptr) mBindableDepthStencilTex = desc.depthStencilSurface.texture; } SPtr MultiRenderTexture::createCore() const { MULTI_RENDER_TEXTURE_CORE_DESC coreDesc; for (auto& colorSurface : mDesc.colorSurfaces) { RENDER_SURFACE_CORE_DESC surfaceDesc; if (colorSurface.texture.isLoaded()) surfaceDesc.texture = colorSurface.texture->getCore(); surfaceDesc.face = colorSurface.face; surfaceDesc.mipLevel = colorSurface.mipLevel; coreDesc.colorSurfaces.push_back(surfaceDesc); } if (mDesc.depthStencilSurface.texture.isLoaded()) coreDesc.depthStencilSurface.texture = mDesc.depthStencilSurface.texture->getCore(); coreDesc.depthStencilSurface.face = mDesc.depthStencilSurface.face; coreDesc.depthStencilSurface.mipLevel = mDesc.depthStencilSurface.mipLevel; return TextureCoreManager::instance().createMultiRenderTextureInternal(coreDesc); } SPtr MultiRenderTexture::getCore() const { return std::static_pointer_cast(mCoreSpecific); } MultiRenderTexturePtr MultiRenderTexture::create(const MULTI_RENDER_TEXTURE_DESC& desc) { return TextureManager::instance().createMultiRenderTexture(desc); } CoreSyncData MultiRenderTexture::syncToCore(FrameAlloc* allocator) { UINT32 size = sizeof(MultiRenderTextureProperties); UINT8* buffer = allocator->alloc(size); MultiRenderTextureProperties& props = const_cast(getProperties()); memcpy(buffer, &props, size); return CoreSyncData(buffer, size); } const MultiRenderTextureProperties& MultiRenderTexture::getProperties() const { return static_cast(getPropertiesInternal()); } UINT32 MultiRenderTexture::getColorSurfaceCount() const { return (UINT32)mDesc.colorSurfaces.size(); } }