My progress (pt.1)

I haven’t written a new entry for a long time now since I have been very busy and had to look for a new fulltime employment. However, I still tried to put time into my „engine“ and the game I want to build with it once I have all the necessary things in place.

With this post I’d like to give a brief overview of what I have worked on all the months. There is actually quite a lot to talk about and I will most likely talk about the changes in multiple blog posts.

Renderer

I started working on a basic rendering architecture. As a reference I used the resources presented at the molecule musing blog where Stefan Reinalter uses a bucket approach that can be filled with draw calls which then will be sorted and submitted to the gpu. I haven’t integrated sorting yet since there isn’t a lot to draw just now. However, I plan to make use of my task system that should help with multithreading the sort algorithm. Each bucket will than be sorted in parallel.

auto Key = GenDrawKey64(true, Material.Index, RenderLayer::StaticGeom, 0.0f);

auto DrawCmd = GeometryBucket.AddCommand<Draw::DrawIndexedData>(Key);
DrawCmd->IndexCount = Mesh->NumIndices;
DrawCmd->VertexArrayId = Mesh->VertexArrayId;
DrawCmd->Model = InModelMatrix;

The above sample shows how an indexed draw call could be submitted to a specific bucket. In this case a geometry bucket which renders to the gbuffer.

On top of this I implemented a deferred rendering pipeline, SSAO, FXAA, PBR (without reflections and gi at the moment) and am working on shadow mapping.

DX11

Besides the implementation of the renderer I integrated DX11, too. This forced me to rehtink about the structure of how the GDI-layer, which communicates with DirectX or OpenGL. I took some clues from different engines and decided to use an approach that should fit well enough with modern APIs such as DX12 and Vulkan, too.

The take-away here is that I use a large PipelineStateObject that contains all the resources needed for a pipeline state switch whenever objects need to be rendered differently from the other it will make a full pipeline switch.

// Create DEBUG PSO!
GfxPipelineStateObjectDesc desc = {};
desc.RasterizerState.CullMode = GfxCullMode::CullBack;
desc.RasterizerState.FillMode = GfxFillMode::FillSolid;
desc.RasterizerState.FrontCounterClockwise = 0;    
desc.DepthStencilState.DepthEnable = true;
desc.DepthStencilState.DepthFunc = GfxComparisonFunc::LessEqual;
desc.DepthStencilState.DepthWriteMask = GfxDepthWriteMask::DepthWriteMaskAll;
desc.BlendState.RenderTarget[0].BlendEnable = FALSE;
desc.BlendState.RenderTarget[0].RenderTargetWriteMask = (((1 | 2) | 4) | 8);
desc.InputLayout = gPositionNormUV2Layout;
desc.TopologyType = GfxTopologyType::TopologyPolygon;
desc.PixelShaderId = rs->FindShader(CommonShaderHandles::DebugPS)->GfxShaderId;
desc.VertexShaderId = rs->FindShader(CommonShaderHandles::DebugVS)->GfxShaderId;
CachePSO("Debug", gdi->CreatePSO(desc, nullptr));

The code above shows an example of the creation of a pso object. Calling gdi->CreatePSO creates all the state objects internally. PSO Objects can be saved in a map for easy lookup later on.

Switching between PSOs means that I’ll have to call the SetPipelineState method from the GDI class with the id of the pso. Once the pso is bound I can decide to bind the shaders and commit the resources bound to the pipeline state such as Samplers and ShaderResourceViews (Textures, RenderTargets etc.).

The current state of the engine.

As you can see in the screenshot there is still no lighting at the moment. However, this will change in the upcoming days as I already had it up and running when I still used OpenGL and now it’s only a matter of porting it over to DX11 and HLSL.

Once this is implemented I’ll look and see how it performs with more draw calls and complex meshes. I still have to implement texture support, too.

Kurzmitteilung

Compiling HLSL Shader with premake5

I guess a lot of you that use premake often already know this, but since I find this to be handy I want to share it. A couple of days ago I needed to get shaders up and running in a very simple way. I started out by using the obligatory methods from the DirectX Api:

D3DCompileFromFile or the alternative D3DCompileToBlob. I still employ these methods however instead of compiling the file at runtime I decided to load pre-compiled shaders for now.

Since I don’t want to compile shaders manually each time I compile the project I looked for a solution that can be used with premake5. Everything I write I’ve found at https://stackoverflow.com/questions/55055150/premake5-how-to-build-hlsl-shaders. For an in depth look navigate to the link.

How does it work?

Navigate to your main premake5.lua script file and open it. Add the following lines of code to your project section.

shadermodel("5.0")

   shaderassembler("AssemblyCode")
   local shader_dir = "../Assets/Shader/"

   -- HLSL files that don't end with 'Extensions' will be ignored as they will be
   -- used as includes
   filter("files:**.hlsl")
     flags("ExcludeFromBuild")
     shaderobjectfileoutput(shader_dir.."%{file.basename}"..".cso")
     shaderassembleroutput(shader_dir.."%{file.basename}"..".asm")

   filter("files:**_ps.hlsl")
     removeflags("ExcludeFromBuild")
     shadertype("Pixel")

   filter("files:**_vs.hlsl")
      removeflags("ExcludeFromBuild")
      shadertype("Vertex")


   -- Warnings as errors
   shaderoptions({"/WX"})

The file tells premake which kind of shader is contained in each of the files. I think the keywords in here are very self-explanatory however with each filter you can specify how each shader file will be compiled. Shadertype defines what type of shader the file is containing, the shaderentry contains the name of the entry function of the shader.