diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2018-03-26 15:34:01 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-03-26 15:34:01 -0400 |
| commit | 74bf38b36d9074a83a53d3baf885d8886c0b3752 (patch) | |
| tree | 31ed26ba7057c7165f33ea24b164cde10c17a0ef | |
| parent | 5000d27d993d9ac33ef80482eb44235298d5177e (diff) | |
Renderer resource mangement for render-test (#453)
* First pass at resource based renderer using RefObject.
* Correct handling of array of buffer pointers to Dx11.
* Fix bug with setting viewOut incorrectly in createInputTexture.
* More support for allowing com like interfaces.
* Added and tidied Slang::Result - adding interface specific results
* Guid added comparison support, and made base interface IComUnknown - with lowerCamel methods
| -rw-r--r-- | source/core/slang-com-ptr.h | 80 | ||||
| -rw-r--r-- | source/core/slang-result.h | 21 | ||||
| -rw-r--r-- | tools/render-test/main.cpp | 302 | ||||
| -rw-r--r-- | tools/render-test/render-d3d11.cpp | 401 | ||||
| -rw-r--r-- | tools/render-test/render-gl.cpp | 189 | ||||
| -rw-r--r-- | tools/render-test/render-vk.cpp | 157 | ||||
| -rw-r--r-- | tools/render-test/render.h | 25 |
7 files changed, 703 insertions, 472 deletions
diff --git a/source/core/slang-com-ptr.h b/source/core/slang-com-ptr.h index 0b30c220c..729b6b266 100644 --- a/source/core/slang-com-ptr.h +++ b/source/core/slang-com-ptr.h @@ -49,13 +49,57 @@ struct Guid uint8_t data4[8]; ///< 0, 1 = clock_seq_hi_and_reserved, clock_seq_low, followed by 'spatially unique node' (48 bits) }; +SLANG_FORCE_INLINE bool operator==(const Guid& aIn, const Guid& bIn) +{ + struct GuidCompare + { + enum { kNum = sizeof(Guid) / sizeof(size_t) }; + Guid guid; + size_t data[kNum]; + }; + const GuidCompare& a = reinterpret_cast<const GuidCompare&>(aIn); + const GuidCompare& b = reinterpret_cast<const GuidCompare&>(bIn); + + switch (GuidCompare::kNum) + { + case 2: return ((a.data[0] ^ b.data[0]) | (a.data[1] ^ b.data[1])) == 0; + case 4: return ((a.data[0] ^ b.data[0]) | (a.data[1] ^ b.data[1]) | (a.data[2] ^ b.data[2]) | (a.data[3] ^ b.data[3]) ) == 0; + default: return false; + } +} + +SLANG_FORCE_INLINE bool operator!=(const Guid& a, const Guid& b) +{ + return !(a == b); +} + +// Allows for defining of a GUID that works in C++ and C which defines in a format similar to microsofts INTERFACE style +// MIDL_INTERFACE("00000000-0000-0000-C000-00 00 00 00 00 46") + +#define SLANG_GUID_BYTE(x, index) ((uint8_t)(SLANG_UINT64(0x##x) >> (8 * index))) + +#define SLANG_MAKE_GUID(data0, data1, data2, shortTail, tail) \ + { (uint32_t)(0x##data0), (uint16_t)(0x##data1), (uint16_t)(0x##data2), \ + { (uint8_t)(0x##shortTail >> 8), (uint8_t)(0x##shortTail & 0xff), \ + SLANG_GUID_BYTE(tail,5), SLANG_GUID_BYTE(tail,4), SLANG_GUID_BYTE(tail,3), SLANG_GUID_BYTE(tail,2), SLANG_GUID_BYTE(tail,1), SLANG_GUID_BYTE(tail,0) \ + }} + +// Compatible with Microsoft IUnknown +static const Guid IID_IComUnknown = SLANG_MAKE_GUID(00000000, 0000, 0000, C000, 000000000046); + /// ! Must be kept in sync with IUnknown -class IForwardUnknown +class IComUnknown { public: - virtual SLANG_NO_THROW Result SLANG_MCALL QueryInterface(const Guid& iid, void* objOut) = 0; - virtual SLANG_NO_THROW uint32_t SLANG_MCALL AddRef() = 0; - virtual SLANG_NO_THROW uint32_t SLANG_MCALL Release() = 0; + virtual SLANG_NO_THROW Result SLANG_MCALL queryInterface(const Guid& iid, void* objOut) = 0; + virtual SLANG_NO_THROW uint32_t SLANG_MCALL addRef() = 0; + virtual SLANG_NO_THROW uint32_t SLANG_MCALL release() = 0; +}; + +// Enum to force initializing as an attach (without adding a reference) +enum InitAttach +{ + INIT_ATTACH }; template <class T> @@ -64,15 +108,20 @@ class ComPtr public: typedef T Type; typedef ComPtr ThisType; - typedef IForwardUnknown* Ptr; + typedef IComUnknown* Ptr; /// Constructors /// Default Ctor. Sets to nullptr SLANG_FORCE_INLINE ComPtr() :m_ptr(nullptr) {} /// Sets, and ref counts. - SLANG_FORCE_INLINE explicit ComPtr(T* ptr) :m_ptr(ptr) { if (ptr) ((Ptr)ptr)->AddRef(); } + SLANG_FORCE_INLINE explicit ComPtr(T* ptr) :m_ptr(ptr) { if (ptr) ((Ptr)ptr)->addRef(); } /// The copy ctor - SLANG_FORCE_INLINE ComPtr(const ThisType& rhs) : m_ptr(rhs.m_ptr) { if (m_ptr) ((Ptr)m_ptr)->AddRef(); } + SLANG_FORCE_INLINE ComPtr(const ThisType& rhs) : m_ptr(rhs.m_ptr) { if (m_ptr) ((Ptr)m_ptr)->addRef(); } + + /// Ctor without adding to ref count. + SLANG_FORCE_INLINE explicit ComPtr(InitAttach, T* ptr) :m_ptr(ptr) { } + /// Ctor without adding to ref count + SLANG_FORCE_INLINE ComPtr(InitAttach, const ThisType& rhs) : m_ptr(rhs.m_ptr) { } #ifdef SLANG_HAS_MOVE_SEMANTICS /// Move Ctor @@ -82,7 +131,7 @@ public: #endif /// Destructor releases the pointer, assuming it is set - SLANG_FORCE_INLINE ~ComPtr() { if (m_ptr) ((Ptr)m_ptr)->Release(); } + SLANG_FORCE_INLINE ~ComPtr() { if (m_ptr) ((Ptr)m_ptr)->release(); } // !!! Operators !!! @@ -118,6 +167,7 @@ public: protected: /// Gets the address of the dumb pointer. + // Disabled: use writeRef and readRef to get a reference based on usage. SLANG_FORCE_INLINE T** operator&(); T* m_ptr; @@ -129,23 +179,23 @@ void ComPtr<T>::setNull() { if (m_ptr) { - ((Ptr)m_ptr)->Release(); + ((Ptr)m_ptr)->release(); m_ptr = nullptr; } } //---------------------------------------------------------------------------- -template <typename T> +/* template <typename T> T** ComPtr<T>::operator&() { assert(m_ptr == nullptr); return &m_ptr; -} +} */ //---------------------------------------------------------------------------- template <typename T> const ComPtr<T>& ComPtr<T>::operator=(const ThisType& rhs) { - if (rhs.m_ptr) ((Ptr)rhs.m_ptr)->AddRef(); - if (m_ptr) ((Ptr)m_ptr)->Release(); + if (rhs.m_ptr) ((Ptr)rhs.m_ptr)->addRef(); + if (m_ptr) ((Ptr)m_ptr)->release(); m_ptr = rhs.m_ptr; return *this; } @@ -153,8 +203,8 @@ const ComPtr<T>& ComPtr<T>::operator=(const ThisType& rhs) template <typename T> T* ComPtr<T>::operator=(T* ptr) { - if (ptr) ((Ptr)ptr)->AddRef(); - if (m_ptr) ((Ptr)m_ptr)->Release(); + if (ptr) ((Ptr)ptr)->addRef(); + if (m_ptr) ((Ptr)m_ptr)->release(); m_ptr = ptr; return m_ptr; } diff --git a/source/core/slang-result.h b/source/core/slang-result.h index 767d2c737..348029af4 100644 --- a/source/core/slang-result.h +++ b/source/core/slang-result.h @@ -38,7 +38,7 @@ f is the short version of the facility name For the common used SLANG_OK and SLANG_FAIL, the name prefix is dropped. It is acceptable to expand 'f' to a longer name to differentiate a name ie for a facility 'DRIVER' it might make sense to have an error of the form SLANG_E_DRIVER_OUT_OF_MEMORY -*/ +*/ typedef int32_t SlangResult; @@ -55,8 +55,8 @@ typedef int32_t SlangResult; //! Get the result code for the facility #define SLANG_GET_RESULT_CODE(r) ((int32_t)((r) & 0xffff)) -#define SLANG_MAKE_ERROR(fac, code) (SLANG_MAKE_RESULT_ID(SLANG_FACILITY_##fac, code) | 0x80000000) -#define SLANG_MAKE_SUCCESS(fac, code) SLANG_MAKE_RESULT_ID(SLANG_FACILITY_##fac, code) +#define SLANG_MAKE_ERROR(fac, code) (SLANG_MAKE_RESULT_ID(fac, code) | 0x80000000) +#define SLANG_MAKE_SUCCESS(fac, code) SLANG_MAKE_RESULT_ID(fac, code) /*************************** Facilities ************************************/ @@ -81,21 +81,24 @@ It can be useful to have a consistent short name for a facility, as used in the /* *************************** Codes **************************************/ // Memory -#define SLANG_E_MEM_OUT_OF_MEMORY SLANG_MAKE_ERROR(MEMORY, 1) -#define SLANG_E_MEM_BUFFER_TOO_SMALL SLANG_MAKE_ERROR(MEMORY, 2) +#define SLANG_E_MEM_OUT_OF_MEMORY SLANG_MAKE_ERROR(SLANG_FACILITY_MEMORY, 1) +#define SLANG_E_MEM_BUFFER_TOO_SMALL SLANG_MAKE_ERROR(SLANG_FACILITY_MEMORY, 2) //! SLANG_OK indicates success, and is equivalent to SLANG_MAKE_RESULT(0, GENERAL, 0) #define SLANG_OK 0 //! SLANG_FAIL is the generic failure code - meaning a serious error occurred and the call couldn't complete -#define SLANG_FAIL SLANG_MAKE_ERROR(GENERAL, 1) +#define SLANG_FAIL SLANG_MAKE_ERROR(SLANG_FACILITY_GENERAL, 1) //! Used to identify a Result that has yet to be initialized. //! It defaults to failure such that if used incorrectly will fail, as similar in concept to using an uninitialized variable. -#define SLANG_E_MISC_UNINITIALIZED SLANG_MAKE_ERROR(MISC, 2) +#define SLANG_E_MISC_UNINITIALIZED SLANG_MAKE_ERROR(SLANG_FACILITY_MISC, 2) //! Returned from an async method meaning the output is invalid (thus an error), but a result for the request is pending, and will be returned on a subsequent call with the async handle. -#define SLANG_E_MISC_PENDING SLANG_MAKE_ERROR(MISC, 3) +#define SLANG_E_MISC_PENDING SLANG_MAKE_ERROR(SLANG_FACILITY_MISC, 3) //! Indicates that a handle passed in as parameter to a method is invalid. -#define SLANG_E_MISC_INVALID_HANDLE SLANG_MAKE_ERROR(MISC, 4) +#define SLANG_E_MISC_INVALID_HANDLE SLANG_MAKE_ERROR(SLANG_FACILITY_MISC, 4) + +//! Indicates that tn interface could not be found +#define SLANG_E_INTF_NO_INTERFACE SLANG_MAKE_ERROR(SLANG_FACILITY_INTERFACE, 2) /*! Set SLANG_HANDLE_RESULT_FAIL(x) to code to be executed whenever an error occurs, and is detected by one of the macros */ #ifndef SLANG_HANDLE_RESULT_FAIL diff --git a/tools/render-test/main.cpp b/tools/render-test/main.cpp index 89aa9a544..b333e57bd 100644 --- a/tools/render-test/main.cpp +++ b/tools/render-test/main.cpp @@ -47,109 +47,70 @@ static const Vertex kVertexData[kVertexCount] = { { { 1, 0, 0.5 }, {0, 1, 0} , {1, 1} }, }; +using namespace Slang; -// Global variables for state to be used for rendering... +class RenderTestApp +{ + public: -uintptr_t gConstantBufferSize, gComputeResultBufferSize; + // At initialization time, we are going to load and compile our Slang shader + // code, and then create the API objects we need for rendering. + Result initialize(Renderer* renderer, ShaderCompiler* shaderCompiler); + void runCompute(); + void renderFrame(); + void finalize(); -Buffer* gConstantBuffer; -InputLayout* gInputLayout; -Buffer* gVertexBuffer; -ShaderProgram* gShaderProgram; -BindingState* gBindingState; -ShaderInputLayout gShaderInputLayout; + BindingState* getBindingState() const { return m_bindingState; } -// Entry point name to use for vertex/fragment shader -static char const* vertexEntryPointName = "vertexMain"; -static char const* fragmentEntryPointName = "fragmentMain"; -static char const* computeEntryPointName = "computeMain"; + protected: + /// Called in initialize + Result initializeShaders(ShaderCompiler* shaderCompiler); -// "Profile" to use when compiling for HLSL targets -// TODO: does this belong here? -static char const* vertexProfileName = "vs_5_0"; -static char const* fragmentProfileName = "ps_5_0"; -static char const* computeProfileName = "cs_5_0"; + // variables for state to be used for rendering... + uintptr_t m_constantBufferSize, m_computeResultBufferSize; -SlangResult initializeShaders( - ShaderCompiler* shaderCompiler) -{ - // Read in the source code - char const* sourcePath = gOptions.sourcePath; - FILE* sourceFile = fopen(sourcePath, "rb"); - if( !sourceFile ) - { - fprintf(stderr, "error: failed to open '%s' for reading\n", sourcePath); - return SLANG_FAIL; - } - fseek(sourceFile, 0, SEEK_END); - size_t sourceSize = ftell(sourceFile); - fseek(sourceFile, 0, SEEK_SET); - char* sourceText = (char*) malloc(sourceSize + 1); - if( !sourceText ) - { - fprintf(stderr, "error: out of memory"); - return SLANG_FAIL; - } - fread(sourceText, sourceSize, 1, sourceFile); - fclose(sourceFile); - sourceText[sourceSize] = 0; + RefPtr<Renderer> m_renderer; - gShaderInputLayout.Parse(sourceText); + RefPtr<Buffer> m_constantBuffer; + RefPtr<InputLayout> m_inputLayout; + RefPtr<Buffer> m_vertexBuffer; + RefPtr<ShaderProgram> m_shaderProgram; + RefPtr<BindingState> m_bindingState; - ShaderCompileRequest::SourceInfo sourceInfo; - sourceInfo.path = sourcePath; - sourceInfo.dataBegin = sourceText; - sourceInfo.dataEnd = sourceText + sourceSize; + ShaderInputLayout m_shaderInputLayout; - ShaderCompileRequest compileRequest; - compileRequest.source = sourceInfo; - if (gOptions.shaderType == ShaderProgramType::Graphics || gOptions.shaderType == ShaderProgramType::GraphicsCompute) - { - compileRequest.vertexShader.source = sourceInfo; - compileRequest.vertexShader.name = vertexEntryPointName; - compileRequest.vertexShader.profile = vertexProfileName; - compileRequest.fragmentShader.source = sourceInfo; - compileRequest.fragmentShader.name = fragmentEntryPointName; - compileRequest.fragmentShader.profile = fragmentProfileName; - } - else - { - compileRequest.computeShader.source = sourceInfo; - compileRequest.computeShader.name = computeEntryPointName; - compileRequest.computeShader.profile = computeProfileName; - } - compileRequest.entryPointTypeArguments = gShaderInputLayout.globalTypeArguments; - gShaderProgram = shaderCompiler->compileProgram(compileRequest); - if( !gShaderProgram ) - { - return SLANG_FAIL; - } +}; - return SLANG_OK; -} -// -// At initialization time, we are going to load and compile our Slang shader -// code, and then create the D3D11 API objects we need for rendering. -// -SlangResult initializeInner( - Renderer* renderer, - ShaderCompiler* shaderCompiler) +// Entry point name to use for vertex/fragment shader +static const char vertexEntryPointName[] = "vertexMain"; +static const char fragmentEntryPointName[] = "fragmentMain"; +static const char computeEntryPointName[] = "computeMain"; + +// "Profile" to use when compiling for HLSL targets +// TODO: does this belong here? +static const char vertexProfileName[] = "vs_5_0"; +static const char fragmentProfileName[] = "ps_5_0"; +static const char computeProfileName[] = "cs_5_0"; + +SlangResult RenderTestApp::initialize(Renderer* renderer, ShaderCompiler* shaderCompiler) { SLANG_RETURN_ON_FAIL(initializeShaders(shaderCompiler)); - gBindingState = renderer->createBindingState(gShaderInputLayout); + m_renderer = renderer; + + m_bindingState = renderer->createBindingState(m_shaderInputLayout); // Do other initialization that doesn't depend on the source language. // TODO(tfoley): use each API's reflection interface to query the constant-buffer size needed - gConstantBufferSize = 16 * sizeof(float); + m_constantBufferSize = 16 * sizeof(float); BufferDesc constantBufferDesc; - constantBufferDesc.size = gConstantBufferSize; + constantBufferDesc.size = m_constantBufferSize; constantBufferDesc.flavor = BufferFlavor::Constant; - gConstantBuffer = renderer->createBuffer(constantBufferDesc); - if(!gConstantBuffer) + m_constantBuffer = renderer->createBuffer(constantBufferDesc); + if(!m_constantBuffer) return SLANG_FAIL; // Input Assembler (IA) @@ -160,8 +121,8 @@ SlangResult initializeInner( { "A", 2, Format::RG_Float32, offsetof(Vertex, uv) }, }; - gInputLayout = renderer->createInputLayout(&inputElements[0], sizeof(inputElements)/sizeof(inputElements[0])); - if(!gInputLayout) + m_inputLayout = renderer->createInputLayout(&inputElements[0], sizeof(inputElements)/sizeof(inputElements[0])); + if(!m_inputLayout) return SLANG_FAIL; BufferDesc vertexBufferDesc; @@ -169,17 +130,73 @@ SlangResult initializeInner( vertexBufferDesc.flavor = BufferFlavor::Vertex; vertexBufferDesc.initData = &kVertexData[0]; - gVertexBuffer = renderer->createBuffer(vertexBufferDesc); - if(!gVertexBuffer) + m_vertexBuffer = renderer->createBuffer(vertexBufferDesc); + if(!m_vertexBuffer) return SLANG_FAIL; return SLANG_OK; } -void renderFrameInner( - Renderer* renderer) +Result RenderTestApp::initializeShaders(ShaderCompiler* shaderCompiler) +{ + // Read in the source code + char const* sourcePath = gOptions.sourcePath; + FILE* sourceFile = fopen(sourcePath, "rb"); + if (!sourceFile) + { + fprintf(stderr, "error: failed to open '%s' for reading\n", sourcePath); + return SLANG_FAIL; + } + fseek(sourceFile, 0, SEEK_END); + size_t sourceSize = ftell(sourceFile); + fseek(sourceFile, 0, SEEK_SET); + char* sourceText = (char*)malloc(sourceSize + 1); + if (!sourceText) + { + fprintf(stderr, "error: out of memory"); + return SLANG_FAIL; + } + fread(sourceText, sourceSize, 1, sourceFile); + fclose(sourceFile); + sourceText[sourceSize] = 0; + + m_shaderInputLayout.Parse(sourceText); + + ShaderCompileRequest::SourceInfo sourceInfo; + sourceInfo.path = sourcePath; + sourceInfo.dataBegin = sourceText; + sourceInfo.dataEnd = sourceText + sourceSize; + + ShaderCompileRequest compileRequest; + compileRequest.source = sourceInfo; + if (gOptions.shaderType == ShaderProgramType::Graphics || gOptions.shaderType == ShaderProgramType::GraphicsCompute) + { + compileRequest.vertexShader.source = sourceInfo; + compileRequest.vertexShader.name = vertexEntryPointName; + compileRequest.vertexShader.profile = vertexProfileName; + compileRequest.fragmentShader.source = sourceInfo; + compileRequest.fragmentShader.name = fragmentEntryPointName; + compileRequest.fragmentShader.profile = fragmentProfileName; + } + else + { + compileRequest.computeShader.source = sourceInfo; + compileRequest.computeShader.name = computeEntryPointName; + compileRequest.computeShader.profile = computeProfileName; + } + compileRequest.entryPointTypeArguments = m_shaderInputLayout.globalTypeArguments; + m_shaderProgram = shaderCompiler->compileProgram(compileRequest); + if (!m_shaderProgram) + { + return SLANG_FAIL; + } + + return SLANG_OK; +} + +void RenderTestApp::renderFrame() { - auto mappedData = renderer->map(gConstantBuffer, MapFlavor::WriteDiscard); + auto mappedData = m_renderer->map(m_constantBuffer, MapFlavor::WriteDiscard); if(mappedData) { static const float kIdentity[] = @@ -189,40 +206,39 @@ void renderFrameInner( 0, 0, 0, 1 }; memcpy(mappedData, kIdentity, sizeof(kIdentity)); - renderer->unmap(gConstantBuffer); + m_renderer->unmap(m_constantBuffer); } // Input Assembler (IA) - renderer->setInputLayout(gInputLayout); - renderer->setPrimitiveTopology(PrimitiveTopology::TriangleList); + m_renderer->setInputLayout(m_inputLayout); + m_renderer->setPrimitiveTopology(PrimitiveTopology::TriangleList); - renderer->setVertexBuffer(0, gVertexBuffer, sizeof(Vertex)); + m_renderer->setVertexBuffer(0, m_vertexBuffer, sizeof(Vertex)); // Vertex Shader (VS) // Pixel Shader (PS) - renderer->setShaderProgram(gShaderProgram); - renderer->setConstantBuffer(0, gConstantBuffer); - renderer->setBindingState(gBindingState); + m_renderer->setShaderProgram(m_shaderProgram); + m_renderer->setConstantBuffer(0, m_constantBuffer); + m_renderer->setBindingState(m_bindingState); // - renderer->draw(3); + m_renderer->draw(3); } -void runCompute(Renderer * renderer) +void RenderTestApp::runCompute() { - renderer->setShaderProgram(gShaderProgram); - renderer->setBindingState(gBindingState); - renderer->dispatchCompute(1, 1, 1); + m_renderer->setShaderProgram(m_shaderProgram); + m_renderer->setBindingState(m_bindingState); + m_renderer->dispatchCompute(1, 1, 1); } -void finalize() +void RenderTestApp::finalize() { } - // // We use a bare-minimum window procedure to get things up and running. // @@ -243,7 +259,6 @@ static LRESULT CALLBACK windowProc( return DefWindowProcW(windowHandle, message, wParam, lParam); } - SlangResult innerMain(int argc, char** argv) { // Parse command-line options @@ -283,7 +298,6 @@ SlangResult innerMain(int argc, char** argv) DWORD windowStyle = WS_POPUP; DWORD windowExtendedStyle = 0; - RECT windowRect = { 0, 0, gWindowWidth, gWindowHeight }; AdjustWindowRectEx(&windowRect, windowStyle, /*hasMenu=*/false, windowExtendedStyle); @@ -308,8 +322,8 @@ SlangResult innerMain(int argc, char** argv) return SLANG_FAIL; } + Slang::RefPtr<Renderer> renderer; - Renderer* renderer = nullptr; SlangSourceLanguage nativeLanguage = SLANG_SOURCE_LANGUAGE_UNKNOWN; SlangCompileTarget slangTarget = SLANG_TARGET_NONE; switch (gOptions.rendererID) @@ -356,53 +370,57 @@ SlangResult innerMain(int argc, char** argv) break; } - SLANG_RETURN_ON_FAIL(initializeInner(renderer, shaderCompiler)); + { + RenderTestApp app; - // Once initialization is all complete, we show the window... - ShowWindow(windowHandle, showCommand); + SLANG_RETURN_ON_FAIL(app.initialize(renderer, shaderCompiler)); - // ... and enter the event loop: - for (;;) - { - MSG message; + // Once initialization is all complete, we show the window... + ShowWindow(windowHandle, showCommand); - int result = PeekMessageW(&message, NULL, 0, 0, PM_REMOVE); - if (result != 0) + // ... and enter the event loop: + for (;;) { - if (message.message == WM_QUIT) - { - return (int)message.wParam; - } + MSG message; - TranslateMessage(&message); - DispatchMessageW(&message); - } - else - { - // Whenever we don't have Windows events to process, we render a frame. - if (gOptions.shaderType == ShaderProgramType::Compute) + int result = PeekMessageW(&message, NULL, 0, 0, PM_REMOVE); + if (result != 0) { - runCompute(renderer); - } - else - { - static const float kClearColor[] = { 0.25, 0.25, 0.25, 1.0 }; - renderer->setClearColor(kClearColor); - renderer->clearFrame(); + if (message.message == WM_QUIT) + { + return (int)message.wParam; + } - renderFrameInner(renderer); + TranslateMessage(&message); + DispatchMessageW(&message); } - // If we are in a mode where output is requested, we need to snapshot the back buffer here - if (gOptions.outputPath) + else { - if (gOptions.shaderType == ShaderProgramType::Compute || gOptions.shaderType == ShaderProgramType::GraphicsCompute) - renderer->serializeOutput(gBindingState, gOptions.outputPath); + // Whenever we don't have Windows events to process, we render a frame. + if (gOptions.shaderType == ShaderProgramType::Compute) + { + app.runCompute(); + } else - SLANG_RETURN_ON_FAIL(renderer->captureScreenShot(gOptions.outputPath)); - return SLANG_OK; + { + static const float kClearColor[] = { 0.25, 0.25, 0.25, 1.0 }; + renderer->setClearColor(kClearColor); + renderer->clearFrame(); + + app.renderFrame(); + } + // If we are in a mode where output is requested, we need to snapshot the back buffer here + if (gOptions.outputPath) + { + if (gOptions.shaderType == ShaderProgramType::Compute || gOptions.shaderType == ShaderProgramType::GraphicsCompute) + renderer->serializeOutput(app.getBindingState(), gOptions.outputPath); + else + SLANG_RETURN_ON_FAIL(renderer->captureScreenShot(gOptions.outputPath)); + return SLANG_OK; + } + + renderer->presentFrame(); } - - renderer->presentFrame(); } } diff --git a/tools/render-test/render-d3d11.cpp b/tools/render-test/render-d3d11.cpp index b4195c63d..35c04a79f 100644 --- a/tools/render-test/render-d3d11.cpp +++ b/tools/render-test/render-d3d11.cpp @@ -8,6 +8,8 @@ #include <slang.h> +#include "../../source/core/slang-com-ptr.h" + #ifdef _MSC_VER #pragma warning(disable: 4996) #endif @@ -70,35 +72,45 @@ public: protected: - struct BindingImpl + struct Binding { ShaderInputType type; InputBufferType bufferType; // Only valid if `type` is `Buffer` - ID3D11ShaderResourceView* srv = nullptr; - ID3D11UnorderedAccessView* uav = nullptr; - ID3D11Buffer* buffer = nullptr; - ID3D11SamplerState* samplerState = nullptr; + ComPtr<ID3D11ShaderResourceView> srv; + ComPtr<ID3D11UnorderedAccessView> uav; + ComPtr<ID3D11Buffer> buffer; + ComPtr<ID3D11SamplerState> samplerState; int binding = 0; bool isOutput = false; int bufferLength = 0; }; - struct BindingStateImpl + + class BindingStateImpl: public BindingState { - List<BindingImpl> bindings; - int numRenderTargets = 0; + public: + List<Binding> m_bindings; + int m_numRenderTargets = 0; }; - struct ShaderProgramImpl + class ShaderProgramImpl: public ShaderProgram { - ID3D11VertexShader* vertexShader = nullptr; - ID3D11PixelShader* pixelShader = nullptr; - ID3D11ComputeShader* computeShader = nullptr; + public: + ComPtr<ID3D11VertexShader> m_vertexShader; + ComPtr<ID3D11PixelShader> m_pixelShader; + ComPtr<ID3D11ComputeShader> m_computeShader; }; - struct BufferImpl + class BufferImpl: public Buffer { - ID3D11Buffer* buffer = nullptr; + public: + ComPtr<ID3D11Buffer> m_buffer; }; + class InputLayoutImpl: public InputLayout + { + public: + ComPtr<ID3D11InputLayout> m_layout; + }; + /// Calculate size taking into account alignment. Alignment must be a power of 2 static UInt calcAligned(UInt size, UInt alignment) { return (size + alignment - 1) & ~(alignment - 1); } @@ -107,29 +119,32 @@ public: /// The Slang compiler currently generates HLSL source, so we'll need a utility /// routine (defined later) to translate that into D3D11 shader bytecode. /// Definition of the HLSL-to-bytecode compilation logic. - static ID3DBlob* compileHLSLShader(char const* sourcePath, char const* source, char const* entryPointName, char const* dxProfileName); + static Result compileHLSLShader(char const* sourcePath, char const* source, char const* entryPointName, char const* dxProfileName, ComPtr<ID3DBlob>& shaderBlobOut); /// Capture a texture to a file static HRESULT captureTextureToFile(ID3D11Device* device, ID3D11DeviceContext* context, ID3D11Texture2D* texture, char const* outputPath); void* map(ID3D11Buffer* buffer, MapFlavor flavor); void unmap(ID3D11Buffer* buffer); - void createInputBuffer(InputBufferDesc& bufferDesc, List<unsigned int>& bufferData, ID3D11Buffer*& bufferOut, - ID3D11UnorderedAccessView*& viewOut, ID3D11ShaderResourceView*& srvOut); + Result createInputBuffer(InputBufferDesc& bufferDesc, const List<unsigned int>& bufferData, + ComPtr<ID3D11Buffer>& bufferOut, ComPtr<ID3D11UnorderedAccessView>& viewOut, ComPtr<ID3D11ShaderResourceView>& srvOut); - void createInputTexture(const InputTextureDesc& inputDesc, ID3D11ShaderResourceView*& viewOut); + Result createInputTexture(const InputTextureDesc& inputDesc, ComPtr<ID3D11ShaderResourceView>& viewOut); - void createInputSampler(const InputSamplerDesc& inputDesc, ID3D11SamplerState*& stateOut); + Result createInputSampler(const InputSamplerDesc& inputDesc, ComPtr<ID3D11SamplerState>& stateOut); void applyBindingState(bool isCompute); - IDXGISwapChain* m_swapChain = nullptr; - ID3D11Device* m_device = nullptr; - ID3D11DeviceContext* m_immediateContext = nullptr; - ID3D11Texture2D* m_backBufferTexture = nullptr; - List<ID3D11RenderTargetView*> m_renderTargetViews; - List<ID3D11Texture2D*> m_renderTargetTextures; - BindingStateImpl* m_currentBindings = nullptr; + ComPtr<IDXGISwapChain> m_swapChain; + ComPtr<ID3D11Device> m_device; + ComPtr<ID3D11DeviceContext> m_immediateContext; + ComPtr<ID3D11Texture2D> m_backBufferTexture; + + List<ComPtr<ID3D11RenderTargetView> > m_renderTargetViews; + List<ComPtr<ID3D11Texture2D> > m_renderTargetTextures; + + RefPtr<BindingStateImpl> m_currentBindings; + float m_clearColor[4] = { 0, 0, 0, 0 }; }; @@ -151,7 +166,7 @@ Renderer* createD3D11Renderer() } } -/* static */ID3DBlob* D3D11Renderer::compileHLSLShader(char const* sourcePath, char const* source, char const* entryPointName, char const* dxProfileName) +/* static */Result D3D11Renderer::compileHLSLShader(char const* sourcePath, char const* source, char const* entryPointName, char const* dxProfileName, ComPtr<ID3DBlob>& shaderBlobOut) { // Rather than statically link against the `d3dcompile` library, we // dynamically load it. @@ -168,14 +183,14 @@ Renderer* createD3D11Renderer() if (!compilerModule) { fprintf(stderr, "error: failed load 'd3dcompiler_47.dll'\n"); - return nullptr; - } + return SLANG_FAIL; + } compileFunc = (pD3DCompile)GetProcAddress(compilerModule, "D3DCompile"); if (!compileFunc) { fprintf(stderr, "error: failed load symbol 'D3DCompile'\n"); - return nullptr; + return SLANG_FAIL; } } @@ -195,10 +210,11 @@ Renderer* createD3D11Renderer() // The `D3DCompile` entry point takes a bunch of parameters, but we // don't really need most of them for Slang-generated code. - ID3DBlob* shaderBlob = nullptr; - ID3DBlob* errorBlob = nullptr; + ComPtr<ID3DBlob> shaderBlob; + ComPtr<ID3DBlob> errorBlob; + HRESULT hr = compileFunc(source, strlen(source), sourcePath, &defines[0], nullptr, entryPointName, dxProfileName, flags, 0, - &shaderBlob, &errorBlob); + shaderBlob.writeRef(), errorBlob.writeRef()); // If the HLSL-to-bytecode compilation produced any diagnostic messages // then we will print them out (whether or not the compilation failed). @@ -207,16 +223,12 @@ Renderer* createD3D11Renderer() ::fputs((const char*)errorBlob->GetBufferPointer(), stderr); ::fflush(stderr); ::OutputDebugStringA((const char*)errorBlob->GetBufferPointer()); - - errorBlob->Release(); - } - - if (FAILED(hr)) - { - return nullptr; + return SLANG_FAIL; } - return shaderBlob; + SLANG_RETURN_ON_FAIL(hr); + shaderBlobOut.swap(shaderBlob); + return SLANG_OK; } /* static */HRESULT D3D11Renderer::captureTextureToFile(ID3D11Device* device, ID3D11DeviceContext* context, @@ -236,12 +248,11 @@ Renderer* createD3D11Renderer() } HRESULT hr = S_OK; - ID3D11Texture2D* stagingTexture = nullptr; - + ComPtr<ID3D11Texture2D> stagingTexture; + if (textureDesc.Usage == D3D11_USAGE_STAGING && (textureDesc.CPUAccessFlags & D3D11_CPU_ACCESS_READ)) { stagingTexture = texture; - stagingTexture->AddRef(); } else { @@ -251,7 +262,7 @@ Renderer* createD3D11Renderer() textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; textureDesc.Usage = D3D11_USAGE_STAGING; - hr = device->CreateTexture2D(&textureDesc, 0, &stagingTexture); + hr = device->CreateTexture2D(&textureDesc, 0, stagingTexture.writeRef()); if (FAILED(hr)) { fprintf(stderr, "ERROR: failed to create staging texture\n"); @@ -276,7 +287,6 @@ Renderer* createD3D11Renderer() // Make sure to unmap context->Unmap(stagingTexture, 0); - stagingTexture->Release(); if (!stbResult) { @@ -356,19 +366,19 @@ SlangResult D3D11Renderer::initialize(void* inWindowHandle) for (int ii = 0; ii < 2; ++ii) { const HRESULT hr = D3D11CreateDeviceAndSwapChain_( - NULL, // adapter (use default) + nullptr, // adapter (use default) D3D_DRIVER_TYPE_REFERENCE, //D3D_DRIVER_TYPE_HARDWARE, - NULL, // software + nullptr, // software deviceFlags, &featureLevels[ii], totalNumFeatureLevels - ii, D3D11_SDK_VERSION, &swapChainDesc, - &m_swapChain, - &m_device, + m_swapChain.writeRef(), + m_device.writeRef(), &featureLevel, - &m_immediateContext); + m_immediateContext.writeRef()); // Failures with `E_INVALIDARG` might be due to feature level 11_1 // not being supported. @@ -390,27 +400,27 @@ SlangResult D3D11Renderer::initialize(void* inWindowHandle) 0x6f15aaf2, 0xd208, 0x4e89, 0x9a, 0xb4, 0x48, 0x95, 0x35, 0xd3, 0x4f, 0x9c }; - SLANG_RETURN_ON_FAIL(m_swapChain->GetBuffer(0, kIID_ID3D11Texture2D, (void**)&m_backBufferTexture)); + SLANG_RETURN_ON_FAIL(m_swapChain->GetBuffer(0, kIID_ID3D11Texture2D, (void**)m_backBufferTexture.writeRef())); for (int i = 0; i < 8; i++) { - ID3D11Texture2D* texture; + ComPtr<ID3D11Texture2D> texture; D3D11_TEXTURE2D_DESC textureDesc; m_backBufferTexture->GetDesc(&textureDesc); - SLANG_RETURN_ON_FAIL(m_device->CreateTexture2D(&textureDesc, nullptr, &texture)); + SLANG_RETURN_ON_FAIL(m_device->CreateTexture2D(&textureDesc, nullptr, texture.writeRef())); - ID3D11RenderTargetView * rtv; + ComPtr<ID3D11RenderTargetView> rtv; D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; rtvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; rtvDesc.Texture2D.MipSlice = 0; rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - SLANG_RETURN_ON_FAIL(m_device->CreateRenderTargetView(texture, &rtvDesc, &rtv)); + SLANG_RETURN_ON_FAIL(m_device->CreateRenderTargetView(texture, &rtvDesc, rtv.writeRef())); m_renderTargetViews.Add(rtv); m_renderTargetTextures.Add(texture); } - m_immediateContext->OMSetRenderTargets((UINT)m_renderTargetViews.Count(), m_renderTargetViews.Buffer(), nullptr); + m_immediateContext->OMSetRenderTargets((UINT)m_renderTargetViews.Count(), m_renderTargetViews.Buffer()->readRef(), nullptr); // Similarly, we are going to set up a viewport once, and then never // switch, since this is a simple test app. @@ -434,9 +444,9 @@ void D3D11Renderer::setClearColor(const float color[4]) void D3D11Renderer::clearFrame() { for (auto i = 0u; i < m_renderTargetViews.Count(); i++) - m_immediateContext->ClearRenderTargetView( - m_renderTargetViews[i], - m_clearColor); + { + m_immediateContext->ClearRenderTargetView(m_renderTargetViews[i], m_clearColor); + } } void D3D11Renderer::presentFrame() @@ -486,13 +496,12 @@ Buffer* D3D11Renderer::createBuffer(const BufferDesc& desc) D3D11_SUBRESOURCE_DATA subResourceData = { 0 }; subResourceData.pSysMem = desc.initData; - ID3D11Buffer* buffer = nullptr; - HRESULT hr = m_device->CreateBuffer(&bufferDesc, desc.initData ? &subResourceData : nullptr, &buffer); - if (FAILED(hr)) return nullptr; - + ComPtr<ID3D11Buffer> buffer; + SLANG_RETURN_NULL_ON_FAIL(m_device->CreateBuffer(&bufferDesc, desc.initData ? &subResourceData : nullptr, buffer.writeRef())); + BufferImpl* rs = new BufferImpl; - rs->buffer = buffer; - return (Buffer*)rs; + rs->m_buffer = buffer; + return rs; } InputLayout* D3D11Renderer::createInputLayout(const InputElementDesc* inputElementsIn, UInt inputElementCount) @@ -541,20 +550,17 @@ InputLayout* D3D11Renderer::createInputLayout(const InputElementDesc* inputEleme hlslCursor += sprintf(hlslCursor, "\n) : SV_Position { return 0; }"); - auto vertexShaderBlob = compileHLSLShader("inputLayout", hlslBuffer, "main", "vs_5_0"); - if (!vertexShaderBlob) - return nullptr; + ComPtr<ID3DBlob> vertexShaderBlob; + SLANG_RETURN_NULL_ON_FAIL(compileHLSLShader("inputLayout", hlslBuffer, "main", "vs_5_0", vertexShaderBlob)); - ID3D11InputLayout* inputLayout = nullptr; - HRESULT hr = m_device->CreateInputLayout(&inputElements[0], (UINT)inputElementCount, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), - &inputLayout); + ComPtr<ID3D11InputLayout> inputLayout; + SLANG_RETURN_NULL_ON_FAIL(m_device->CreateInputLayout(&inputElements[0], (UINT)inputElementCount, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), + inputLayout.writeRef())); - vertexShaderBlob->Release(); + InputLayoutImpl* impl = new InputLayoutImpl; + impl->m_layout.swap(inputLayout); - if (FAILED(hr)) - return nullptr; - - return (InputLayout*)inputLayout; + return impl; } void* D3D11Renderer::map(ID3D11Buffer* buffer, MapFlavor flavorIn) @@ -579,16 +585,14 @@ void* D3D11Renderer::map(ID3D11Buffer* buffer, MapFlavor flavorIn) // of the example, but we don't actually load different data // per-frame (we always use an identity projection). D3D11_MAPPED_SUBRESOURCE mappedSub; - HRESULT hr = m_immediateContext->Map(buffer, 0, mapType, 0, &mappedSub); - if (FAILED(hr)) - return nullptr; - + SLANG_RETURN_NULL_ON_FAIL(m_immediateContext->Map(buffer, 0, mapType, 0, &mappedSub)); + return mappedSub.pData; } void* D3D11Renderer::map(Buffer* buffer, MapFlavor flavor) { - return map(((BufferImpl*)buffer)->buffer, flavor); + return map(((BufferImpl*)buffer)->m_buffer, flavor); } void D3D11Renderer::unmap(ID3D11Buffer* buffer) @@ -598,14 +602,13 @@ void D3D11Renderer::unmap(ID3D11Buffer* buffer) void D3D11Renderer::unmap(Buffer* bufferIn) { - unmap(((BufferImpl*)bufferIn)->buffer); + unmap(((BufferImpl*)bufferIn)->m_buffer); } void D3D11Renderer::setInputLayout(InputLayout* inputLayoutIn) { - auto inputLayout = (ID3D11InputLayout*)inputLayoutIn; - - m_immediateContext->IASetInputLayout(inputLayout); + auto inputLayout = static_cast<InputLayoutImpl*>(inputLayoutIn); + m_immediateContext->IASetInputLayout(inputLayout->m_layout); } void D3D11Renderer::setPrimitiveTopology(PrimitiveTopology topology) @@ -627,36 +630,50 @@ void D3D11Renderer::setPrimitiveTopology(PrimitiveTopology topology) void D3D11Renderer::setVertexBuffers(UInt startSlot, UInt slotCount, Buffer*const* buffersIn, const UInt* stridesIn, const UInt* offsetsIn) { static const int kMaxVertexBuffers = 16; + assert(slotCount <= kMaxVertexBuffers); UINT vertexStrides[kMaxVertexBuffers]; UINT vertexOffsets[kMaxVertexBuffers]; + ID3D11Buffer* dxBuffers[kMaxVertexBuffers]; + + auto buffers = (BufferImpl*const*)buffersIn; for (UInt ii = 0; ii < slotCount; ++ii) { vertexStrides[ii] = (UINT)stridesIn[ii]; vertexOffsets[ii] = (UINT)offsetsIn[ii]; - } - - auto buffers = (BufferImpl* const*)buffersIn; + dxBuffers[ii] = buffers[ii]->m_buffer; + } - m_immediateContext->IASetVertexBuffers((UINT)startSlot, (UINT)slotCount, &(buffers[0])->buffer, &vertexStrides[0], &vertexOffsets[0]); + m_immediateContext->IASetVertexBuffers((UINT)startSlot, (UINT)slotCount, dxBuffers, &vertexStrides[0], &vertexOffsets[0]); } void D3D11Renderer::setShaderProgram(ShaderProgram* programIn) { auto program = (ShaderProgramImpl*)programIn; - m_immediateContext->CSSetShader(program->computeShader, nullptr, 0); - m_immediateContext->VSSetShader(program->vertexShader, nullptr, 0); - m_immediateContext->PSSetShader(program->pixelShader, nullptr, 0); + m_immediateContext->CSSetShader(program->m_computeShader, nullptr, 0); + m_immediateContext->VSSetShader(program->m_vertexShader, nullptr, 0); + m_immediateContext->PSSetShader(program->m_pixelShader, nullptr, 0); } void D3D11Renderer::setConstantBuffers(UInt startSlot, UInt slotCount, Buffer*const* buffersIn, const UInt* offsetsIn) { + static const int kMaxConstantBuffers = 16; + assert(slotCount <= kMaxConstantBuffers); + // TODO: actually use those offsets auto buffers = (BufferImpl*const*)buffersIn; - m_immediateContext->VSSetConstantBuffers((UINT)startSlot, (UINT)slotCount, &buffers[0]->buffer); - m_immediateContext->VSSetConstantBuffers((UINT)startSlot, (UINT)slotCount, &buffers[0]->buffer); + + // Copy out the actual dx buffers + ID3D11Buffer* dxBuffers[kMaxConstantBuffers]; + for (int i = 0; i < slotCount; i++) + { + dxBuffers[i] = buffers[i]->m_buffer; + } + + m_immediateContext->VSSetConstantBuffers((UINT)startSlot, (UINT)slotCount, dxBuffers); + m_immediateContext->VSSetConstantBuffers((UINT)startSlot, (UINT)slotCount, dxBuffers); } void D3D11Renderer::draw(UInt vertexCount, UInt startVertex) @@ -669,46 +686,32 @@ ShaderProgram* D3D11Renderer::compileProgram(const ShaderCompileRequest& request { if (request.computeShader.name) { - auto computeShaderBlob = compileHLSLShader(request.computeShader.source.path, request.computeShader.source.dataBegin, request.computeShader.name, request.computeShader.profile); - if (!computeShaderBlob) - return nullptr; - - ID3D11ComputeShader* computeShader; + ComPtr<ID3DBlob> computeShaderBlob; + SLANG_RETURN_NULL_ON_FAIL(compileHLSLShader(request.computeShader.source.path, request.computeShader.source.dataBegin, request.computeShader.name, request.computeShader.profile, computeShaderBlob)); - HRESULT hr = m_device->CreateComputeShader(computeShaderBlob->GetBufferPointer(), computeShaderBlob->GetBufferSize(), nullptr, &computeShader); - - computeShaderBlob->Release(); - - if (FAILED(hr)) return nullptr; + ComPtr<ID3D11ComputeShader> computeShader; + SLANG_RETURN_NULL_ON_FAIL(m_device->CreateComputeShader(computeShaderBlob->GetBufferPointer(), computeShaderBlob->GetBufferSize(), nullptr, computeShader.writeRef())); ShaderProgramImpl* shaderProgram = new ShaderProgramImpl(); - shaderProgram->computeShader = computeShader; - return (ShaderProgram*)shaderProgram; + shaderProgram->m_computeShader.swap(computeShader); + return shaderProgram; } else { - auto vertexShaderBlob = compileHLSLShader(request.vertexShader.source.path, request.vertexShader.source.dataBegin, request.vertexShader.name, request.vertexShader.profile); - if (!vertexShaderBlob) return nullptr; - - auto fragmentShaderBlob = compileHLSLShader(request.fragmentShader.source.path, request.fragmentShader.source.dataBegin, request.fragmentShader.name, request.fragmentShader.profile); - if (!fragmentShaderBlob) return nullptr; + ComPtr<ID3DBlob> vertexShaderBlob, fragmentShaderBlob; + SLANG_RETURN_NULL_ON_FAIL(compileHLSLShader(request.vertexShader.source.path, request.vertexShader.source.dataBegin, request.vertexShader.name, request.vertexShader.profile, vertexShaderBlob)); + SLANG_RETURN_NULL_ON_FAIL(compileHLSLShader(request.fragmentShader.source.path, request.fragmentShader.source.dataBegin, request.fragmentShader.name, request.fragmentShader.profile, fragmentShaderBlob)); + + ComPtr<ID3D11VertexShader> vertexShader; + ComPtr<ID3D11PixelShader> pixelShader; - ID3D11VertexShader* vertexShader; - ID3D11PixelShader* pixelShader; - - HRESULT vsResult = m_device->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), nullptr, &vertexShader); - HRESULT psResult = m_device->CreatePixelShader(fragmentShaderBlob->GetBufferPointer(), fragmentShaderBlob->GetBufferSize(), nullptr, &pixelShader); - - vertexShaderBlob->Release(); - fragmentShaderBlob->Release(); - - if (FAILED(vsResult)) return nullptr; - if (FAILED(psResult)) return nullptr; + SLANG_RETURN_NULL_ON_FAIL(m_device->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), nullptr, vertexShader.writeRef())); + SLANG_RETURN_NULL_ON_FAIL(m_device->CreatePixelShader(fragmentShaderBlob->GetBufferPointer(), fragmentShaderBlob->GetBufferSize(), nullptr, pixelShader.writeRef())); ShaderProgramImpl* shaderProgram = new ShaderProgramImpl(); - shaderProgram->vertexShader = vertexShader; - shaderProgram->pixelShader = pixelShader; - return (ShaderProgram*)shaderProgram; + shaderProgram->m_vertexShader.swap(vertexShader); + shaderProgram->m_pixelShader.swap(pixelShader); + return shaderProgram; } } @@ -718,8 +721,8 @@ void D3D11Renderer::dispatchCompute(int x, int y, int z) m_immediateContext->Dispatch(x, y, z); } -void D3D11Renderer::createInputBuffer(InputBufferDesc& bufferDesc, List<unsigned int>& bufferData, ID3D11Buffer*& bufferOut, - ID3D11UnorderedAccessView*& viewOut, ID3D11ShaderResourceView*& srvOut) +Result D3D11Renderer::createInputBuffer(InputBufferDesc& bufferDesc, const List<unsigned int>& bufferData, + ComPtr<ID3D11Buffer>& bufferOut, ComPtr<ID3D11UnorderedAccessView>& viewOut, ComPtr<ID3D11ShaderResourceView>& srvOut) { D3D11_BUFFER_DESC desc = { 0 }; List<unsigned int> newBuffer; @@ -748,7 +751,7 @@ void D3D11Renderer::createInputBuffer(InputBufferDesc& bufferDesc, List<unsigned } D3D11_SUBRESOURCE_DATA data = { 0 }; data.pSysMem = newBuffer.Buffer(); - m_device->CreateBuffer(&desc, &data, &bufferOut); + SLANG_RETURN_ON_FAIL(m_device->CreateBuffer(&desc, &data, bufferOut.writeRef())); int elemSize = bufferDesc.stride <= 0 ? 1 : bufferDesc.stride; if (bufferDesc.type == InputBufferType::StorageBuffer) { @@ -769,7 +772,7 @@ void D3D11Renderer::createInputBuffer(InputBufferDesc& bufferDesc, List<unsigned viewDesc.Format = DXGI_FORMAT_R32_TYPELESS; } - m_device->CreateUnorderedAccessView(bufferOut, &viewDesc, &viewOut); + SLANG_RETURN_ON_FAIL(m_device->CreateUnorderedAccessView(bufferOut, &viewDesc, viewOut.writeRef())); } if (bufferDesc.type != InputBufferType::ConstantBuffer) { @@ -781,12 +784,22 @@ void D3D11Renderer::createInputBuffer(InputBufferDesc& bufferDesc, List<unsigned srvDesc.Buffer.ElementOffset = 0; srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; srvDesc.Format = DXGI_FORMAT_UNKNOWN; - m_device->CreateShaderResourceView(bufferOut, &srvDesc, &srvOut); + + if (bufferDesc.stride == 0) + { + srvDesc.Format = DXGI_FORMAT_R32_FLOAT; + } + + SLANG_RETURN_ON_FAIL(m_device->CreateShaderResourceView(bufferOut, &srvDesc, srvOut.writeRef())); } + + return SLANG_OK; } -void D3D11Renderer::createInputTexture(const InputTextureDesc& inputDesc, ID3D11ShaderResourceView*& viewOut) +Result D3D11Renderer::createInputTexture(const InputTextureDesc& inputDesc, ComPtr<ID3D11ShaderResourceView>& viewOut) { + ComPtr<ID3D11ShaderResourceView> view; + TextureData texData; generateTextureData(texData, inputDesc); List<D3D11_SUBRESOURCE_DATA> subRes; @@ -816,10 +829,10 @@ void D3D11Renderer::createInputTexture(const InputTextureDesc& inputDesc, ID3D11 desc.Width = texData.textureSize; desc.Usage = D3D11_USAGE_DEFAULT; - ID3D11Texture1D * texture; - m_device->CreateTexture1D(&desc, subRes.Buffer(), &texture); - D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc; + ComPtr<ID3D11Texture1D> texture; + SLANG_RETURN_ON_FAIL(m_device->CreateTexture1D(&desc, subRes.Buffer(), texture.writeRef())); + D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc; viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D; if (inputDesc.arrayLength != 0) viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY; @@ -830,7 +843,7 @@ void D3D11Renderer::createInputTexture(const InputTextureDesc& inputDesc, ID3D11 viewDesc.Texture1DArray.MipLevels = texData.mipLevels; viewDesc.Texture1DArray.MostDetailedMip = 0; viewDesc.Format = desc.Format; - m_device->CreateShaderResourceView(texture, &viewDesc, &viewOut); + m_device->CreateShaderResourceView(texture, &viewDesc, view.writeRef()); } else if (inputDesc.dimension == 2) { @@ -871,9 +884,10 @@ void D3D11Renderer::createInputTexture(const InputTextureDesc& inputDesc, ID3D11 desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; viewDesc.Format = desc.Format; - ID3D11Texture2D * texture; - m_device->CreateTexture2D(&desc, subRes.Buffer(), &texture); - m_device->CreateShaderResourceView(texture, &viewDesc, &viewOut); + + ComPtr<ID3D11Texture2D> texture; + SLANG_RETURN_ON_FAIL(m_device->CreateTexture2D(&desc, subRes.Buffer(), texture.writeRef())); + SLANG_RETURN_ON_FAIL(m_device->CreateShaderResourceView(texture, &viewDesc, view.writeRef())); } else if (inputDesc.dimension == 3) { @@ -889,16 +903,20 @@ void D3D11Renderer::createInputTexture(const InputTextureDesc& inputDesc, ID3D11 desc.Height = texData.textureSize; desc.Depth = texData.textureSize; desc.Usage = D3D11_USAGE_DEFAULT; - ID3D11Texture3D * texture; - m_device->CreateTexture3D(&desc, subRes.Buffer(), &texture); + + ComPtr<ID3D11Texture3D> texture; + m_device->CreateTexture3D(&desc, subRes.Buffer(), texture.writeRef()); viewDesc.Texture3D.MipLevels = 1; viewDesc.Texture3D.MostDetailedMip = 0; viewDesc.Format = desc.Format; - m_device->CreateShaderResourceView(texture, &viewDesc, &viewOut); + m_device->CreateShaderResourceView(texture, &viewDesc, view.writeRef()); } + + viewOut.swap(view); + return SLANG_OK; } -void D3D11Renderer::createInputSampler(const InputSamplerDesc& inputDesc, ID3D11SamplerState*& stateOut) +Result D3D11Renderer::createInputSampler(const InputSamplerDesc& inputDesc, ComPtr<ID3D11SamplerState>& stateOut) { D3D11_SAMPLER_DESC desc; memset(&desc, 0, sizeof(desc)); @@ -916,16 +934,16 @@ void D3D11Renderer::createInputSampler(const InputSamplerDesc& inputDesc, ID3D11 desc.MinLOD = 0.0f; desc.MaxLOD = 100.0f; } - m_device->CreateSamplerState(&desc, &stateOut); + return m_device->CreateSamplerState(&desc, stateOut.writeRef()); } -BindingState * D3D11Renderer::createBindingState(const ShaderInputLayout& layout) +BindingState* D3D11Renderer::createBindingState(const ShaderInputLayout& layout) { - BindingStateImpl * rs = new BindingStateImpl; - rs->numRenderTargets = layout.numRenderTargets; + List<Binding> bindings; + for (auto & entry : layout.entries) { - BindingImpl rsEntry; + Binding rsEntry; rsEntry.type = entry.type; rsEntry.binding = entry.hlslBinding; rsEntry.isOutput = entry.isOutput; @@ -933,66 +951,73 @@ BindingState * D3D11Renderer::createBindingState(const ShaderInputLayout& layout { case ShaderInputType::Buffer: { - createInputBuffer(entry.bufferDesc, entry.bufferData, rsEntry.buffer, rsEntry.uav, rsEntry.srv); + SLANG_RETURN_NULL_ON_FAIL(createInputBuffer(entry.bufferDesc, entry.bufferData, rsEntry.buffer, rsEntry.uav, rsEntry.srv)); + rsEntry.bufferLength = (int)(entry.bufferData.Count() * sizeof(unsigned int)); rsEntry.bufferType = entry.bufferDesc.type; - } - break; + break; + } case ShaderInputType::Texture: { - createInputTexture(entry.textureDesc, rsEntry.srv); - } - break; + SLANG_RETURN_NULL_ON_FAIL(createInputTexture(entry.textureDesc, rsEntry.srv)); + break; + } case ShaderInputType::Sampler: { - createInputSampler(entry.samplerDesc, rsEntry.samplerState); - } - break; + SLANG_RETURN_NULL_ON_FAIL(createInputSampler(entry.samplerDesc, rsEntry.samplerState)); + break; + } case ShaderInputType::CombinedTextureSampler: { - throw "not implemented"; - } - break; + assert(!"Not implemented"); + //throw "not implemented"; + return nullptr; + break; + } } - rs->bindings.Add(rsEntry); + bindings.Add(rsEntry); } - return (BindingState*)rs; + BindingStateImpl* rs = new BindingStateImpl; + rs->m_numRenderTargets = layout.numRenderTargets; + rs->m_bindings.SwapWith(bindings); + + return rs; } void D3D11Renderer::applyBindingState(bool isCompute) { - auto context = m_immediateContext; - for (auto & binding : m_currentBindings->bindings) + auto context = m_immediateContext.get(); + for (auto & binding : m_currentBindings->m_bindings) { if (binding.type == ShaderInputType::Buffer) { if (binding.bufferType == InputBufferType::ConstantBuffer) { if (isCompute) - context->CSSetConstantBuffers(binding.binding, 1, &binding.buffer); + context->CSSetConstantBuffers(binding.binding, 1, binding.buffer.readRef()); else { - context->VSSetConstantBuffers(binding.binding, 1, &binding.buffer); - context->PSSetConstantBuffers(binding.binding, 1, &binding.buffer); + context->VSSetConstantBuffers(binding.binding, 1, binding.buffer.readRef()); + context->PSSetConstantBuffers(binding.binding, 1, binding.buffer.readRef()); } } else if (binding.uav) { if (isCompute) - context->CSSetUnorderedAccessViews(binding.binding, 1, &binding.uav, nullptr); + context->CSSetUnorderedAccessViews(binding.binding, 1, binding.uav.readRef(), nullptr); else - context->OMSetRenderTargetsAndUnorderedAccessViews(m_currentBindings->numRenderTargets, - m_renderTargetViews.Buffer(), nullptr, binding.binding, 1, &binding.uav, nullptr); + context->OMSetRenderTargetsAndUnorderedAccessViews(m_currentBindings->m_numRenderTargets, + m_renderTargetViews.Buffer()->readRef(), nullptr, binding.binding, 1, binding.uav.readRef(), nullptr); } else { if (isCompute) - context->CSSetShaderResources(binding.binding, 1, &binding.srv); + context->CSSetShaderResources(binding.binding, 1, binding.srv.readRef()); else { - context->PSSetShaderResources(binding.binding, 1, &binding.srv); - context->VSSetShaderResources(binding.binding, 1, &binding.srv); + context->PSSetShaderResources(binding.binding, 1, binding.srv.readRef()); + context->VSSetShaderResources(binding.binding, 1, binding.srv.readRef()); } } } @@ -1001,30 +1026,30 @@ void D3D11Renderer::applyBindingState(bool isCompute) if (binding.uav) { if (isCompute) - context->CSSetUnorderedAccessViews(binding.binding, 1, &binding.uav, nullptr); + context->CSSetUnorderedAccessViews(binding.binding, 1, binding.uav.readRef(), nullptr); else context->OMSetRenderTargetsAndUnorderedAccessViews(D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, - nullptr, nullptr, binding.binding, 1, &binding.uav, nullptr); + nullptr, nullptr, binding.binding, 1, binding.uav.readRef(), nullptr); } else { if (isCompute) - context->CSSetShaderResources(binding.binding, 1, &binding.srv); + context->CSSetShaderResources(binding.binding, 1, binding.srv.readRef()); else { - context->PSSetShaderResources(binding.binding, 1, &binding.srv); - context->VSSetShaderResources(binding.binding, 1, &binding.srv); + context->PSSetShaderResources(binding.binding, 1, binding.srv.readRef()); + context->VSSetShaderResources(binding.binding, 1, binding.srv.readRef()); } } } else if (binding.type == ShaderInputType::Sampler) { if (isCompute) - context->CSSetSamplers(binding.binding, 1, &binding.samplerState); + context->CSSetSamplers(binding.binding, 1, binding.samplerState.readRef()); else { - context->PSSetSamplers(binding.binding, 1, &binding.samplerState); - context->VSSetSamplers(binding.binding, 1, &binding.samplerState); + context->PSSetSamplers(binding.binding, 1, binding.samplerState.readRef()); + context->VSSetSamplers(binding.binding, 1, binding.samplerState.readRef()); } } else @@ -1034,22 +1059,23 @@ void D3D11Renderer::applyBindingState(bool isCompute) void D3D11Renderer::setBindingState(BindingState* state) { - m_currentBindings = (BindingStateImpl*)state; + m_currentBindings = static_cast<BindingStateImpl*>(state); } -void D3D11Renderer::serializeOutput(BindingState* state, const char* fileName) +void D3D11Renderer::serializeOutput(BindingState* stateIn, const char* fileName) { - auto bindingState = (BindingStateImpl*)state; + auto bindingState = static_cast<BindingStateImpl*>(stateIn); FILE * f = fopen(fileName, "wb"); int id = 0; - for (auto & binding : bindingState->bindings) + for (auto & binding : bindingState->m_bindings) { if (binding.isOutput) { if (binding.buffer) { // create staging buffer - ID3D11Buffer* stageBuf; + ComPtr<ID3D11Buffer> stageBuf; + D3D11_BUFFER_DESC bufDesc; memset(&bufDesc, 0, sizeof(bufDesc)); bufDesc.BindFlags = 0; @@ -1057,14 +1083,13 @@ void D3D11Renderer::serializeOutput(BindingState* state, const char* fileName) bufDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; bufDesc.Usage = D3D11_USAGE_STAGING; - m_device->CreateBuffer(&bufDesc, nullptr, &stageBuf); + SLANG_RETURN_VOID_ON_FAIL(m_device->CreateBuffer(&bufDesc, nullptr, stageBuf.writeRef())); m_immediateContext->CopyResource(stageBuf, binding.buffer); auto ptr = (unsigned int *)map(stageBuf, MapFlavor::HostRead); for (auto i = 0u; i < binding.bufferLength / sizeof(unsigned int); i++) fprintf(f, "%X\n", ptr[i]); unmap(stageBuf); - stageBuf->Release(); } else { diff --git a/tools/render-test/render-gl.cpp b/tools/render-test/render-gl.cpp index 9c77fe7ba..37745d93b 100644 --- a/tools/render-test/render-gl.cpp +++ b/tools/render-test/render-gl.cpp @@ -51,7 +51,8 @@ F(glGenBuffers, PFNGLGENBUFFERSPROC) \ F(glBindBuffer, PFNGLBINDBUFFERPROC) \ F(glBufferData, PFNGLBUFFERDATAPROC) \ - F(glMapBuffer, PFNGLMAPBUFFERPROC) \ + F(glDeleteBuffers, PFNGLDELETEBUFFERSPROC) \ + F(glMapBuffer, PFNGLMAPBUFFERPROC) \ F(glUnmapBuffer, PFNGLUNMAPBUFFERPROC) \ F(glUseProgram, PFNGLUSEPROGRAMPROC) \ F(glBindBufferBase, PFNGLBINDBUFFERBASEPROC) \ @@ -62,6 +63,7 @@ F(glDispatchCompute, PFNGLDISPATCHCOMPUTEPROC) \ F(glActiveTexture, PFNGLACTIVETEXTUREPROC) \ F(glCreateSamplers, PFNGLCREATESAMPLERSPROC) \ + F(glDeleteSamplers, PFNGLDELETESAMPLERSPROC) \ F(glBindSampler, PFNGLBINDSAMPLERPROC) \ F(glTexImage3D, PFNGLTEXIMAGE3DPROC) \ F(glSamplerParameteri, PFNGLSAMPLERPARAMETERIPROC) \ @@ -120,13 +122,33 @@ public: GLsizei offset; }; - struct InputLayoutImpl + class InputLayoutImpl: public InputLayout { - VertexAttributeDesc attributes[kMaxVertexStreams]; - UInt attributeCount = 0; + public: + VertexAttributeDesc m_attributes[kMaxVertexStreams]; + UInt m_attributeCount = 0; }; - struct BindingEntryImpl + class BufferImpl: public Buffer + { + public: + BufferImpl(GLRenderer* renderer, GLuint id): + m_renderer(renderer), + m_id(id) + {} + ~BufferImpl() + { + if (m_renderer) + { + m_renderer->glDeleteBuffers(1, &m_id); + } + } + + GLRenderer* m_renderer; + GLuint m_id; + }; + + struct BindingEntry { ShaderInputType type; GLuint handle; @@ -135,18 +157,56 @@ public: int bufferSize; bool isOutput = false; }; - struct BindingStateImpl - { - List<BindingEntryImpl> entries; + class BindingStateImpl: public BindingState + { + public: + BindingStateImpl(GLRenderer* renderer): + m_renderer(renderer) + { + } + + ~BindingStateImpl() + { + if (m_renderer) + { + m_renderer->destroyBindingEntries(m_entries.Buffer(), int(m_entries.Count())); + } + } + + GLRenderer* m_renderer; + List<BindingEntry> m_entries; }; + class ShaderProgramImpl : public ShaderProgram + { + public: + ShaderProgramImpl(GLRenderer* renderer, GLuint id): + m_renderer(renderer), + m_id(id) + { + } + ~ShaderProgramImpl() + { + if (m_renderer) + { + m_renderer->glDeleteProgram(m_id); + } + } + + GLuint m_id; + GLRenderer* m_renderer; + }; + + void destroyBindingEntry(const BindingEntry& entry); + void destroyBindingEntries(const BindingEntry* entries, int numEntries); + void bindBufferImpl(int target, UInt startSlot, UInt slotCount, Buffer*const* buffers, const UInt* offsets); void flushStateForDraw(); GLuint loadShader(GLenum stage, char const* source); - void createInputBuffer(BindingEntryImpl& rs, InputBufferDesc bufDesc, List<unsigned int>& bufferData); + void createInputBuffer(BindingEntry& rs, InputBufferDesc bufDesc, List<unsigned int>& bufferData); void debugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message); - void createInputTexture(BindingEntryImpl& rs, InputTextureDesc texDesc, InputSamplerDesc samplerDesc); - void createInputSampler(BindingEntryImpl& rs, InputSamplerDesc samplerDesc); + void createInputTexture(BindingEntry& rs, InputTextureDesc texDesc, InputSamplerDesc samplerDesc); + void createInputSampler(BindingEntry& rs, InputSamplerDesc samplerDesc); static void APIENTRY staticDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam); static VertexAttributeFormat getVertexAttributeFormat(Format format); @@ -155,7 +215,9 @@ public: HGLRC m_glContext; float m_clearColor[4] = { 0, 0, 0, 0 }; - InputLayoutImpl* m_boundInputLayout = nullptr; + RefPtr<ShaderProgramImpl> m_boundShaderProgram; + RefPtr<InputLayoutImpl> m_boundInputLayout; + GLenum m_boundPrimitiveTopology = GL_TRIANGLES; GLuint m_boundVertexStreamBuffers[kMaxVertexStreams]; UInt m_boundVertexStreamStrides[kMaxVertexStreams]; @@ -214,9 +276,9 @@ void GLRenderer::bindBufferImpl(int target, UInt startSlot, UInt slotCount, Buff { UInt slot = startSlot + ii; - Buffer* buffer = buffers[ii]; - GLuint bufferID = (GLuint)(uintptr_t)buffer; - + BufferImpl* buffer = static_cast<BufferImpl*>(buffers[ii]); + GLuint bufferID = buffer ? buffer->m_id : 0; + assert(!offsets || !offsets[ii]); glBindBufferBase(target, (GLuint)slot, bufferID); @@ -225,11 +287,11 @@ void GLRenderer::bindBufferImpl(int target, UInt startSlot, UInt slotCount, Buff void GLRenderer::flushStateForDraw() { - auto layout = m_boundInputLayout; - auto attrCount = layout->attributeCount; + auto layout = m_boundInputLayout.Ptr(); + auto attrCount = layout->m_attributeCount; for (UInt ii = 0; ii < attrCount; ++ii) { - auto& attr = layout->attributes[ii]; + auto& attr = layout->m_attributes[ii]; auto streamIndex = attr.streamIndex; @@ -362,7 +424,39 @@ GLuint GLRenderer::loadShader(GLenum stage, const char* source) return shaderID; } -void GLRenderer::createInputBuffer(BindingEntryImpl& rs, InputBufferDesc bufDesc, List<unsigned int>& bufferData) +void GLRenderer::destroyBindingEntry(const BindingEntry& entry) +{ + switch (entry.type) + { + case ShaderInputType::Buffer: + { + glDeleteBuffers(1, &entry.handle); + break; + } + case ShaderInputType::Texture: + case ShaderInputType::CombinedTextureSampler: + { + glDeleteTextures(1, &entry.handle); + break; + } + case ShaderInputType::Sampler: + { + glDeleteSamplers(1, &entry.handle); + break; + } + default: break; + } +} + +void GLRenderer::destroyBindingEntries(const BindingEntry* entries, int numEntries) +{ + for (int i = 0; i < numEntries; ++i) + { + destroyBindingEntry(entries[i]); + } +} + +void GLRenderer::createInputBuffer(BindingEntry& rs, InputBufferDesc bufDesc, List<unsigned int>& bufferData) { rs.bindTarget = (bufDesc.type == InputBufferType::StorageBuffer ? GL_SHADER_STORAGE_BUFFER : GL_UNIFORM_BUFFER); glGenBuffers(1, &rs.handle); @@ -371,8 +465,7 @@ void GLRenderer::createInputBuffer(BindingEntryImpl& rs, InputBufferDesc bufDesc glBindBuffer(rs.bindTarget, 0); } - -void GLRenderer::createInputTexture(BindingEntryImpl& rs, InputTextureDesc texDesc, InputSamplerDesc samplerDesc) +void GLRenderer::createInputTexture(BindingEntry& rs, InputTextureDesc texDesc, InputSamplerDesc samplerDesc) { TextureData texData; generateTextureData(texData, texDesc); @@ -386,11 +479,13 @@ void GLRenderer::createInputTexture(BindingEntryImpl& rs, InputTextureDesc texDe glBindTexture(rs.bindTarget, rs.handle); int slice = 0; for (int i = 0; i < texData.arraySize; i++) + { for (int j = 0; j < texData.mipLevels; j++) { glTexImage2D(rs.bindTarget, j, GL_RGBA8, texData.textureSize, i, 0, GL_RGBA, GL_UNSIGNED_BYTE, texData.dataBuffer[slice].Buffer()); slice++; } + } } else { @@ -458,7 +553,7 @@ void GLRenderer::createInputTexture(BindingEntryImpl& rs, InputTextureDesc texDe } } -void GLRenderer::createInputSampler(BindingEntryImpl& rs, InputSamplerDesc samplerDesc) +void GLRenderer::createInputSampler(BindingEntry& rs, InputSamplerDesc samplerDesc) { glCreateSamplers(1, &rs.handle); glSamplerParameteri(rs.handle, GL_TEXTURE_WRAP_S, GL_REPEAT); @@ -608,18 +703,18 @@ Buffer* GLRenderer::createBuffer(const BufferDesc& desc) glBufferData(target, desc.size, desc.initData, usage); - return (Buffer*)(uintptr_t)bufferID; + return new BufferImpl(this, bufferID); } InputLayout* GLRenderer::createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) { InputLayoutImpl* inputLayout = new InputLayoutImpl; - inputLayout->attributeCount = inputElementCount; + inputLayout->m_attributeCount = inputElementCount; for (UInt ii = 0; ii < inputElementCount; ++ii) { auto& inputAttr = inputElements[ii]; - auto& glAttr = inputLayout->attributes[ii]; + auto& glAttr = inputLayout->m_attributes[ii]; glAttr.streamIndex = 0; glAttr.format = getVertexAttributeFormat(inputAttr.format); @@ -629,8 +724,10 @@ InputLayout* GLRenderer::createInputLayout(const InputElementDesc* inputElements return (InputLayout*)inputLayout; } -void* GLRenderer::map(Buffer* buffer, MapFlavor flavor) +void* GLRenderer::map(Buffer* bufferIn, MapFlavor flavor) { + BufferImpl* buffer = static_cast<BufferImpl*>(bufferIn); + GLenum target = GL_UNIFORM_BUFFER; GLuint access = 0; @@ -645,23 +742,23 @@ void* GLRenderer::map(Buffer* buffer, MapFlavor flavor) break; } - auto bufferID = (GLuint)(uintptr_t)buffer; + auto bufferID = buffer ? buffer->m_id : 0; glBindBuffer(target, bufferID); return glMapBuffer(target, access); } -void GLRenderer::unmap(Buffer* buffer) +void GLRenderer::unmap(Buffer* bufferIn) { + BufferImpl* buffer = static_cast<BufferImpl*>(bufferIn); GLenum target = GL_UNIFORM_BUFFER; - - auto bufferID = (GLuint)(uintptr_t)buffer; + auto bufferID = buffer ? buffer->m_id : 0; glUnmapBuffer(target); } void GLRenderer::setInputLayout(InputLayout* inputLayout) { - m_boundInputLayout = (InputLayoutImpl*)inputLayout; + m_boundInputLayout = static_cast<InputLayoutImpl*>(inputLayout); } void GLRenderer::setPrimitiveTopology(PrimitiveTopology topology) @@ -684,19 +781,21 @@ void GLRenderer::setVertexBuffers(UInt startSlot, UInt slotCount, Buffer*const* { UInt slot = startSlot + ii; - Buffer* buffer = buffers[ii]; - GLuint bufferID = (GLuint)(uintptr_t)buffer; - + BufferImpl* buffer = static_cast<BufferImpl*>(buffers[ii]); + GLuint bufferID = buffer ? buffer->m_id : 0; + m_boundVertexStreamBuffers[slot] = bufferID; m_boundVertexStreamStrides[slot] = strides[ii]; m_boundVertexStreamOffsets[slot] = offsets[ii]; } } -void GLRenderer::setShaderProgram(ShaderProgram* program) +void GLRenderer::setShaderProgram(ShaderProgram* programIn) { - GLuint programID = (GLuint)(uintptr_t)program; - glUseProgram(programID); + ShaderProgramImpl* program = static_cast<ShaderProgramImpl*>(programIn); + m_boundShaderProgram = program; + GLuint programID = program ? program->m_id : 0; + glUseProgram(programID); } void GLRenderer::setConstantBuffers(UInt startSlot, UInt slotCount, Buffer*const* buffers, const UInt* offsets) @@ -718,10 +817,10 @@ void GLRenderer::dispatchCompute(int x, int y, int z) BindingState* GLRenderer::createBindingState(const ShaderInputLayout& layout) { - BindingStateImpl* rs = new BindingStateImpl; + BindingStateImpl* state = new BindingStateImpl(this); for (auto & entry : layout.entries) { - BindingEntryImpl rsEntry; + BindingEntry rsEntry; rsEntry.isOutput = entry.isOutput; rsEntry.binding = entry.glslBinding; rsEntry.type = entry.type; @@ -740,15 +839,15 @@ BindingState* GLRenderer::createBindingState(const ShaderInputLayout& layout) createInputSampler(rsEntry, entry.samplerDesc); break; } - rs->entries.Add(rsEntry); + state->m_entries.Add(rsEntry); } - return (BindingState*)rs; + return state; } void GLRenderer::setBindingState(BindingState* stateIn) { - BindingStateImpl* state = (BindingStateImpl*)stateIn; - for (auto & entry : state->entries) + BindingStateImpl* state = static_cast<BindingStateImpl*>(stateIn); + for (auto & entry : state->m_entries) { switch (entry.type) { @@ -773,7 +872,7 @@ void GLRenderer::serializeOutput(BindingState* stateIn, const char* fileName) BindingStateImpl * state = (BindingStateImpl*)stateIn; FILE * f; fopen_s(&f, fileName, "wt"); - for (auto & entry : state->entries) + for (auto & entry : state->m_entries) { if (entry.isOutput) { @@ -837,7 +936,7 @@ ShaderProgram* GLRenderer::compileProgram(const ShaderCompileRequest& request) return nullptr; } - return (ShaderProgram*)(uintptr_t)programID; + return new ShaderProgramImpl(this, programID); } diff --git a/tools/render-test/render-vk.cpp b/tools/render-test/render-vk.cpp index ff22c91ea..bb177a88a 100644 --- a/tools/render-test/render-vk.cpp +++ b/tools/render-test/render-vk.cpp @@ -4,6 +4,8 @@ #include "options.h" #include "render.h" +#include "../../source/core/smart-pointer.h" + #ifdef _WIN32 #define VK_USE_PLATFORM_WIN32_KHR 1 #endif @@ -75,6 +77,7 @@ namespace renderer_test { +using namespace Slang; #define RETURN_ON_VK_FAIL(x) { VkResult _vkRes = x; if (_vkRes != VK_SUCCESS) { SLANG_RETURN_ON_FAIL(toSlangResult(_vkRes)); }} @@ -108,20 +111,45 @@ public: protected: - struct BufferImpl + class BufferImpl: public Buffer { - VkBuffer buffer; - VkDeviceMemory memory; + public: + + BufferImpl(VKRenderer* renderer, VkBuffer buffer, VkDeviceMemory memory): + m_renderer(renderer), + m_buffer(buffer), + m_memory(memory) + { + assert(renderer); + } + + ~BufferImpl() + { + // Now destroy the staging buffer + if (m_renderer) + { + m_renderer->vkDestroyBuffer(m_renderer->m_device, m_buffer, nullptr); + m_renderer->vkFreeMemory(m_renderer->m_device, m_memory, nullptr); + } + } + + VKRenderer* m_renderer; + VkBuffer m_buffer; + VkDeviceMemory m_memory; }; - struct ShaderProgramImpl + class ShaderProgramImpl: public ShaderProgram { - VkPipelineShaderStageCreateInfo compute; - VkPipelineShaderStageCreateInfo vertex; - VkPipelineShaderStageCreateInfo fragment; + public: + + VkPipelineShaderStageCreateInfo m_compute; + VkPipelineShaderStageCreateInfo m_vertex; + VkPipelineShaderStageCreateInfo m_fragment; + + List<char> m_buffers[2]; //< To keep storage of code in scope }; - struct BindingImpl + struct Binding { ShaderInputType type; InputBufferType bufferType; // Only valid if `type` is `Buffer` @@ -136,19 +164,28 @@ public: int bufferLength = 0; }; - struct BindingStateImpl + class BindingStateImpl: public BindingState { - Slang::List<BindingImpl> bindings; - int numRenderTargets; + public: + BindingStateImpl(VKRenderer* renderer): + m_renderer(renderer), + m_numRenderTargets(0) + { + } + + VKRenderer* m_renderer; + List<Binding> m_bindings; + int m_numRenderTargets; }; - struct InputLayoutImpl + class InputLayoutImpl: public InputLayout { + public: }; VkBool32 handleDebugMessage(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg); - BufferImpl createBufferImpl(size_t bufferSize, VkBufferUsageFlags usage, VkMemoryPropertyFlags reqMemoryProperties, const void* initData = nullptr); + BufferImpl* createBufferImpl(size_t bufferSize, VkBufferUsageFlags usage, VkMemoryPropertyFlags reqMemoryProperties, const void* initData = nullptr); VkCommandBuffer getCommandBuffer(); VkCommandBuffer beginCommandBuffer(); @@ -156,7 +193,7 @@ public: uint32_t getMemoryTypeIndex(uint32_t inTypeBits, VkMemoryPropertyFlags properties); - VkPipelineShaderStageCreateInfo compileEntryPoint(const ShaderCompileRequest::EntryPoint& entryPointRequest, VkShaderStageFlagBits stage); + VkPipelineShaderStageCreateInfo compileEntryPoint(const ShaderCompileRequest::EntryPoint& entryPointRequest, VkShaderStageFlagBits stage, List<char>& bufferOut); void createInputTexture(const InputTextureDesc& inputDesc, VkImageView& viewOut); void createInputSampler(const InputSamplerDesc& inputDesc, VkSampler& stateOut); @@ -179,8 +216,8 @@ public: VkSubmitInfo m_submitInfo; VkDebugReportCallbackEXT m_debugReportCallback; - BindingStateImpl* m_currentBindingState = nullptr; - ShaderProgramImpl* m_currentProgram = nullptr; + RefPtr<BindingStateImpl> m_currentBindingState; + RefPtr<ShaderProgramImpl> m_currentProgram; float m_clearColor[4] = { 0, 0, 0, 0 };; @@ -276,7 +313,7 @@ void VKRenderer::flushCommandBuffer(VkCommandBuffer commandBuffer) vkFreeCommandBuffers(m_device, m_commandPool, 1, &commandBuffer); } -VKRenderer::BufferImpl VKRenderer::createBufferImpl(size_t bufferSize, VkBufferUsageFlags usage, VkMemoryPropertyFlags reqMemoryProperties, const void* initData) +VKRenderer::BufferImpl* VKRenderer::createBufferImpl(size_t bufferSize, VkBufferUsageFlags usage, VkMemoryPropertyFlags reqMemoryProperties, const void* initData) { if (initData) { @@ -313,33 +350,26 @@ VKRenderer::BufferImpl VKRenderer::createBufferImpl(size_t bufferSize, VkBufferU // used for the buffer doesn't let us fill things in // directly. - BufferImpl staging = createBufferImpl(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + RefPtr<BufferImpl> staging = createBufferImpl(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); // Copy into staging buffer void* mappedData = nullptr; - checkResult(vkMapMemory(m_device, staging.memory, 0, bufferSize, 0, &mappedData)); + checkResult(vkMapMemory(m_device, staging->m_memory, 0, bufferSize, 0, &mappedData)); memcpy(mappedData, initData, bufferSize); - vkUnmapMemory(m_device, staging.memory); + vkUnmapMemory(m_device, staging->m_memory); // Copy from staging buffer to real buffer VkCommandBuffer commandBuffer = beginCommandBuffer(); VkBufferCopy copyInfo = {}; copyInfo.size = bufferSize; - vkCmdCopyBuffer(commandBuffer, staging.buffer, buffer, 1, ©Info); + vkCmdCopyBuffer(commandBuffer, staging->m_buffer, buffer, 1, ©Info); flushCommandBuffer(commandBuffer); - - // Now destroy the staging buffer - vkDestroyBuffer(m_device, staging.buffer, nullptr); - vkFreeMemory(m_device, staging.memory, nullptr); } - BufferImpl impl; - impl.buffer = buffer; - impl.memory = memory; - return impl; + return new BufferImpl(this, buffer, memory); } uint32_t VKRenderer::getMemoryTypeIndex(uint32_t inTypeBits, VkMemoryPropertyFlags properties) @@ -401,12 +431,13 @@ void VKRenderer::createInputBuffer(const ShaderInputLayoutEntry& entry, const In usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT; } - BufferImpl bufferImpl = createBufferImpl(bufferSize, usage, reqMemoryProperties, initData); + RefPtr<BufferImpl> bufferImpl(createBufferImpl(bufferSize, usage, reqMemoryProperties, initData)); // TODO: need to hang onto the `memory` field so // that we can release it when we are done. - - bufferOut = bufferImpl.buffer; + // Set the m_renderer to null to stop any destruction as bufferImpl leaves scope + bufferImpl->m_renderer = nullptr; + bufferOut = bufferImpl->m_buffer; // Fill in any views needed switch (bufferDesc.type) @@ -421,7 +452,7 @@ void VKRenderer::createInputBuffer(const ShaderInputLayoutEntry& entry, const In } } -VkPipelineShaderStageCreateInfo VKRenderer::compileEntryPoint(const ShaderCompileRequest::EntryPoint& entryPointRequest, VkShaderStageFlagBits stage) +VkPipelineShaderStageCreateInfo VKRenderer::compileEntryPoint(const ShaderCompileRequest::EntryPoint& entryPointRequest, VkShaderStageFlagBits stage, List<char>& bufferOut) { char const* dataBegin = entryPointRequest.source.dataBegin; char const* dataEnd = entryPointRequest.source.dataEnd; @@ -429,9 +460,11 @@ VkPipelineShaderStageCreateInfo VKRenderer::compileEntryPoint(const ShaderCompil // We need to make a copy of the code, since the Slang compiler // will free the memory after a compile request is closed. size_t codeSize = dataEnd - dataBegin; - char* codeBegin = (char*)malloc(codeSize); - memcpy(codeBegin, dataBegin, codeSize); + bufferOut.InsertRange(0, dataBegin, codeSize); + + char* codeBegin = bufferOut.Buffer(); + VkShaderModuleCreateInfo moduleCreateInfo = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO }; moduleCreateInfo.pCode = (uint32_t*)codeBegin; moduleCreateInfo.codeSize = codeSize; @@ -661,15 +694,7 @@ Buffer* VKRenderer::createBuffer(const BufferDesc& desc) break; } - BufferImpl bufferImpl = createBufferImpl( - bufferSize, - usage, - reqMemoryProperties, - desc.initData); - - BufferImpl* bufferPtr = new BufferImpl(); - *bufferPtr = bufferImpl; - return (Buffer*)bufferPtr; + return createBufferImpl(bufferSize, usage, reqMemoryProperties, desc.initData); } InputLayout* VKRenderer::createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) @@ -717,11 +742,11 @@ void VKRenderer::draw(UInt vertexCount, UInt startVertex = 0) BindingState* VKRenderer::createBindingState(const ShaderInputLayout& layout) { - BindingStateImpl* bindingState = new BindingStateImpl; - bindingState->numRenderTargets = layout.numRenderTargets; + BindingStateImpl* bindingState = new BindingStateImpl(this); + bindingState->m_numRenderTargets = layout.numRenderTargets; for (auto & entry : layout.entries) { - BindingImpl binding; + Binding binding; binding.type = entry.type; binding.binding = entry.hlslBinding; binding.isOutput = entry.isOutput; @@ -750,24 +775,24 @@ BindingState* VKRenderer::createBindingState(const ShaderInputLayout& layout) break; } } - bindingState->bindings.Add(binding); + bindingState->m_bindings.Add(binding); } - return (BindingState*)bindingState; + return bindingState; } void VKRenderer::setBindingState(BindingState* state) { - m_currentBindingState = (BindingStateImpl*)state; + m_currentBindingState = static_cast<BindingStateImpl*>(state); } void VKRenderer::serializeOutput(BindingState* s, const char* fileName) { - auto state = (BindingStateImpl*)s; + auto state = static_cast<BindingStateImpl*>(s); FILE * f = fopen(fileName, "wb"); int id = 0; - for (auto& bb : state->bindings) + for (auto& bb : state->m_bindings) { if (bb.isOutput) { @@ -775,31 +800,27 @@ void VKRenderer::serializeOutput(BindingState* s, const char* fileName) { // create staging buffer size_t bufferSize = bb.bufferLength; - BufferImpl staging = createBufferImpl(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + RefPtr<BufferImpl> staging(createBufferImpl(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)); // Copy from real buffer to staging buffer VkCommandBuffer commandBuffer = beginCommandBuffer(); VkBufferCopy copyInfo = {}; copyInfo.size = bufferSize; - vkCmdCopyBuffer(commandBuffer, bb.buffer, staging.buffer, 1, ©Info); + vkCmdCopyBuffer(commandBuffer, bb.buffer, staging->m_buffer, 1, ©Info); flushCommandBuffer(commandBuffer); // Write out the data from the buffer void* mappedData = nullptr; - checkResult(vkMapMemory(m_device, staging.memory, 0, bufferSize, 0, &mappedData)); + checkResult(vkMapMemory(m_device, staging->m_memory, 0, bufferSize, 0, &mappedData)); auto ptr = (unsigned int *)mappedData; for (auto i = 0u; i < bufferSize / sizeof(unsigned int); i++) fprintf(f, "%X\n", ptr[i]); - vkUnmapMemory(m_device, staging.memory); - - // Now destroy the staging buffer - vkDestroyBuffer(m_device, staging.buffer, nullptr); - vkFreeMemory(m_device, staging.memory, nullptr); + vkUnmapMemory(m_device, staging->m_memory); } else { @@ -819,7 +840,7 @@ void VKRenderer::dispatchCompute(int x, int y, int z) Slang::List<VkDescriptorSetLayoutBinding> bindings; - for (auto bb : m_currentBindingState->bindings) + for (auto bb : m_currentBindingState->m_bindings) { switch (bb.type) { @@ -887,7 +908,7 @@ void VKRenderer::dispatchCompute(int x, int y, int z) checkResult(vkAllocateDescriptorSets(m_device, &descriptorSetAllocInfo, &descriptorSet)); // Fill in the descritpor set, using our binding information - for (auto bb : m_currentBindingState->bindings) + for (auto bb : m_currentBindingState->m_bindings) { switch (bb.type) { @@ -939,7 +960,7 @@ void VKRenderer::dispatchCompute(int x, int y, int z) // Then create a pipeline to use that layout VkComputePipelineCreateInfo computePipelineInfo = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO }; - computePipelineInfo.stage = m_currentProgram->compute; + computePipelineInfo.stage = m_currentProgram->m_compute; computePipelineInfo.layout = pipelineLayout; VkPipelineCache pipelineCache = 0; @@ -977,14 +998,14 @@ ShaderProgram* VKRenderer::compileProgram(const ShaderCompileRequest & request) ShaderProgramImpl* impl = new ShaderProgramImpl; if (request.computeShader.name) { - impl->compute = compileEntryPoint(request.computeShader, VK_SHADER_STAGE_COMPUTE_BIT); + impl->m_compute = compileEntryPoint(request.computeShader, VK_SHADER_STAGE_COMPUTE_BIT, impl->m_buffers[0]); } else { - impl->vertex = compileEntryPoint(request.vertexShader, VK_SHADER_STAGE_VERTEX_BIT); - impl->fragment = compileEntryPoint(request.fragmentShader, VK_SHADER_STAGE_FRAGMENT_BIT); + impl->m_vertex = compileEntryPoint(request.vertexShader, VK_SHADER_STAGE_VERTEX_BIT, impl->m_buffers[0]); + impl->m_fragment = compileEntryPoint(request.fragmentShader, VK_SHADER_STAGE_FRAGMENT_BIT, impl->m_buffers[1]); } - return (ShaderProgram*)impl; + return impl; } } // renderer_test diff --git a/tools/render-test/render.h b/tools/render-test/render.h index 08d364b05..7484f0f3d 100644 --- a/tools/render-test/render.h +++ b/tools/render-test/render.h @@ -6,14 +6,29 @@ #include "shader-input-layout.h" #include "../../source/core/slang-result.h" +#include "../../source/core/smart-pointer.h" namespace renderer_test { // Declare opaque type -struct Buffer; -struct InputLayout; -struct ShaderProgram; -struct BindingState; +class Buffer: public Slang::RefObject +{ + public: +}; +class InputLayout: public Slang::RefObject +{ + public: +}; + +class ShaderProgram: public Slang::RefObject +{ + public: +}; + +class BindingState: public Slang::RefObject +{ + public: +}; struct ShaderCompileRequest { @@ -91,7 +106,7 @@ enum class PrimitiveTopology TriangleList, }; -class Renderer +class Renderer: public Slang::RefObject { public: virtual SlangResult initialize(void* inWindowHandle) = 0; |
