From 5b0e345b7156fb7d19ff7a70d0320165d72e5c42 Mon Sep 17 00:00:00 2001 From: ducphamhong Date: Thu, 23 Jul 2020 22:52:24 +0700 Subject: [PATCH] feat: #98 Add gpu read-write buffer --- Projects/Irrlicht/Include/IRWBuffer.h | 42 +++++++++++ Projects/Irrlicht/Include/IVideoDriver.h | 10 +++ Projects/Irrlicht/Source/CD3D11Driver.cpp | 8 +- Projects/Irrlicht/Source/CD3D11Driver.h | 4 + Projects/Irrlicht/Source/CD3D11RWBuffer.cpp | 73 +++++++++++++++++++ Projects/Irrlicht/Source/CD3D11RWBuffer.h | 46 ++++++++++++ Projects/Irrlicht/Source/CNullDriver.cpp | 7 +- Projects/Irrlicht/Source/CNullDriver.h | 4 + .../Source/Lightmapper/CGPUBaker.cpp | 51 +++++++++++++ .../Source/Lightmapper/CGPUBaker.h | 51 +++++++++++++ .../Source/Lightmapper/CLightmapper.cpp | 25 +++++-- .../Source/Lightmapper/CLightmapper.h | 2 + .../Source/Lightmapper/CMTBaker.cpp | 21 ++++-- .../Lightmapper/Source/Lightmapper/CMTBaker.h | 6 +- 14 files changed, 335 insertions(+), 15 deletions(-) create mode 100644 Projects/Irrlicht/Include/IRWBuffer.h create mode 100644 Projects/Irrlicht/Source/CD3D11RWBuffer.cpp create mode 100644 Projects/Irrlicht/Source/CD3D11RWBuffer.h create mode 100644 Projects/Skylicht/Lightmapper/Source/Lightmapper/CGPUBaker.cpp create mode 100644 Projects/Skylicht/Lightmapper/Source/Lightmapper/CGPUBaker.h diff --git a/Projects/Irrlicht/Include/IRWBuffer.h b/Projects/Irrlicht/Include/IRWBuffer.h new file mode 100644 index 000000000..ae76c3233 --- /dev/null +++ b/Projects/Irrlicht/Include/IRWBuffer.h @@ -0,0 +1,42 @@ +// Copyright (C) 2020 Pham Hong Duc +// This file is part of the "Skylicht Engine" +// Upgrade GPU Compute Shader feature + +#ifndef __IRR_IRW_BUFFER_H_INCLUDED__ +#define __IRR_IRW_BUFFER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#include "IReferenceCounted.h" +#include "IImage.h" +#include "dimension2d.h" +#include "EDriverTypes.h" +#include "path.h" +#include "matrix4.h" + +namespace irr +{ + namespace video + { + class IRWBuffer : public virtual IReferenceCounted + { + public: + IRWBuffer(ECOLOR_FORMAT format, u32 numElements) : + DriverType(EDT_NULL), + Format(format), + NumElements(numElements) + { + } + + E_DRIVER_TYPE getDriverType() const { return DriverType; }; + + protected: + + E_DRIVER_TYPE DriverType; + ECOLOR_FORMAT Format; + u32 NumElements; + }; + } +} + +#endif \ No newline at end of file diff --git a/Projects/Irrlicht/Include/IVideoDriver.h b/Projects/Irrlicht/Include/IVideoDriver.h index 6767201f5..00b25f087 100644 --- a/Projects/Irrlicht/Include/IVideoDriver.h +++ b/Projects/Irrlicht/Include/IVideoDriver.h @@ -21,6 +21,7 @@ #include "SExposedVideoData.h" #include "IHardwareBuffer.h" +#include "IRWBuffer.h" namespace irr { @@ -1108,6 +1109,15 @@ namespace video const core::position2d& pos, const core::dimension2d& size) =0; + //! Creates a buffer stored on gpu + /** + \param format pixel data. + \param number of pixels + \return The gpu buffer object. + If you no longer need the image, you should call IImage::drop(). + See IReferenceCounted::drop() for more information. */ + virtual IRWBuffer* createRWBuffer(video::ECOLOR_FORMAT format, u32 numElements) = 0; + //! Event handler for resize events. Only used by the engine internally. /** Used to notify the driver that the window was resized. Usually, there is no need to call this method. */ diff --git a/Projects/Irrlicht/Source/CD3D11Driver.cpp b/Projects/Irrlicht/Source/CD3D11Driver.cpp index 978bd8df8..0f1ad9d8c 100644 --- a/Projects/Irrlicht/Source/CD3D11Driver.cpp +++ b/Projects/Irrlicht/Source/CD3D11Driver.cpp @@ -21,7 +21,7 @@ #include "CD3D11Texture.h" #include "CD3D11HardwareBuffer.h" #include "CD3D11VideoRT.h" - +#include "CD3D11RWBuffer.h" inline void unpack_texureBlendFunc(irr::video::E_BLEND_FACTOR &srcFact, irr::video::E_BLEND_FACTOR &dstFact, irr::video::E_MODULATE_FUNC &modulo, irr::u32& alphaSource, const irr::f32 param) @@ -1412,6 +1412,12 @@ namespace irr return new CD3D11TextureCube(this, "TextureCube", imageX1, imageX2, imageY1, imageY2, imageZ1, imageZ2); } + //! creates a buffer stored on gpu + IRWBuffer* CD3D11Driver::createRWBuffer(video::ECOLOR_FORMAT format, u32 numElements) + { + return new CD3D11RWBuffer(this, format, numElements); + } + void CD3D11Driver::setViewPort(const core::rect& area) { core::dimension2du size = getCurrentRenderTargetSize(); diff --git a/Projects/Irrlicht/Source/CD3D11Driver.h b/Projects/Irrlicht/Source/CD3D11Driver.h index d8da27dd2..e4e707cba 100644 --- a/Projects/Irrlicht/Source/CD3D11Driver.h +++ b/Projects/Irrlicht/Source/CD3D11Driver.h @@ -61,6 +61,7 @@ namespace video friend class CD3D11TextureCube; friend class CD3D11TextureArray; friend class CD3D11VideoRT; + friend class CD3D11RWBuffer; //! constructor CD3D11Driver(const irr::SIrrlichtCreationParameters& params, @@ -220,6 +221,9 @@ namespace video virtual ITexture* getTextureArray(IImage** images, u32 num); + //! creates a buffer stored on gpu + virtual IRWBuffer* createRWBuffer(video::ECOLOR_FORMAT format, u32 numElements); + //! Clears the ZBuffer. virtual void clearZBuffer(); diff --git a/Projects/Irrlicht/Source/CD3D11RWBuffer.cpp b/Projects/Irrlicht/Source/CD3D11RWBuffer.cpp new file mode 100644 index 000000000..97c38d9f6 --- /dev/null +++ b/Projects/Irrlicht/Source/CD3D11RWBuffer.cpp @@ -0,0 +1,73 @@ +// Copyright (C) 2020 Pham Hong Duc +// This file is part of the "Skylicht Engine" +// Upgrade GPU Compute Shader feature + +#include "pch.h" +#include "IrrCompileConfig.h" +#include "CD3D11Driver.h" +#include "CD3D11RWBuffer.h" + +#ifdef _IRR_COMPILE_WITH_DIRECT3D_11_ + +#define _IRR_DONT_DO_MEMORY_DEBUGGING_HERE + +#include "irrOS.h" + +namespace irr +{ + namespace video + { + CD3D11RWBuffer::CD3D11RWBuffer(CD3D11Driver *driver, ECOLOR_FORMAT format, u32 numElements) : + IRWBuffer(format, numElements), + Driver(driver) + { + DriverType = EDT_DIRECT3D11; + + D3DFormat = Driver->getD3DFormatFromColorFormat(format); + u32 bytePerPixel = Driver->getBitsPerPixel(D3DFormat) / 8; + + Device = driver->getExposedVideoData().D3D11.D3DDev11; + if (Device) + { + Device->AddRef(); + Device->GetImmediateContext(&Context); + } + + D3D11_BUFFER_DESC bufferDesc; + bufferDesc.ByteWidth = bytePerPixel * numElements; + bufferDesc.Usage = D3D11_USAGE_DEFAULT; + bufferDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS; + bufferDesc.CPUAccessFlags = 0; + bufferDesc.MiscFlags = 0; + bufferDesc.StructureByteStride = 0; + Device->CreateBuffer(&bufferDesc, NULL, &Buffer); + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = D3DFormat; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + srvDesc.Buffer.ElementOffset = 0; + srvDesc.Buffer.ElementWidth = numElements; + Device->CreateShaderResourceView(Buffer, &srvDesc, &SRView); + + D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; + uavDesc.Format = D3DFormat; + uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; + uavDesc.Buffer.FirstElement = 0; + uavDesc.Buffer.Flags = 0; + uavDesc.Buffer.NumElements = numElements; + Device->CreateUnorderedAccessView(Buffer, &uavDesc, &UAView); + } + + CD3D11RWBuffer::~CD3D11RWBuffer() + { + SRView->Release(); + UAView->Release(); + Buffer->Release(); + + Context->Release(); + Device->Release(); + } + } +} + +#endif \ No newline at end of file diff --git a/Projects/Irrlicht/Source/CD3D11RWBuffer.h b/Projects/Irrlicht/Source/CD3D11RWBuffer.h new file mode 100644 index 000000000..6d753ef38 --- /dev/null +++ b/Projects/Irrlicht/Source/CD3D11RWBuffer.h @@ -0,0 +1,46 @@ +// Copyright (C) 2020 Pham Hong Duc +// This file is part of the "Skylicht Engine" +// Upgrade GPU Compute Shader feature + +#ifndef __C_DIRECTX11_RWBUFFER_H_INCLUDED__ +#define __C_DIRECTX11_RWBUFFER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_WINDOWS_ +#ifdef _IRR_COMPILE_WITH_DIRECT3D_11_ + +#include "IRWBuffer.h" + +namespace irr +{ + namespace video + { + class CD3D11Driver; + + class CD3D11RWBuffer : public IRWBuffer + { + public: + CD3D11RWBuffer(CD3D11Driver *driver, ECOLOR_FORMAT format, u32 numElements); + + ~CD3D11RWBuffer(); + + protected: + + CD3D11Driver *Driver; + + ID3D11Device* Device; + ID3D11DeviceContext* Context; + + ID3D11Buffer* Buffer; + ID3D11ShaderResourceView* SRView; + ID3D11UnorderedAccessView* UAView; + + DXGI_FORMAT D3DFormat; + }; +} +} + +#endif +#endif +#endif \ No newline at end of file diff --git a/Projects/Irrlicht/Source/CNullDriver.cpp b/Projects/Irrlicht/Source/CNullDriver.cpp index fd526ea9a..b8ffdb1ed 100644 --- a/Projects/Irrlicht/Source/CNullDriver.cpp +++ b/Projects/Irrlicht/Source/CNullDriver.cpp @@ -786,7 +786,6 @@ void CNullDriver::addTexture(video::ITexture* texture) } } - //! looks if the image is already loaded video::ITexture* CNullDriver::findTexture(const io::path& filename) { @@ -842,7 +841,10 @@ ITexture* CNullDriver::addTexture(const core::dimension2d& size, return t; } - +IRWBuffer* CNullDriver::createRWBuffer(video::ECOLOR_FORMAT format, u32 numElements) +{ + return NULL; +} //! returns a device dependent texture from a software surface (IImage) //! THIS METHOD HAS TO BE OVERRIDDEN BY DERIVED DRIVERS WITH OWN TEXTURES @@ -2677,7 +2679,6 @@ bool CNullDriver::setClipPlane(u32 index, const core::plane3df& plane, bool enab return false; } - //! Enable/disable a clipping plane. void CNullDriver::enableClipPlane(u32 index, bool enable) { diff --git a/Projects/Irrlicht/Source/CNullDriver.h b/Projects/Irrlicht/Source/CNullDriver.h index 943d028d9..fd34ca93f 100644 --- a/Projects/Irrlicht/Source/CNullDriver.h +++ b/Projects/Irrlicht/Source/CNullDriver.h @@ -145,6 +145,9 @@ namespace video bool clearZBuffer, SColor color) _IRR_OVERRIDE_; + //! creates a buffer stored on gpu + virtual IRWBuffer* createRWBuffer(video::ECOLOR_FORMAT format, u32 numElements) _IRR_OVERRIDE_; + //! sets a viewport virtual void setViewPort(const core::rect& area) _IRR_OVERRIDE_; @@ -660,6 +663,7 @@ namespace video core::array Textures; core::array VRTs; + core::array RWBuffers; struct SOccQuery { diff --git a/Projects/Skylicht/Lightmapper/Source/Lightmapper/CGPUBaker.cpp b/Projects/Skylicht/Lightmapper/Source/Lightmapper/CGPUBaker.cpp new file mode 100644 index 000000000..9c4d4c9b8 --- /dev/null +++ b/Projects/Skylicht/Lightmapper/Source/Lightmapper/CGPUBaker.cpp @@ -0,0 +1,51 @@ +/* +!@ +MIT License + +Copyright (c) 2020 Skylicht Technology CO., LTD + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files +(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +This file is part of the "Skylicht Engine". +https://github.com/skylicht-lab/skylicht-engine +!# +*/ + +#include "pch.h" +#include "CGPUBaker.h" + +namespace Skylicht +{ + namespace Lightmapper + { + CGPUBaker::CGPUBaker() + { + m_shBuffer = getVideoDriver()->createRWBuffer(video::ECF_A32B32G32R32F, MAX_NUM_THREAD * 9); + } + + CGPUBaker::~CGPUBaker() + { + if (m_shBuffer != NULL) + m_shBuffer->drop(); + } + + bool CGPUBaker::canUseGPUBaker() + { + if (getVideoDriver()->getDriverType() == video::EDT_DIRECT3D11 && m_shBuffer != NULL) + return true; + + return false; + } + } +} \ No newline at end of file diff --git a/Projects/Skylicht/Lightmapper/Source/Lightmapper/CGPUBaker.h b/Projects/Skylicht/Lightmapper/Source/Lightmapper/CGPUBaker.h new file mode 100644 index 000000000..2b2824499 --- /dev/null +++ b/Projects/Skylicht/Lightmapper/Source/Lightmapper/CGPUBaker.h @@ -0,0 +1,51 @@ +/* +!@ +MIT License + +Copyright (c) 2020 Skylicht Technology CO., LTD + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files +(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +This file is part of the "Skylicht Engine". +https://github.com/skylicht-lab/skylicht-engine +!# +*/ + +#pragma once + +#include "CSH9.h" +#include "Camera/CCamera.h" +#include "RenderPipeline/IRenderPipeline.h" +#include "Entity/CEntityManager.h" + +#include "CMTBaker.h" + +namespace Skylicht +{ + namespace Lightmapper + { + class CGPUBaker : public CMTBaker + { + protected: + IRWBuffer *m_shBuffer; + + public: + CGPUBaker(); + + virtual ~CGPUBaker(); + + bool canUseGPUBaker(); + }; + } +} \ No newline at end of file diff --git a/Projects/Skylicht/Lightmapper/Source/Lightmapper/CLightmapper.cpp b/Projects/Skylicht/Lightmapper/Source/Lightmapper/CLightmapper.cpp index 6d61f7cf0..004b967e4 100644 --- a/Projects/Skylicht/Lightmapper/Source/Lightmapper/CLightmapper.cpp +++ b/Projects/Skylicht/Lightmapper/Source/Lightmapper/CLightmapper.cpp @@ -34,7 +34,8 @@ namespace Skylicht CLightmapper::CLightmapper() : m_singleBaker(NULL), - m_multiBaker(NULL) + m_multiBaker(NULL), + m_gpuBaker(NULL) { } @@ -46,6 +47,9 @@ namespace Skylicht if (m_multiBaker != NULL) delete m_multiBaker; + + if (m_gpuBaker != NULL) + delete m_gpuBaker; } void CLightmapper::initBaker(u32 hemisphereBakeSize) @@ -56,10 +60,14 @@ namespace Skylicht if (m_multiBaker != NULL) delete m_multiBaker; + if (m_gpuBaker != NULL) + delete m_gpuBaker; + s_hemisphereBakeSize = hemisphereBakeSize; m_singleBaker = new CBaker(); m_multiBaker = new CMTBaker(); + m_gpuBaker = new CGPUBaker(); } const CSH9& CLightmapper::bakeAtPosition( @@ -90,14 +98,21 @@ namespace Skylicht int numFace) { out.clear(); - + if (m_multiBaker == NULL) { os::Printer::log("[CLightmapper::bakeAtPosition] Need call initBaker first"); return; } - int maxMT = m_multiBaker->getMaxMT(); + // default use multi thread bakder + CMTBaker *baker = m_multiBaker; + + // switch gpu if supported + if (m_gpuBaker->canUseGPUBaker() == true) + baker = m_gpuBaker; + + int maxMT = baker->getMaxMT(); int current = 0; while (current < count) @@ -106,7 +121,7 @@ namespace Skylicht numMT = core::min_(numMT, maxMT); // bake and get SH result - m_multiBaker->bake(camera, + baker->bake(camera, rp, entityMgr, position + current, @@ -117,7 +132,7 @@ namespace Skylicht numFace); for (int i = 0; i < numMT; i++) - out.push_back(m_multiBaker->getSH(i)); + out.push_back(baker->getSH(i)); current += numMT; } diff --git a/Projects/Skylicht/Lightmapper/Source/Lightmapper/CLightmapper.h b/Projects/Skylicht/Lightmapper/Source/Lightmapper/CLightmapper.h index c260436a2..0748e6e1c 100644 --- a/Projects/Skylicht/Lightmapper/Source/Lightmapper/CLightmapper.h +++ b/Projects/Skylicht/Lightmapper/Source/Lightmapper/CLightmapper.h @@ -27,6 +27,7 @@ This file is part of the "Skylicht Engine". #include "Utils/CGameSingleton.h" #include "CBaker.h" #include "CMTBaker.h" +#include "CGPUBaker.h" #include "Components/Probe/CLightProbe.h" namespace Skylicht @@ -42,6 +43,7 @@ namespace Skylicht protected: CBaker *m_singleBaker; CMTBaker *m_multiBaker; + CGPUBaker *m_gpuBaker; CSH9 m_temp; diff --git a/Projects/Skylicht/Lightmapper/Source/Lightmapper/CMTBaker.cpp b/Projects/Skylicht/Lightmapper/Source/Lightmapper/CMTBaker.cpp index e83ea9703..4033e51eb 100644 --- a/Projects/Skylicht/Lightmapper/Source/Lightmapper/CMTBaker.cpp +++ b/Projects/Skylicht/Lightmapper/Source/Lightmapper/CMTBaker.cpp @@ -53,6 +53,7 @@ namespace Skylicht { IVideoDriver *driver = getVideoDriver(); + // render radiance // apply projection camera->setAspect(1.0f); camera->setFOV(90.0f); @@ -60,8 +61,6 @@ namespace Skylicht // clear rtt getVideoDriver()->setRenderTarget(m_radiance, true, true); - core::matrix4 toTangentSpace[MAX_NUM_THREAD][NUM_FACES]; - u32 rtSize = CLightmapper::getHemisphereBakeSize(); for (int tid = 0; tid < count; tid++) @@ -76,8 +75,10 @@ namespace Skylicht getWorldView(normal[tid], tangent[tid], binormal[tid], position[tid], face, cameraWorld); // to tangent space - toTangentSpace[tid][face] = cameraWorld; - setRow(toTangentSpace[tid][face], 3, core::vector3df(0.0f, 0.0f, 0.0f), 1.0f); + m_toTangentSpace[tid * NUM_FACES + face] = cameraWorld; + + // remove position + setRow(m_toTangentSpace[tid * NUM_FACES + face], 3, core::vector3df(0.0f, 0.0f, 0.0f), 1.0f); // camera world camera->getGameObject()->getTransform()->setMatrixTransform(cameraWorld); @@ -101,6 +102,15 @@ namespace Skylicht driver->setRenderTarget(NULL, false, false); + // compute sh from radiance + computeSH(count, numFace); + } + + void CMTBaker::computeSH(int count, int numFace) + { + // render target size + u32 rtSize = CLightmapper::getHemisphereBakeSize(); + // Cubemap to SH u8 *imageData = (u8*)m_radiance->lock(video::ETLM_READ_ONLY); u32 bpp = 4; @@ -173,7 +183,8 @@ namespace Skylicht dirTS.X = u; dirTS.Y = v; dirTS.Z = 1.0f; - toTangentSpace[tid][face].rotateVect(dirTS); + + m_toTangentSpace[tid * NUM_FACES + face].rotateVect(dirTS); dirTS.normalize(); m_sh[tid].projectAddOntoSH(dirTS, color); diff --git a/Projects/Skylicht/Lightmapper/Source/Lightmapper/CMTBaker.h b/Projects/Skylicht/Lightmapper/Source/Lightmapper/CMTBaker.h index 7d4d9ffde..e6a2103b4 100644 --- a/Projects/Skylicht/Lightmapper/Source/Lightmapper/CMTBaker.h +++ b/Projects/Skylicht/Lightmapper/Source/Lightmapper/CMTBaker.h @@ -44,6 +44,8 @@ namespace Skylicht CSH9 m_sh[MAX_NUM_THREAD]; + core::matrix4 m_toTangentSpace[MAX_NUM_THREAD * NUM_FACES]; + float m_weightSum; public: @@ -51,7 +53,7 @@ namespace Skylicht virtual ~CMTBaker(); - void bake(CCamera *camera, + virtual void bake(CCamera *camera, IRenderPipeline* rp, CEntityManager* entityMgr, const core::vector3df* position, @@ -61,6 +63,8 @@ namespace Skylicht int count, int numFace); + virtual void computeSH(int count, int numFace); + inline int getMaxMT() { return MAX_NUM_THREAD;