From b0764790237f7f353d6e0a7c23b3f396bfad3f36 Mon Sep 17 00:00:00 2001 From: ducphamhong Date: Fri, 24 Jul 2020 22:41:17 +0700 Subject: [PATCH] feat: #98 Implete compile compute shader --- Projects/Irrlicht/Include/IGPUCompute.h | 45 ++++ .../Include/IGPUProgrammingServices.h | 11 + Projects/Irrlicht/Include/IRWBuffer.h | 4 - Projects/Irrlicht/Include/IVideoDriver.h | 2 +- Projects/Irrlicht/Source/CD3D11Driver.cpp | 18 +- Projects/Irrlicht/Source/CD3D11Driver.h | 7 +- Projects/Irrlicht/Source/CD3D11GPUCompute.cpp | 192 ++++++++++++++++++ Projects/Irrlicht/Source/CD3D11GPUCompute.h | 55 +++++ Projects/Irrlicht/Source/CD3D11RWBuffer.cpp | 18 +- Projects/Irrlicht/Source/CD3D11RWBuffer.h | 12 +- Projects/Irrlicht/Source/CNullDriver.cpp | 50 ++++- Projects/Irrlicht/Source/CNullDriver.h | 10 +- 12 files changed, 410 insertions(+), 14 deletions(-) create mode 100644 Projects/Irrlicht/Include/IGPUCompute.h create mode 100644 Projects/Irrlicht/Source/CD3D11GPUCompute.cpp create mode 100644 Projects/Irrlicht/Source/CD3D11GPUCompute.h diff --git a/Projects/Irrlicht/Include/IGPUCompute.h b/Projects/Irrlicht/Include/IGPUCompute.h new file mode 100644 index 000000000..29aa84e34 --- /dev/null +++ b/Projects/Irrlicht/Include/IGPUCompute.h @@ -0,0 +1,45 @@ +// Copyright (C) 2020 Pham Hong Duc +// This file is part of the "Skylicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h +// Add irrlicht compute shader feature + +#ifndef __I_GPU_COMPUTE_H_INCLUDED__ +#define __I_GPU_COMPUTE_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#include "IReferenceCounted.h" +#include "EDriverTypes.h" + +namespace irr +{ + namespace video + { + class IRWBuffer; + class ITexture; + + class IGPUCompute : public virtual IReferenceCounted + { + public: + IGPUCompute() : + DriverType(EDT_NULL) + { + + } + + E_DRIVER_TYPE getDriverType() const { return DriverType; }; + + virtual void setTexture(int slot, ITexture *texture) = 0; + + virtual void setBuffer(int slot, IRWBuffer *buffer) = 0; + + virtual void dispatch(int threadGroupX, int threadGroupY, int threadGroupZ) = 0; + + protected: + + E_DRIVER_TYPE DriverType; + }; + } +} + +#endif \ No newline at end of file diff --git a/Projects/Irrlicht/Include/IGPUProgrammingServices.h b/Projects/Irrlicht/Include/IGPUProgrammingServices.h index 28717d5ed..97a7fc53f 100644 --- a/Projects/Irrlicht/Include/IGPUProgrammingServices.h +++ b/Projects/Irrlicht/Include/IGPUProgrammingServices.h @@ -10,6 +10,8 @@ #include "EPrimitiveTypes.h" #include "path.h" +#include "IGPUCompute.h" + namespace irr { @@ -23,6 +25,7 @@ namespace video class IVideoDriver; class IShaderConstantSetCallBack; +class IGPUCompute; //! Enumeration for different types of shading languages enum E_GPU_SHADING_LANGUAGE @@ -124,6 +127,14 @@ class IGPUProgrammingServices callback, baseMaterial, userData, shadingLang); } + virtual IGPUCompute* createComputeProgram(const c8* computeShaderProgram, + const c8* computeShaderEntryPointName = "main", + E_COMPUTE_SHADER_TYPE csCompileTarget = ECST_CS_5_0) = 0; + + virtual IGPUCompute* createComputeProgramFromFile(const io::path& computeShaderFileName, + const c8* computeShaderEntryPointName = "main", + E_COMPUTE_SHADER_TYPE csCompileTarget = ECST_CS_5_0) = 0; + //! convenience function for use with many defaults, without geometry shader /** All shader names are set to "main" and compile targets are shader type 1.1. diff --git a/Projects/Irrlicht/Include/IRWBuffer.h b/Projects/Irrlicht/Include/IRWBuffer.h index ae76c3233..0cfc5e17c 100644 --- a/Projects/Irrlicht/Include/IRWBuffer.h +++ b/Projects/Irrlicht/Include/IRWBuffer.h @@ -8,11 +8,7 @@ #include "IrrCompileConfig.h" #include "IReferenceCounted.h" -#include "IImage.h" -#include "dimension2d.h" #include "EDriverTypes.h" -#include "path.h" -#include "matrix4.h" namespace irr { diff --git a/Projects/Irrlicht/Include/IVideoDriver.h b/Projects/Irrlicht/Include/IVideoDriver.h index 00b25f087..fb8493c58 100644 --- a/Projects/Irrlicht/Include/IVideoDriver.h +++ b/Projects/Irrlicht/Include/IVideoDriver.h @@ -1116,7 +1116,7 @@ namespace video \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; + virtual IRWBuffer* createRWBuffer(video::ECOLOR_FORMAT format, u32 numElements, void *initialData = NULL) = 0; //! Event handler for resize events. Only used by the engine internally. /** Used to notify the driver that the window was resized. diff --git a/Projects/Irrlicht/Source/CD3D11Driver.cpp b/Projects/Irrlicht/Source/CD3D11Driver.cpp index 0f1ad9d8c..b584a5116 100644 --- a/Projects/Irrlicht/Source/CD3D11Driver.cpp +++ b/Projects/Irrlicht/Source/CD3D11Driver.cpp @@ -22,6 +22,7 @@ #include "CD3D11HardwareBuffer.h" #include "CD3D11VideoRT.h" #include "CD3D11RWBuffer.h" +#include "CD3D11GPUCompute.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) @@ -1413,7 +1414,7 @@ namespace irr } //! creates a buffer stored on gpu - IRWBuffer* CD3D11Driver::createRWBuffer(video::ECOLOR_FORMAT format, u32 numElements) + IRWBuffer* CD3D11Driver::createRWBuffer(video::ECOLOR_FORMAT format, u32 numElements, void *initialData) { return new CD3D11RWBuffer(this, format, numElements); } @@ -2807,6 +2808,21 @@ namespace irr return id; } + IGPUCompute* CD3D11Driver::createComputeProgram(const c8* computeShaderProgram, + const c8* computeShaderEntryPointName, + E_COMPUTE_SHADER_TYPE csCompileTarget) + { + CD3D11GPUCompute *compute = new CD3D11GPUCompute(this); + + if (compute->compile(computeShaderProgram, computeShaderEntryPointName, csCompileTarget) == true) + { + return compute; + } + + compute->drop(); + return NULL; + } + //! Adds a new material renderer to the VideoDriver, using pixel and/or //! vertex shaders to render geometry. s32 CD3D11Driver::addShaderMaterial(const c8* vertexShaderProgram, diff --git a/Projects/Irrlicht/Source/CD3D11Driver.h b/Projects/Irrlicht/Source/CD3D11Driver.h index e4e707cba..eb95edd78 100644 --- a/Projects/Irrlicht/Source/CD3D11Driver.h +++ b/Projects/Irrlicht/Source/CD3D11Driver.h @@ -62,6 +62,7 @@ namespace video friend class CD3D11TextureArray; friend class CD3D11VideoRT; friend class CD3D11RWBuffer; + friend class CD3D11GPUCompute; //! constructor CD3D11Driver(const irr::SIrrlichtCreationParameters& params, @@ -222,7 +223,7 @@ namespace video virtual ITexture* getTextureArray(IImage** images, u32 num); //! creates a buffer stored on gpu - virtual IRWBuffer* createRWBuffer(video::ECOLOR_FORMAT format, u32 numElements); + virtual IRWBuffer* createRWBuffer(video::ECOLOR_FORMAT format, u32 numElements, void *initialData = NULL); //! Clears the ZBuffer. virtual void clearZBuffer(); @@ -416,6 +417,10 @@ namespace video virtual s32 addShaderMaterial(const c8* vertexShaderProgram, const c8* pixelShaderProgram, IShaderConstantSetCallBack* callback, E_MATERIAL_TYPE baseMaterial, s32 userData); + virtual IGPUCompute* createComputeProgram(const c8* computeShaderProgram, + const c8* computeShaderEntryPointName = "main", + E_COMPUTE_SHADER_TYPE csCompileTarget = ECST_CS_5_0); + void draw2D3DVertexPrimitiveList(const void* vertices, u32 vertexCount, u32 pVertexSize, const void* indices, u32 primitiveCount, E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType, bool is3D, u32 numInstances = 0); diff --git a/Projects/Irrlicht/Source/CD3D11GPUCompute.cpp b/Projects/Irrlicht/Source/CD3D11GPUCompute.cpp new file mode 100644 index 000000000..11bbf52e2 --- /dev/null +++ b/Projects/Irrlicht/Source/CD3D11GPUCompute.cpp @@ -0,0 +1,192 @@ +// 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 "CD3D11Texture.h" +#include "CD3D11RWBuffer.h" +#include "CD3D11GPUCompute.h" + +#ifdef _IRR_COMPILE_WITH_DIRECT3D_11_ + +#include "irrOS.h" + +#include "d3dcompiler.h" + +namespace irr +{ + namespace video + { + CD3D11GPUCompute::CD3D11GPUCompute(CD3D11Driver *driver) : + ComputeShader(NULL), + ShaderBuffer(NULL) + { + DriverType = EDT_DIRECT3D11; + + Device = driver->getExposedVideoData().D3D11.D3DDev11; + if (Device) + { + Device->AddRef(); + Device->GetImmediateContext(&Context); + } + + for (int i = 0; i < NUM_PARAMS_SUPPORT; i++) + { + TextureSlot[i] = NULL; + BufferSlot[i] = NULL; + } + } + + CD3D11GPUCompute::~CD3D11GPUCompute() + { + Device->Release(); + Context->Release(); + + if (ComputeShader != NULL) + ComputeShader->Release(); + + if (ShaderBuffer != NULL) + ShaderBuffer->Release(); + } + + bool CD3D11GPUCompute::compile(const c8* computeShaderProgram, + const c8* computeShaderEntryPointName, + E_COMPUTE_SHADER_TYPE csCompileTarget) + { + ID3D10Blob* errorMsgs = 0; + + ID3DInclude* includer = NULL; + + UINT flags = 0; + +#if !defined(WINDOWS_STORE) + if (csCompileTarget >= ECST_CS_5_0) + flags |= D3D10_SHADER_ENABLE_STRICTNESS; + else + { + flags |= D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY; + csCompileTarget = ECST_CS_4_0; + } + +#ifdef _DEBUG + // These values allow use of PIX and shader debuggers + flags |= D3D10_SHADER_DEBUG; + flags |= D3D10_SHADER_SKIP_OPTIMIZATION; +#else + // These flags allow maximum performance + flags |= D3D10_SHADER_OPTIMIZATION_LEVEL3; +#endif + + flags |= D3D10_SHADER_OPTIMIZATION_LEVEL3; +#endif + + // last macro has to be NULL + core::array macroArray; + + D3D_SHADER_MACRO macro; + macro.Definition = NULL; + macro.Name = NULL; + + macroArray.push_back(macro); + + HRESULT hr = D3DCompile( + computeShaderProgram, + strlen(computeShaderProgram), + "", + ¯oArray[0], + includer, + computeShaderEntryPointName, + COMPUTE_SHADER_TYPE_NAMES[csCompileTarget], + flags, 0, + &ShaderBuffer, + &errorMsgs); + + if (FAILED(hr)) + { + core::stringc errorMsg = "Could not compile shader"; + + if (errorMsgs) + { + errorMsg += ": "; + errorMsg += static_cast(errorMsgs->GetBufferPointer()); + + errorMsgs->Release(); + } + + logFormatError(hr, errorMsg); + + return false; + } +#ifdef _DEBUG + else if (errorMsgs) + { + core::stringc errorMsg = "Shader compilation warning: "; + errorMsg += static_cast(errorMsgs->GetBufferPointer()); + + errorMsgs->Release(); + errorMsgs = NULL; + + os::Printer::log(errorMsg.c_str(), ELL_WARNING); + } +#endif + + if (errorMsgs) + errorMsgs->Release(); + + if (!ShaderBuffer) + return false; + + hr = Device->CreateComputeShader( + ShaderBuffer->GetBufferPointer(), + ShaderBuffer->GetBufferSize(), + NULL, + &ComputeShader); + + if (FAILED(hr)) + { + core::stringc errorMsg = "Could not create computeshader"; + logFormatError(hr, errorMsg); + return false; + } + + return true; + } + + void CD3D11GPUCompute::setTexture(int slot, ITexture *texture) + { + TextureSlot[slot] = texture; + } + + void CD3D11GPUCompute::setBuffer(int slot, IRWBuffer *buffer) + { + BufferSlot[slot] = buffer; + } + + void CD3D11GPUCompute::dispatch(int threadGroupX, int threadGroupY, int threadGroupZ) + { + Context->CSSetShader(ComputeShader, NULL, 0); + + for (int i = 0; i < NUM_PARAMS_SUPPORT; i++) + { + // Texture resource view + ID3D11ShaderResourceView* views = NULL; + if (TextureSlot[i]) + views = ((CD3D11Texture*)TextureSlot[i])->getShaderResourceView(); + Context->CSSetShaderResources(i, 1, &views); + + // Buffer unorderred access view + ID3D11UnorderedAccessView* unorderedAccessView; + if (BufferSlot[i]) + unorderedAccessView = ((CD3D11RWBuffer*)BufferSlot[i])->getUnorderedAccessView(); + Context->CSSetUnorderedAccessViews(i, 1, &unorderedAccessView, NULL); + } + + // do gpu compute + Context->Dispatch(threadGroupX, threadGroupY, threadGroupZ); + } + } +} + +#endif \ No newline at end of file diff --git a/Projects/Irrlicht/Source/CD3D11GPUCompute.h b/Projects/Irrlicht/Source/CD3D11GPUCompute.h new file mode 100644 index 000000000..0004ed530 --- /dev/null +++ b/Projects/Irrlicht/Source/CD3D11GPUCompute.h @@ -0,0 +1,55 @@ +// Copyright (C) 2020 Pham Hong Duc +// This file is part of the "Skylicht Engine" +// Upgrade GPU Compute Shader feature + +#ifndef __C_DIRECTX11_GPUCOMPUTE_H_INCLUDED__ +#define __C_DIRECTX11_GPUCOMPUTE_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_WINDOWS_ +#ifdef _IRR_COMPILE_WITH_DIRECT3D_11_ + +#define NUM_PARAMS_SUPPORT 4 + +#include "IGPUCompute.h" + +namespace irr +{ + namespace video + { + class CD3D11Driver; + + class CD3D11GPUCompute : public IGPUCompute + { + protected: + ID3D11Device* Device; + ID3D11DeviceContext* Context; + + ID3D11ComputeShader *ComputeShader; + ID3D10Blob* ShaderBuffer; + + ITexture *TextureSlot[NUM_PARAMS_SUPPORT]; + IRWBuffer *BufferSlot[NUM_PARAMS_SUPPORT]; + + public: + CD3D11GPUCompute(CD3D11Driver *driver); + + virtual ~CD3D11GPUCompute(); + + bool compile(const c8* computeShaderProgram, + const c8* computeShaderEntryPointName = "main", + E_COMPUTE_SHADER_TYPE csCompileTarget = ECST_CS_5_0); + + virtual void setTexture(int slot, ITexture *texture); + + virtual void setBuffer(int slot, IRWBuffer *buffer); + + virtual void dispatch(int threadGroupX, int threadGroupY, int threadGroupZ); + }; + } +} + +#endif +#endif +#endif \ No newline at end of file diff --git a/Projects/Irrlicht/Source/CD3D11RWBuffer.cpp b/Projects/Irrlicht/Source/CD3D11RWBuffer.cpp index 97c38d9f6..963359f23 100644 --- a/Projects/Irrlicht/Source/CD3D11RWBuffer.cpp +++ b/Projects/Irrlicht/Source/CD3D11RWBuffer.cpp @@ -9,15 +9,13 @@ #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) : + CD3D11RWBuffer::CD3D11RWBuffer(CD3D11Driver *driver, ECOLOR_FORMAT format, u32 numElements, void *initialData) : IRWBuffer(format, numElements), Driver(driver) { @@ -40,7 +38,19 @@ namespace irr bufferDesc.CPUAccessFlags = 0; bufferDesc.MiscFlags = 0; bufferDesc.StructureByteStride = 0; - Device->CreateBuffer(&bufferDesc, NULL, &Buffer); + + if (initialData == NULL) + Device->CreateBuffer(&bufferDesc, NULL, &Buffer); + else + { + // Load initial data + D3D11_SUBRESOURCE_DATA data; + data.pSysMem = initialData; + data.SysMemPitch = 0; + data.SysMemSlicePitch = 0; + + Device->CreateBuffer(&bufferDesc, &data, &Buffer); + } D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.Format = D3DFormat; diff --git a/Projects/Irrlicht/Source/CD3D11RWBuffer.h b/Projects/Irrlicht/Source/CD3D11RWBuffer.h index 6d753ef38..30d9e85b8 100644 --- a/Projects/Irrlicht/Source/CD3D11RWBuffer.h +++ b/Projects/Irrlicht/Source/CD3D11RWBuffer.h @@ -21,10 +21,20 @@ namespace irr class CD3D11RWBuffer : public IRWBuffer { public: - CD3D11RWBuffer(CD3D11Driver *driver, ECOLOR_FORMAT format, u32 numElements); + CD3D11RWBuffer(CD3D11Driver *driver, ECOLOR_FORMAT format, u32 numElements, void *initialData = NULL); ~CD3D11RWBuffer(); + ID3D11ShaderResourceView *getShaderResourceView() + { + return SRView; + } + + ID3D11UnorderedAccessView *getUnorderedAccessView() + { + return UAView; + } + protected: CD3D11Driver *Driver; diff --git a/Projects/Irrlicht/Source/CNullDriver.cpp b/Projects/Irrlicht/Source/CNullDriver.cpp index b8ffdb1ed..ed9fc627a 100644 --- a/Projects/Irrlicht/Source/CNullDriver.cpp +++ b/Projects/Irrlicht/Source/CNullDriver.cpp @@ -841,7 +841,7 @@ ITexture* CNullDriver::addTexture(const core::dimension2d& size, return t; } -IRWBuffer* CNullDriver::createRWBuffer(video::ECOLOR_FORMAT format, u32 numElements) +IRWBuffer* CNullDriver::createRWBuffer(video::ECOLOR_FORMAT format, u32 numElements, void *initialData) { return NULL; } @@ -2481,6 +2481,54 @@ s32 CNullDriver::addHighLevelShaderMaterialFromFiles( return result; } +IGPUCompute* CNullDriver::createComputeProgramFromFile(const io::path& computeShaderFileName, + const c8* computeShaderEntryPointName, + E_COMPUTE_SHADER_TYPE csCompileTarget) +{ + io::IReadFile* csfile = 0; + + if (computeShaderFileName.size()) + { + csfile = FileSystem->createAndOpenFile(computeShaderFileName); + if (!csfile) + { + os::Printer::log("Could not open vertex shader program file", + computeShaderFileName, ELL_WARNING); + return NULL; + } + } + + c8 *cs = NULL; + + const long size = csfile->getSize(); + if (size) + { + cs = new c8[size + 1]; + csfile->read(cs, size); + cs[size] = 0; + } + + IGPUCompute *result = NULL; + + if (cs != NULL) + { + result = createComputeProgram(cs, computeShaderEntryPointName, csCompileTarget); + delete []cs; + } + + if (csfile) + csfile->drop(); + + return result; +} + +IGPUCompute* CNullDriver::createComputeProgram(const c8* computeShaderProgram, + const c8* computeShaderEntryPointName, + E_COMPUTE_SHADER_TYPE csCompileTarget) +{ + os::Printer::log("Compute shader not implemented yet in this driver, sorry."); + return NULL; +} //! Adds a new material renderer to the VideoDriver, using pixel and/or //! vertex shaders to render geometry. diff --git a/Projects/Irrlicht/Source/CNullDriver.h b/Projects/Irrlicht/Source/CNullDriver.h index fd34ca93f..3ce1b7da4 100644 --- a/Projects/Irrlicht/Source/CNullDriver.h +++ b/Projects/Irrlicht/Source/CNullDriver.h @@ -146,7 +146,7 @@ namespace video SColor color) _IRR_OVERRIDE_; //! creates a buffer stored on gpu - virtual IRWBuffer* createRWBuffer(video::ECOLOR_FORMAT format, u32 numElements) _IRR_OVERRIDE_; + virtual IRWBuffer* createRWBuffer(video::ECOLOR_FORMAT format, u32 numElements, void *initialData = NULL) _IRR_OVERRIDE_; //! sets a viewport virtual void setViewPort(const core::rect& area) _IRR_OVERRIDE_; @@ -494,6 +494,14 @@ namespace video E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, s32 userData = 0, E_GPU_SHADING_LANGUAGE shadingLang = EGSL_DEFAULT) _IRR_OVERRIDE_; + virtual IGPUCompute* createComputeProgram(const c8* computeShaderProgram, + const c8* computeShaderEntryPointName = "main", + E_COMPUTE_SHADER_TYPE csCompileTarget = ECST_CS_5_0) _IRR_OVERRIDE_; + + virtual IGPUCompute* createComputeProgramFromFile(const io::path& computeShaderFileName, + const c8* computeShaderEntryPointName = "main", + E_COMPUTE_SHADER_TYPE csCompileTarget = ECST_CS_5_0) _IRR_OVERRIDE_; + //! Returns a pointer to the mesh manipulator. virtual scene::IMeshManipulator* getMeshManipulator() _IRR_OVERRIDE_;