summaryrefslogtreecommitdiffstats
path: root/Projects/Asteroids/src/asteroids_DE.cpp
diff options
context:
space:
mode:
authorEgor Yusov <egor.yusov@gmail.com>2017-05-20 20:20:23 +0000
committerEgor Yusov <egor.yusov@gmail.com>2017-05-20 20:20:23 +0000
commitcdd751dc2f5bf0851c795587aab4fd547e95b6a8 (patch)
treec20f440a9a092ec8f655e38f30cab522a4933f93 /Projects/Asteroids/src/asteroids_DE.cpp
parentUpdated submodules (diff)
downloadDiligentEngine-cdd751dc2f5bf0851c795587aab4fd547e95b6a8.tar.gz
DiligentEngine-cdd751dc2f5bf0851c795587aab4fd547e95b6a8.zip
Added asteroids sample
Diffstat (limited to 'Projects/Asteroids/src/asteroids_DE.cpp')
-rw-r--r--Projects/Asteroids/src/asteroids_DE.cpp870
1 files changed, 870 insertions, 0 deletions
diff --git a/Projects/Asteroids/src/asteroids_DE.cpp b/Projects/Asteroids/src/asteroids_DE.cpp
new file mode 100644
index 0000000..0cb3ddf
--- /dev/null
+++ b/Projects/Asteroids/src/asteroids_DE.cpp
@@ -0,0 +1,870 @@
+// Copyright 2014 Intel Corporation All Rights Reserved
+//
+// Intel makes no representations about the suitability of this software for any purpose.
+// THIS SOFTWARE IS PROVIDED ""AS IS."" INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES,
+// EXPRESS OR IMPLIED, AND ALL LIABILITY, INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES,
+// FOR THE USE OF THIS SOFTWARE, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY
+// RIGHTS, AND INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+// Intel does not assume any responsibility for any errors which may appear in this software
+// nor any responsibility to update it.
+
+#include <directxmath.h>
+#include <math.h>
+
+#include <iostream>
+#include <algorithm>
+#include <vector>
+#include <future>
+#include <limits>
+#include <random>
+#include <locale>
+#include <codecvt>
+
+#include "asteroids_DE.h"
+#include "RenderDeviceFactoryD3D11.h"
+#include "RenderDeviceFactoryD3D12.h"
+#include "RenderDeviceFactoryOpenGL.h"
+#include "BasicShaderSourceStreamFactory.h"
+#include "MapHelper.h"
+
+#include "util.h"
+#include "mesh.h"
+#include "noise.h"
+#include "texture.h"
+#include "StringTools.h"
+#include "TextureUtilities.h"
+
+using namespace Diligent;
+
+namespace Diligent
+{
+#ifdef ENGINE_DLL
+ CreateDeviceAndContextsD3D11Type CreateDeviceAndContextsD3D11 = nullptr;
+ CreateSwapChainD3D11Type CreateSwapChainD3D11 = nullptr;
+
+ CreateDeviceAndContextsD3D12Type CreateDeviceAndContextsD3D12 = nullptr;
+ CreateSwapChainD3D12Type CreateSwapChainD3D12 = nullptr;
+
+ CreateDeviceAndSwapChainGLType CreateDeviceAndSwapChainGL = nullptr;
+#endif
+}
+
+namespace AsteroidsDE {
+
+
+// Create Direct3D device and swap chain
+void Asteroids::InitDevice(HWND hWnd, DeviceType DevType)
+{
+ EngineCreationAttribs EngineCreationAttribs;
+ EngineCreationAttribs.strShaderCachePath = "bin\\tmp\\ShaderCache";
+ SwapChainDesc SwapChainDesc;
+ SwapChainDesc.SamplesCount = 1;
+ SwapChainDesc.BufferCount = NUM_SWAP_CHAIN_BUFFERS;
+ SwapChainDesc.ColorBufferFormat = TEX_FORMAT_RGBA8_UNORM_SRGB;
+ SwapChainDesc.DepthBufferFormat = TEX_FORMAT_D32_FLOAT;
+ SwapChainDesc.DefaultDepthValue = 0.f;
+ switch (DevType)
+ {
+ case DeviceType::D3D12:
+ case DeviceType::D3D11:
+ {
+ std::vector<IDeviceContext*> ppContexts(mNumSubsets);
+ if(DevType == DeviceType::D3D11)
+ {
+ EngineD3D11Attribs DeviceAttribs;
+ DeviceAttribs.DebugFlags = (Uint32)EngineD3D11DebugFlags::VerifyCommittedShaderResources |
+ (Uint32)EngineD3D11DebugFlags::VerifyCommittedResourceRelevance;
+
+#ifdef ENGINE_DLL
+ if(!CreateDeviceAndContextsD3D11 || !CreateSwapChainD3D11)
+ LoadGraphicsEngineD3D11(CreateDeviceAndContextsD3D11, CreateSwapChainD3D11);
+#endif
+ CreateDeviceAndContextsD3D11( DeviceAttribs, &mDevice, ppContexts.data(), mNumSubsets-1 );
+ CreateSwapChainD3D11( mDevice, ppContexts[0], SwapChainDesc, hWnd, &mSwapChain );
+ }
+ else
+ {
+ EngineD3D12Attribs Attribs;
+ Attribs.GPUDescriptorHeapDynamicSize[0] = 65536*4;
+ Attribs.GPUDescriptorHeapSize[0] = 65536*4;
+#ifndef _DEBUG
+ Attribs.DynamicDescriptorAllocationChunkSize[0] = 4*2048;
+#endif
+#ifdef ENGINE_DLL
+ if(!CreateDeviceAndContextsD3D12 || !CreateSwapChainD3D12)
+ LoadGraphicsEngineD3D12(CreateDeviceAndContextsD3D12, CreateSwapChainD3D12);
+#endif
+ CreateDeviceAndContextsD3D12( Attribs, &mDevice, ppContexts.data(), mNumSubsets-1 );
+ CreateSwapChainD3D12( mDevice, ppContexts[0], SwapChainDesc, hWnd, &mSwapChain );
+ }
+
+ mDeviceCtxt.Attach(ppContexts[0]);
+ mDeferredCtxt.resize(mNumSubsets-1);
+ for(size_t ctx=0; ctx < mNumSubsets-1; ++ctx)
+ mDeferredCtxt[ctx].Attach(ppContexts[1+ctx]);
+ }
+ break;
+
+ case DeviceType::OpenGL:
+#ifdef ENGINE_DLL
+ if(!CreateDeviceAndSwapChainGL)
+ LoadGraphicsEngineOpenGL(CreateDeviceAndSwapChainGL);
+#endif
+ CreateDeviceAndSwapChainGL(
+ EngineCreationAttribs, &mDevice, &mDeviceCtxt, SwapChainDesc, hWnd, &mSwapChain );
+ break;
+
+ default:
+ LOG_ERROR_AND_THROW("Unknown device type");
+ break;
+ }
+}
+
+Asteroids::Asteroids(UINT NumThreads, AsteroidsSimulation* asteroids, GUI* gui, HWND hWnd, Diligent::DeviceType DevType)
+ : mAsteroids(asteroids)
+ , mGUI(gui)
+{
+ QueryPerformanceFrequency((LARGE_INTEGER*)&mPerfCounterFreq);
+
+ mNumSubsets = std::max(NumThreads,1u);
+ mNumSubsets = std::min(NumThreads,32u);
+
+ InitDevice(hWnd, DevType);
+
+ mCmdLists.resize(mDeferredCtxt.size());
+ mWorkerThreads.resize(mNumSubsets-1);
+ for(auto &thread : mWorkerThreads)
+ {
+ thread = std::thread(WorkerThreadFunc, this, (Uint32)(&thread-mWorkerThreads.data()) );
+ }
+
+ const char *spriteFile = nullptr;
+ switch(DevType)
+ {
+ case DeviceType::D3D11: spriteFile = "DiligentD3D11.dds"; break;
+ case DeviceType::D3D12: spriteFile = "DiligentD3D12.dds"; break;
+ case DeviceType::OpenGL: spriteFile = "DiligentGL.dds"; break;
+ }
+ mSprite.reset( new GUISprite(5, 10, 140, 50, spriteFile) );
+
+ BasicShaderSourceStreamFactory BasicSSSFactory({"src"});
+
+ mBackBufferWidth = mSwapChain->GetDesc().Width;
+ mBackBufferHeight = mSwapChain->GetDesc().Height;
+ // Create draw constant buffer
+ {
+ BufferDesc desc;
+ desc.Name = "draw constant buffer (dynamic)";
+ desc.Usage = USAGE_DYNAMIC;
+ desc.uiSizeInBytes = (Uint32) sizeof(DrawConstantBuffer);
+ desc.BindFlags = BIND_UNIFORM_BUFFER;
+ desc.CPUAccessFlags = CPU_ACCESS_WRITE;
+ mDevice->CreateBuffer(desc, BufferData(), &mDrawConstantBuffer);
+ }
+
+ // create pipeline state
+ {
+ PipelineStateDesc PSODesc;
+ LayoutElement inputDesc[] = {
+ LayoutElement( 0, 0, 3, VT_FLOAT32),
+ LayoutElement( 1, 0, 3, VT_FLOAT32)
+ };
+
+ PSODesc.GraphicsPipeline.InputLayout.LayoutElements = inputDesc;
+ PSODesc.GraphicsPipeline.InputLayout.NumElements = _countof(inputDesc);
+
+ PSODesc.GraphicsPipeline.DepthStencilDesc.DepthFunc = COMPARISON_FUNC_GREATER_EQUAL;
+
+ RefCntAutoPtr<IShader> vs, ps;
+ {
+ ShaderCreationAttribs attribs;
+ attribs.Desc.DefaultVariableType = SHADER_VARIABLE_TYPE_STATIC;
+ attribs.Desc.ShaderType = SHADER_TYPE_VERTEX;
+ attribs.Desc.Name = "Asteroids VS";
+ attribs.EntryPoint = "asteroid_vs";
+ attribs.FilePath = "asteroid_vs.hlsl";
+ attribs.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL;
+ attribs.pShaderSourceStreamFactory = &BasicSSSFactory;
+ mDevice->CreateShader(attribs, &vs);
+ vs->GetShaderVariable("DrawConstantBuffer")->Set(mDrawConstantBuffer);
+ }
+
+ {
+ ShaderCreationAttribs attribs;
+ attribs.Desc.DefaultVariableType = m_BindingMode == BindingMode::Dynamic ? SHADER_VARIABLE_TYPE_DYNAMIC : SHADER_VARIABLE_TYPE_MUTABLE;
+ attribs.Desc.ShaderType = SHADER_TYPE_PIXEL;
+ attribs.Desc.Name = "Asteroids PS";
+ attribs.EntryPoint = "asteroid_ps_d3d11";
+ attribs.FilePath = "asteroid_ps_d3d11.hlsl";
+ attribs.pShaderSourceStreamFactory = &BasicSSSFactory;
+ attribs.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL;
+
+ StaticSamplerDesc samDesc;
+ samDesc.Desc.MagFilter = FILTER_TYPE_ANISOTROPIC;
+ samDesc.Desc.MinFilter = FILTER_TYPE_ANISOTROPIC;
+ samDesc.Desc.MipFilter = FILTER_TYPE_ANISOTROPIC;
+ samDesc.Desc.AddressU = TEXTURE_ADDRESS_WRAP;
+ samDesc.Desc.AddressV = TEXTURE_ADDRESS_WRAP;
+ samDesc.Desc.AddressW = TEXTURE_ADDRESS_WRAP;
+ samDesc.Desc.MinLOD = -D3D11_FLOAT32_MAX;
+ samDesc.Desc.MaxLOD = D3D11_FLOAT32_MAX;
+ samDesc.Desc.MipLODBias = 0.0f;
+ samDesc.Desc.MaxAnisotropy = TEXTURE_ANISO;
+ samDesc.Desc.ComparisonFunc = COMPARISON_FUNC_NEVER;
+ samDesc.TextureName = "Tex";
+ attribs.Desc.StaticSamplers = &samDesc;
+ attribs.Desc.NumStaticSamplers = 1;
+
+ mDevice->CreateShader(attribs, &ps);
+ }
+ PSODesc.GraphicsPipeline.RTVFormats[0] = TEX_FORMAT_RGBA8_UNORM_SRGB;
+ PSODesc.GraphicsPipeline.NumRenderTargets = 1;
+ PSODesc.GraphicsPipeline.DSVFormat = TEX_FORMAT_D32_FLOAT;
+ PSODesc.GraphicsPipeline.PrimitiveTopologyType = PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
+ PSODesc.Name = "Asteroids PSO";
+
+ PSODesc.GraphicsPipeline.pVS = vs;
+ PSODesc.GraphicsPipeline.pPS = ps;
+ Uint32 NumSRBs = 0;
+ if(m_BindingMode == BindingMode::Dynamic)
+ {
+ NumSRBs = mNumSubsets;
+ }
+ else if(m_BindingMode == BindingMode::Mutable)
+ {
+ PSODesc.SRBAllocationGranularity = 1024;
+ NumSRBs = NUM_ASTEROIDS;
+ }
+ else if(m_BindingMode == BindingMode::TextureMutable)
+ {
+ PSODesc.SRBAllocationGranularity = NUM_UNIQUE_TEXTURES;
+ NumSRBs = NUM_UNIQUE_TEXTURES;
+ }
+ mDevice->CreatePipelineState(PSODesc, &mAsteroidsPSO);
+ mAsteroidsSRBs.resize(NumSRBs);
+ for(size_t srb = 0; srb < mAsteroidsSRBs.size(); ++srb)
+ {
+ mAsteroidsPSO->CreateShaderResourceBinding(&mAsteroidsSRBs[srb]);
+ }
+ }
+
+
+ // Load textures
+ {
+ TextureLoadInfo loadInfo;
+ loadInfo.IsSRGB = true;
+ RefCntAutoPtr<ITexture> skybox;
+ CreateTextureFromFile("starbox_1024.dds", loadInfo, mDevice, &skybox);
+ mSkyboxSRV = skybox->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE);
+ }
+
+ // Create skybox constant buffer
+ {
+ BufferDesc desc;
+ desc.Name = "skybox constant buffer (dynamic)";
+ desc.Usage = USAGE_DYNAMIC;
+ desc.uiSizeInBytes = sizeof(SkyboxConstantBuffer);
+ desc.BindFlags = BIND_UNIFORM_BUFFER;
+ desc.CPUAccessFlags = CPU_ACCESS_WRITE;
+ mDevice->CreateBuffer(desc, BufferData(), &mSkyboxConstantBuffer);
+ }
+
+ // create skybox pipeline state
+ {
+ LayoutElement inputDesc[] = {
+ LayoutElement( 0, 0, 3, VT_FLOAT32),
+ LayoutElement( 1, 0, 3, VT_FLOAT32)
+ };
+
+ RefCntAutoPtr<IShader> vs, ps;
+ ShaderCreationAttribs attribs;
+ attribs.Desc.DefaultVariableType = SHADER_VARIABLE_TYPE_STATIC;
+ attribs.Desc.ShaderType = SHADER_TYPE_VERTEX;
+ attribs.Desc.Name = "Skybox VS";
+ attribs.EntryPoint = "skybox_vs";
+ attribs.FilePath = "skybox_vs.hlsl";
+ attribs.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL;
+ attribs.pShaderSourceStreamFactory = &BasicSSSFactory;
+ mDevice->CreateShader(attribs, &vs);
+ vs->GetShaderVariable("SkyboxConstantBuffer")->Set(mSkyboxConstantBuffer);
+
+ attribs.Desc.Name = "Skybox PS";
+ attribs.EntryPoint = "skybox_ps";
+ attribs.FilePath = "skybox_ps.hlsl";
+ attribs.Desc.ShaderType = SHADER_TYPE_PIXEL;
+
+ StaticSamplerDesc ssdesc;
+ ssdesc.TextureName = "Skybox";
+ ssdesc.Desc.MagFilter = FILTER_TYPE_ANISOTROPIC;
+ ssdesc.Desc.MinFilter = FILTER_TYPE_ANISOTROPIC;
+ ssdesc.Desc.MipFilter = FILTER_TYPE_ANISOTROPIC;
+ ssdesc.Desc.AddressU = TEXTURE_ADDRESS_WRAP;
+ ssdesc.Desc.AddressV = TEXTURE_ADDRESS_WRAP;
+ ssdesc.Desc.AddressW = TEXTURE_ADDRESS_WRAP;
+ ssdesc.Desc.MaxAnisotropy = TEXTURE_ANISO;
+ attribs.Desc.StaticSamplers = &ssdesc;
+ attribs.Desc.NumStaticSamplers = 1;
+ mDevice->CreateShader(attribs, &ps);
+ ps->GetShaderVariable("Skybox")->Set(mSkyboxSRV);
+
+ PipelineStateDesc PSODesc;
+ PSODesc.Name = "Skybox PSO";
+ PSODesc.GraphicsPipeline.InputLayout.LayoutElements = inputDesc;
+ PSODesc.GraphicsPipeline.InputLayout.NumElements = _countof(inputDesc);
+
+ PSODesc.GraphicsPipeline.DepthStencilDesc.DepthFunc = COMPARISON_FUNC_GREATER_EQUAL;
+ PSODesc.GraphicsPipeline.pVS = vs;
+ PSODesc.GraphicsPipeline.pPS = ps;
+
+ PSODesc.GraphicsPipeline.RTVFormats[0] = TEX_FORMAT_RGBA8_UNORM_SRGB;
+ PSODesc.GraphicsPipeline.NumRenderTargets = 1;
+ PSODesc.GraphicsPipeline.DSVFormat = TEX_FORMAT_D32_FLOAT;
+ PSODesc.GraphicsPipeline.PrimitiveTopologyType = PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
+
+ mDevice->CreatePipelineState(PSODesc, &mSkyboxPSO);
+ }
+
+ // Create sampler
+ {
+ SamplerDesc desc;
+ desc.MagFilter = FILTER_TYPE_ANISOTROPIC;
+ desc.MinFilter = FILTER_TYPE_ANISOTROPIC;
+ desc.MipFilter = FILTER_TYPE_ANISOTROPIC;
+ desc.AddressU = TEXTURE_ADDRESS_WRAP;
+ desc.AddressV = TEXTURE_ADDRESS_WRAP;
+ desc.AddressW = TEXTURE_ADDRESS_WRAP;
+ desc.MinLOD = -D3D11_FLOAT32_MAX;
+ desc.MaxLOD = D3D11_FLOAT32_MAX;
+ desc.MipLODBias = 0.0f;
+ desc.MaxAnisotropy = TEXTURE_ANISO;
+ desc.ComparisonFunc = COMPARISON_FUNC_NEVER;
+ mDevice->CreateSampler(desc, &mSamplerState);
+ }
+
+ CreateGUIResources();
+
+ // Sprites and fonts
+ {
+ PipelineStateDesc PSODesc;
+ LayoutElement inputDesc[] = {
+ LayoutElement( 0, 0, 2, VT_FLOAT32),
+ LayoutElement( 1, 0, 2, VT_FLOAT32)
+ };
+ PSODesc.GraphicsPipeline.InputLayout.LayoutElements = inputDesc;
+ PSODesc.GraphicsPipeline.InputLayout.NumElements = _countof(inputDesc);
+
+ auto &BlendState = PSODesc.GraphicsPipeline.BlendDesc;
+ {
+ // Premultiplied over blend
+ BlendState.RenderTargets[0].BlendEnable = TRUE;
+ BlendState.RenderTargets[0].SrcBlend = BLEND_FACTOR_ONE;
+ BlendState.RenderTargets[0].BlendOp = BLEND_OPERATION_ADD;
+ BlendState.RenderTargets[0].DestBlend = BLEND_FACTOR_INV_SRC_ALPHA;
+ }
+
+ PSODesc.GraphicsPipeline.DepthStencilDesc.DepthEnable = false;
+
+ PSODesc.GraphicsPipeline.RTVFormats[0] = TEX_FORMAT_RGBA8_UNORM_SRGB;
+ PSODesc.GraphicsPipeline.NumRenderTargets = 1;
+ PSODesc.GraphicsPipeline.DSVFormat = TEX_FORMAT_D32_FLOAT;
+ PSODesc.GraphicsPipeline.PrimitiveTopologyType = PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
+
+ RefCntAutoPtr<IShader> sprite_vs, sprite_ps, font_ps;
+ {
+ ShaderCreationAttribs attribs;
+ attribs.Desc.DefaultVariableType = SHADER_VARIABLE_TYPE_STATIC;
+ attribs.Desc.ShaderType = SHADER_TYPE_VERTEX;
+ attribs.Desc.Name = "Sprite VS";
+ attribs.EntryPoint = "sprite_vs";
+ attribs.FilePath = "sprite_vs.hlsl";
+ attribs.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL;
+ attribs.pShaderSourceStreamFactory = &BasicSSSFactory;
+ mDevice->CreateShader(attribs, &sprite_vs);
+ }
+
+ {
+ ShaderCreationAttribs attribs;
+ attribs.Desc.DefaultVariableType = SHADER_VARIABLE_TYPE_DYNAMIC;
+ attribs.Desc.ShaderType = SHADER_TYPE_PIXEL;
+ attribs.Desc.Name = "Sprite PS";
+ attribs.EntryPoint = "sprite_ps";
+ attribs.FilePath = "sprite_ps.hlsl";
+ attribs.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL;
+ attribs.pShaderSourceStreamFactory = &BasicSSSFactory;
+ mDevice->CreateShader(attribs, &sprite_ps);
+ }
+
+ {
+ ShaderCreationAttribs attribs;
+ attribs.Desc.DefaultVariableType = SHADER_VARIABLE_TYPE_STATIC;
+ attribs.Desc.ShaderType = SHADER_TYPE_PIXEL;
+ attribs.Desc.Name = "Font PS";
+ attribs.EntryPoint = "font_ps";
+ attribs.FilePath = "font_ps.hlsl";
+ attribs.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL;
+ attribs.pShaderSourceStreamFactory = &BasicSSSFactory;
+ mDevice->CreateShader(attribs, &font_ps);
+ font_ps->GetShaderVariable("Tex")->Set(mFontTextureSRV);
+ }
+
+ PSODesc.Name = "Sprite PSO";
+ PSODesc.GraphicsPipeline.pVS = sprite_vs;
+ PSODesc.GraphicsPipeline.pPS = sprite_ps;
+ mDevice->CreatePipelineState(PSODesc, &mSpritePSO);
+ mSpritePSO->CreateShaderResourceBinding(&mSpriteSRB);
+
+ PSODesc.Name = "Font PSO";
+ PSODesc.GraphicsPipeline.pPS = font_ps;
+ mDevice->CreatePipelineState(PSODesc, &mFontPSO);
+ }
+
+
+ CreateMeshes();
+ InitializeTextureData();
+ if( m_BindingMode == BindingMode::Mutable )
+ {
+ for(size_t srb = 0; srb < NUM_ASTEROIDS; ++srb)
+ {
+ auto staticData = &mAsteroids->StaticData()[srb];
+ mAsteroidsSRBs[srb]->GetVariable(SHADER_TYPE_PIXEL, "Tex")->Set(mTextureSRVs[staticData->textureIndex]);
+ }
+ }
+ else if( m_BindingMode == BindingMode::TextureMutable )
+ {
+ for(size_t srb = 0; srb < NUM_UNIQUE_TEXTURES; ++srb)
+ {
+ mAsteroidsSRBs[srb]->GetVariable(SHADER_TYPE_PIXEL, "Tex")->Set(mTextureSRVs[srb]);
+ }
+ }
+
+}
+
+Asteroids::~Asteroids()
+{
+ {
+ std::unique_lock<std::mutex> lk(mMutex);
+ mExitThreads = true;
+ }
+ mCondVar.notify_all();
+
+ for(auto &thread : mWorkerThreads)
+ {
+ thread.join();
+ }
+}
+
+
+
+void Asteroids::ResizeSwapChain(HWND outputWindow, unsigned int width, unsigned int height)
+{
+ mSwapChain->Resize(width, height);
+ mBackBufferWidth = width;
+ mBackBufferHeight = height;
+}
+
+
+void Asteroids::CreateMeshes()
+{
+ auto asteroidMeshes = mAsteroids->Meshes();
+
+ // create vertex buffer
+ {
+ BufferDesc desc;
+ desc.Name = "Asteroid Meshes Vertex Buffer";
+ desc.uiSizeInBytes = (Uint32)asteroidMeshes->vertices.size() * sizeof(asteroidMeshes->vertices[0]);
+ desc.BindFlags = BIND_VERTEX_BUFFER;
+ desc.Usage = USAGE_DEFAULT;
+
+ BufferData data;
+ data.pData = asteroidMeshes->vertices.data();
+ data.DataSize = desc.uiSizeInBytes;
+
+ mDevice->CreateBuffer(desc, data, &mVertexBuffer);
+ }
+
+ // create index buffer
+ {
+ BufferDesc desc;
+ desc.Name = "Asteroid Meshes Index Buffer";
+ desc.uiSizeInBytes = (Uint32)asteroidMeshes->indices.size() * sizeof(asteroidMeshes->indices[0]);
+ desc.BindFlags = BIND_INDEX_BUFFER;
+ desc.Usage = USAGE_DEFAULT;
+
+ BufferData data;
+ data.pData = asteroidMeshes->indices.data();
+ data.DataSize = desc.uiSizeInBytes;
+
+ mDevice->CreateBuffer(desc, data, &mIndexBuffer);
+ }
+
+ std::vector<SkyboxVertex> skyboxVertices;
+ CreateSkyboxMesh(&skyboxVertices);
+
+
+ // create skybox vertex buffer
+ {
+ BufferDesc desc;
+ desc.Name = "Skybox Vertex Buffer";
+ desc.uiSizeInBytes = (Uint32)skyboxVertices.size() * sizeof(skyboxVertices[0]);
+ desc.BindFlags = BIND_VERTEX_BUFFER;
+ desc.Usage = USAGE_DEFAULT;
+
+ BufferData data;
+ data.pData = skyboxVertices.data();
+ data.DataSize = desc.uiSizeInBytes;
+
+ mDevice->CreateBuffer(desc, data, &mSkyboxVertexBuffer);
+ }
+
+ // create sprite vertex buffer (dynamic)
+ {
+ BufferDesc desc;
+ desc.Name = "sprite vertex buffer (dynamic)";
+ desc.uiSizeInBytes = (Uint32)MAX_SPRITE_VERTICES_PER_FRAME * sizeof(SpriteVertex);
+ desc.BindFlags = BIND_VERTEX_BUFFER;
+ desc.Usage = USAGE_DYNAMIC;
+ desc.CPUAccessFlags = CPU_ACCESS_WRITE;
+
+ mDevice->CreateBuffer(desc, BufferData(), &mSpriteVertexBuffer);
+ }
+}
+
+void Asteroids::InitializeTextureData()
+{
+ TextureDesc textureDesc;
+ textureDesc.Type = RESOURCE_DIM_TEX_2D_ARRAY;
+ textureDesc.Width = TEXTURE_DIM;
+ textureDesc.Height = TEXTURE_DIM;
+ textureDesc.ArraySize = 3;
+ textureDesc.MipLevels = 0; // Full chain
+ textureDesc.Format = TEX_FORMAT_RGBA8_UNORM_SRGB;
+ textureDesc.SampleCount = 1;
+ textureDesc.Usage = USAGE_DEFAULT;
+ textureDesc.BindFlags = BIND_SHADER_RESOURCE;
+
+ for (UINT t = 0; t < NUM_UNIQUE_TEXTURES; ++t) {
+ std::vector<TextureSubResData> subResData(textureDesc.ArraySize*mAsteroids->GetTextureMipLevels());
+ auto *texData = mAsteroids->TextureData(t);
+ for(size_t subRes=0; subRes < subResData.size(); ++subRes)
+ {
+ subResData[subRes].pData = texData[subRes].pSysMem;
+ subResData[subRes].Stride = texData[subRes].SysMemPitch;
+ subResData[subRes].DepthStride = texData[subRes].SysMemSlicePitch;
+ }
+ TextureData initData;
+ initData.NumSubresources = (Uint32)subResData.size();
+ initData.pSubResources = subResData.data();
+ mDevice->CreateTexture(textureDesc, initData, &mTextures[t]);
+ mTextureSRVs[t] = mTextures[t]->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE);
+ mTextureSRVs[t]->SetSampler(mSamplerState);
+ }
+}
+
+void Asteroids::CreateGUIResources()
+{
+ auto font = mGUI->Font();
+ TextureDesc textureDesc;
+ textureDesc.Type = RESOURCE_DIM_TEX_2D;
+ textureDesc.Format = TEX_FORMAT_R8_UNORM;
+ textureDesc.Width = font->BitmapWidth();
+ textureDesc.Height = font->BitmapHeight();
+ textureDesc.MipLevels = 1;
+ textureDesc.ArraySize = 1;
+ textureDesc.BindFlags = BIND_SHADER_RESOURCE;
+ textureDesc.Usage = USAGE_DEFAULT;
+
+ TextureData initialData;
+ TextureSubResData subresources[] = {
+ TextureSubResData((void*)font->Pixels(), font->BitmapWidth())
+ };
+ initialData.pSubResources = subresources;
+ initialData.NumSubresources = _countof(subresources);
+
+ RefCntAutoPtr<ITexture> texture;
+ mDevice->CreateTexture(textureDesc, initialData, &texture);
+ mFontTextureSRV = texture->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE);
+ mFontTextureSRV->SetSampler(mSamplerState);
+
+ // Load any GUI sprite textures
+ for (int i = -1; i < (int)mGUI->size(); ++i) {
+ auto control = i >= 0 ? (*mGUI)[i] : mSprite.get();
+ if (control->TextureFile().length() > 0 && mSpriteTextures.find(control->TextureFile()) == mSpriteTextures.end()) {
+ std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
+ ID3D11ShaderResourceView* textureSRV = nullptr;
+ auto path = NarrowString(converter.from_bytes(control->TextureFile()).c_str());
+ TextureLoadInfo loadInfo;
+ loadInfo.IsSRGB = true;
+ RefCntAutoPtr<ITexture> spriteTexture;
+ CreateTextureFromFile(path.c_str(), loadInfo, mDevice, &spriteTexture);
+ auto *pSRV = spriteTexture->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE);
+ pSRV->SetSampler(mSamplerState);
+ mSpriteTextures[control->TextureFile()] = pSRV;
+ }
+ }
+}
+
+static_assert(sizeof(IndexType) == 2, "Expecting 16-bit index buffer");
+
+void Asteroids::WorkerThreadFunc(Asteroids *pThis, Diligent::Uint32 ThreadNum)
+{
+ for (;;)
+ {
+ // Wait for mUpdateSubsets or mExitThreads flag on conditional variable
+ {
+ std::unique_lock<std::mutex> lk(pThis->mMutex);
+ pThis->mCondVar.wait(lk, [&]{return pThis->mUpdateSubsets || pThis->mExitThreads;});
+ }
+
+ if(pThis->mExitThreads)
+ return;
+
+ auto SubsetSize = NUM_ASTEROIDS / pThis->mNumSubsets;
+ auto SubsetStart = SubsetSize * (ThreadNum+1);
+ auto &FrameAttribs = pThis->mFrameAttribs;
+
+ pThis->mAsteroids->Update(FrameAttribs.frameTime, FrameAttribs.camera->Eye(), *FrameAttribs.settings, SubsetStart, SubsetSize);
+
+ // Increment number of completed threads
+ ++pThis->m_NumThreadsCompleted;
+
+ // Wait for mRenderSubsets flag on conditional variable
+ {
+ std::unique_lock<std::mutex> lk(pThis->mMutex);
+ pThis->mCondVar.wait(lk, [&]{return pThis->mRenderSubsets || pThis->mExitThreads;});
+ }
+
+ pThis->RenderSubset(1+ThreadNum, pThis->mDeferredCtxt[ThreadNum], *FrameAttribs.camera, SubsetStart, SubsetSize);
+
+ RefCntAutoPtr<ICommandList> pCmdList;
+ pThis->mCmdLists[ThreadNum].Release();
+ pThis->mDeferredCtxt[ThreadNum]->FinishCommandList(&pThis->mCmdLists[ThreadNum]);
+
+ // Increment number of completed threads
+ ++pThis->m_NumThreadsCompleted;
+ }
+
+}
+
+void Asteroids::RenderSubset(Diligent::Uint32 SubsetNum,
+ IDeviceContext *pCtx,
+ const OrbitCamera& camera,
+ Uint32 startIdx,
+ Uint32 numAsteroids)
+{
+ pCtx->SetRenderTargets(0, nullptr, nullptr);
+
+ // Frame data
+ auto staticAsteroidData = mAsteroids->StaticData();
+ auto dynamicAsteroidData = mAsteroids->DynamicData();
+
+ pCtx->SetPipelineState(mAsteroidsPSO);
+
+ {
+ IBuffer* ia_buffers[] = { mVertexBuffer };
+ Uint32 ia_strides[] = { sizeof(Vertex) };
+ Uint32 ia_offsets[] = { 0 };
+ pCtx->SetVertexBuffers(0, 1, ia_buffers, ia_strides, ia_offsets, 0);
+ pCtx->SetIndexBuffer(mIndexBuffer, 0);
+ }
+
+ auto pVar = m_BindingMode == BindingMode::Dynamic ? mAsteroidsSRBs[SubsetNum]->GetVariable(SHADER_TYPE_PIXEL, "Tex") : nullptr;
+ auto viewProjection = camera.ViewProjection();
+ for (UINT drawIdx = startIdx; drawIdx < startIdx+numAsteroids; ++drawIdx)
+ {
+ auto staticData = &staticAsteroidData[drawIdx];
+ auto dynamicData = &dynamicAsteroidData[drawIdx];
+
+ {
+ MapHelper<DrawConstantBuffer> drawConstants(pCtx, mDrawConstantBuffer, MAP_WRITE_DISCARD, 0);
+ XMStoreFloat4x4(&drawConstants->mWorld, dynamicData->world);
+ XMStoreFloat4x4(&drawConstants->mViewProjection, viewProjection);
+ drawConstants->mSurfaceColor = staticData->surfaceColor;
+ drawConstants->mDeepColor = staticData->deepColor;
+ }
+ if( m_BindingMode == BindingMode::Dynamic )
+ {
+ pVar->Set(mTextureSRVs[staticData->textureIndex]);
+ pCtx->CommitShaderResources(mAsteroidsSRBs[SubsetNum], COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES);
+ }
+ else if( m_BindingMode == BindingMode::Mutable )
+ {
+ pCtx->CommitShaderResources(mAsteroidsSRBs[drawIdx], COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES);
+ }
+ else if( m_BindingMode == BindingMode::TextureMutable )
+ {
+ pCtx->CommitShaderResources(mAsteroidsSRBs[staticData->textureIndex], 0);
+ }
+
+ DrawAttribs attribs;
+ attribs.Topology = PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+ attribs.IsIndexed = true;
+ attribs.NumIndices = dynamicData->indexCount;
+ attribs.IndexType = VT_UINT16;
+ attribs.FirstIndexLocation = dynamicData->indexStart;
+ attribs.BaseVertex = staticData->vertexStart;
+ pCtx->Draw(attribs);
+ }
+}
+
+void Asteroids::Render(float frameTime, const OrbitCamera& camera, const Settings& settings)
+{
+ mFrameAttribs.frameTime = frameTime;
+ mFrameAttribs.camera = &camera;
+ mFrameAttribs.settings = &settings;
+
+ // Clear the render target
+ float clearcol[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ mDeviceCtxt->SetRenderTargets(0, nullptr, nullptr);
+ mDeviceCtxt->ClearRenderTarget(nullptr, clearcol);
+ mDeviceCtxt->ClearDepthStencil(nullptr, CLEAR_DEPTH_FLAG, 0.0f, 0);
+
+ if( m_BindingMode == BindingMode::TextureMutable )
+ {
+ for(auto &srb=mAsteroidsSRBs.begin(); srb!=mAsteroidsSRBs.end(); ++srb)
+ {
+ mDeviceCtxt->TransitionShaderResources(mAsteroidsPSO, *srb);
+ }
+ }
+
+ LONG64 currCounter;
+ QueryPerformanceCounter((LARGE_INTEGER*)&currCounter);
+ mUpdateTicks = currCounter;
+
+ auto SubsetSize = NUM_ASTEROIDS / (settings.multithreadedRendering ? mNumSubsets : 1);
+
+ if (settings.multithreadedRendering)
+ {
+ // Set mUpdateSubsets flag
+ {
+ std::unique_lock<std::mutex> lk(mMutex);
+ mUpdateSubsets = true;
+ m_NumThreadsCompleted = 0;
+ }
+ mCondVar.notify_all();
+ }
+
+ mAsteroids->Update(frameTime, camera.Eye(), settings, 0, SubsetSize);
+
+ if (settings.multithreadedRendering)
+ {
+ // Wait for worker threads to finish
+ while(m_NumThreadsCompleted < (int)mNumSubsets-1)
+ std::this_thread::yield();
+ // Clear mUpdateSubsets flag while all threads are waiting for mRenderSubsets flag
+ mUpdateSubsets = false;
+ }
+
+
+ QueryPerformanceCounter((LARGE_INTEGER*)&currCounter);
+ mUpdateTicks = currCounter-mUpdateTicks;
+
+ mRenderTicks = currCounter;
+
+ if (settings.multithreadedRendering)
+ {
+ // Set mRenderSubsets flag
+ {
+ std::unique_lock<std::mutex> lk(mMutex);
+ mRenderSubsets = true;
+ m_NumThreadsCompleted = 0;
+ }
+ mCondVar.notify_all();
+ }
+
+ RenderSubset(0, mDeviceCtxt, camera, 0, SubsetSize);
+
+ if (settings.multithreadedRendering)
+ {
+ // Wait for worker threads to finish
+ while(m_NumThreadsCompleted < (int)mNumSubsets-1)
+ std::this_thread::yield();
+ // Clear mRenderSubsets flag while all threads are waiting for mUpdateSubsets flag
+ mRenderSubsets = false;
+
+ for(auto &cmdList : mCmdLists)
+ {
+ mDeviceCtxt->ExecuteCommandList(cmdList);
+ }
+ }
+
+ QueryPerformanceCounter((LARGE_INTEGER*)&currCounter);
+ mRenderTicks = currCounter-mRenderTicks;
+
+ mDeviceCtxt->SetRenderTargets(0, nullptr, nullptr);
+ // Draw skybox
+ {
+ {
+ MapHelper<SkyboxConstantBuffer> skyboxConstants(mDeviceCtxt, mSkyboxConstantBuffer, MAP_WRITE_DISCARD, 0);
+ XMStoreFloat4x4(&skyboxConstants->mViewProjection, camera.ViewProjection());
+ }
+
+ IBuffer* ia_buffers[] = { mSkyboxVertexBuffer };
+ UINT ia_strides[] = { sizeof(SkyboxVertex) };
+ UINT ia_offsets[] = { 0 };
+ mDeviceCtxt->SetVertexBuffers(0, 1, ia_buffers, ia_strides, ia_offsets, 0);
+
+ mDeviceCtxt->SetPipelineState(mSkyboxPSO);
+ mDeviceCtxt->CommitShaderResources(nullptr, COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES);
+
+ DrawAttribs DrawAttrs;
+ DrawAttrs.Topology = PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+ DrawAttrs.NumVertices = 6*6;
+ mDeviceCtxt->Draw(DrawAttrs);
+ }
+
+ // Draw sprites and fonts
+ {
+ // Fill in vertices (TODO: could move this vector to be a member - not a big deal)
+ std::vector<UINT> controlVertices;
+ controlVertices.reserve(mGUI->size());
+
+ {
+ MapHelper<SpriteVertex> vertexBase(mDeviceCtxt, mSpriteVertexBuffer, MAP_WRITE_DISCARD, 0);
+ auto vertexEnd = (SpriteVertex*)vertexBase;
+
+ for (int i = -1; i < (int)mGUI->size(); ++i) {
+ auto control = i >= 0 ? (*mGUI)[i] : mSprite.get();
+ controlVertices.push_back((UINT)(control->Draw((float)mBackBufferWidth, (float)mBackBufferHeight, vertexEnd) - vertexEnd));
+ vertexEnd += controlVertices.back();
+ }
+ }
+
+ IBuffer* ia_buffers[] = { mSpriteVertexBuffer };
+ Uint32 ia_strides[] = { sizeof(SpriteVertex) };
+ Uint32 ia_offsets[] = { 0 };
+ mDeviceCtxt->SetVertexBuffers(0, 1, ia_buffers, ia_strides, ia_offsets, 0);
+
+ // Draw
+ UINT vertexStart = 0;
+ for (int i = -1; i < (int)mGUI->size(); ++i) {
+ auto control = i >= 0 ? (*mGUI)[i] : mSprite.get();
+ if (control->Visible()) {
+ if (control->TextureFile().length() == 0) { // Font
+ mDeviceCtxt->SetPipelineState(mFontPSO);
+ mDeviceCtxt->CommitShaderResources(nullptr, COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES);
+ } else { // Sprite
+ auto textureSRV = mSpriteTextures[control->TextureFile()];
+ mDeviceCtxt->SetPipelineState(mSpritePSO);
+ mSpriteSRB->GetVariable(SHADER_TYPE_PIXEL, "Tex")->Set(textureSRV);
+ mDeviceCtxt->CommitShaderResources(mSpriteSRB, COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES);
+ }
+ DrawAttribs DrawAttrs;
+ DrawAttrs.Topology = PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+ DrawAttrs.NumVertices = controlVertices[1+i];
+ DrawAttrs.StartVertexLocation = vertexStart;
+ mDeviceCtxt->Draw(DrawAttrs);
+ }
+ vertexStart += controlVertices[1+i];
+ }
+ }
+
+ mSwapChain->Present();//settings.vsync ? 1 : 0, 0);
+}
+
+void Asteroids::GetPerfCounters(float &UpdateTime, float &RenderTime)
+{
+ UpdateTime = (float)mUpdateTicks/(float)mPerfCounterFreq;
+ RenderTime = (float)mRenderTicks/(float)mPerfCounterFreq;
+}
+
+} // namespace AsteroidsDE