diff --git a/WickedEngine/WickedEngineEditor.exe b/WickedEngine/WickedEngineEditor.exe index 7cf0f619b..529b00c2b 100644 Binary files a/WickedEngine/WickedEngineEditor.exe and b/WickedEngine/WickedEngineEditor.exe differ diff --git a/WickedEngine/startup.lua b/WickedEngine/startup.lua index c6bddb2fd..0a3a5552f 100644 --- a/WickedEngine/startup.lua +++ b/WickedEngine/startup.lua @@ -44,6 +44,10 @@ runProcess(function() if(input.Press(VK_F6)) then main.GetActiveComponent().SetPreferredThreadingCount(4); end + + if(input.Press(VK_F7)) then + LoadModel("C:\\PROJECTS\\WickedEngine\\WickedEngine\\Scene\\Sample\\","scene"); + end update() end diff --git a/WickedEngine/wiGraphicsDevice.h b/WickedEngine/wiGraphicsDevice.h index 10f6e81c1..8b49401d3 100644 --- a/WickedEngine/wiGraphicsDevice.h +++ b/WickedEngine/wiGraphicsDevice.h @@ -42,7 +42,8 @@ namespace wiGraphicsTypes virtual HRESULT CreateDepthStencilState(const DepthStencilStateDesc *pDepthStencilStateDesc, DepthStencilState *pDepthStencilState) = 0; virtual HRESULT CreateRasterizerState(const RasterizerStateDesc *pRasterizerStateDesc, RasterizerState *pRasterizerState) = 0; virtual HRESULT CreateSamplerState(const SamplerDesc *pSamplerDesc, Sampler *pSamplerState) = 0; - virtual HRESULT CreateQuery(const GPUQueryDesc *pDesc, GPUQuery *pQuery) = 0; + // async: don't flush GPU pipeline when performing query, but introduce latency of two frames + virtual HRESULT CreateQuery(const GPUQueryDesc *pDesc, GPUQuery *pQuery, bool async = true) = 0; virtual void PresentBegin() = 0; virtual void PresentEnd() = 0; diff --git a/WickedEngine/wiGraphicsDevice_DX11.cpp b/WickedEngine/wiGraphicsDevice_DX11.cpp index 1f0496ae8..a0149ebf4 100644 --- a/WickedEngine/wiGraphicsDevice_DX11.cpp +++ b/WickedEngine/wiGraphicsDevice_DX11.cpp @@ -1308,6 +1308,11 @@ inline Texture2DDesc _ConvertTexture2DDesc_Inv(const D3D11_TEXTURE2D_DESC* pDesc } +// Local Helpers: +const void* const __nullBlob[1024] = { 0 }; // this is initialized to nullptrs! +#define REQUESTQUERYID ((GetFrameCount() + GPUQuery::ASYNC_LATENCY - 1) % GPUQuery::ASYNC_LATENCY) +#define READQUERYID ((GetFrameCount()) % GPUQuery::ASYNC_LATENCY) + // Engine functions @@ -1335,11 +1340,7 @@ GraphicsDevice_DX11::GraphicsDevice_DX11(wiWindowRegistration::window_type windo } UINT createDeviceFlags = 0; -#ifdef _DEBUG -#ifndef WINSTORE_SUPPORT createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; -#endif -#endif D3D_DRIVER_TYPE driverTypes[] = { @@ -1532,7 +1533,7 @@ HRESULT GraphicsDevice_DX11::CreateBuffer(const GPUBufferDesc *pDesc, const Subr ppBuffer->desc = *pDesc; HRESULT hr = device->CreateBuffer(&desc, data, &ppBuffer->resource_DX11); - assert(SUCCEEDED(hr) && "GPUBuffer Creation failed!"); + assert(SUCCEEDED(hr) && "GPUBuffer creation failed!"); if (SUCCEEDED(hr)) { @@ -1627,7 +1628,7 @@ HRESULT GraphicsDevice_DX11::CreateTexture2D(const Texture2DDesc* pDesc, const S HRESULT hr = S_OK; hr = device->CreateTexture2D(&desc, data, &((*ppTexture2D)->texture2D_DX11)); - assert(SUCCEEDED(hr) && "Texture2D creating failed!"); + assert(SUCCEEDED(hr) && "Texture2D creation failed!"); if (FAILED(hr)) return hr; @@ -2168,9 +2169,10 @@ HRESULT GraphicsDevice_DX11::CreateSamplerState(const SamplerDesc *pSamplerDesc, pSamplerState->desc = *pSamplerDesc; return device->CreateSamplerState(&desc, &pSamplerState->resource_DX11); } -HRESULT GraphicsDevice_DX11::CreateQuery(const GPUQueryDesc *pDesc, GPUQuery *pQuery) +HRESULT GraphicsDevice_DX11::CreateQuery(const GPUQueryDesc *pDesc, GPUQuery *pQuery, bool async) { pQuery->desc = *pDesc; + pQuery->async = async; D3D11_QUERY_DESC desc; desc.MiscFlags = 0; @@ -2179,7 +2181,23 @@ HRESULT GraphicsDevice_DX11::CreateQuery(const GPUQueryDesc *pDesc, GPUQuery *pQ { desc.Query = D3D11_QUERY_OCCLUSION; } - return device->CreateQuery(&desc, &pQuery->resource_DX11); + + HRESULT hr = E_FAIL; + if (async) + { + for (int i = 0; i < GPUQuery::ASYNC_LATENCY; ++i) + { + hr = device->CreateQuery(&desc, &pQuery->resource_DX11[i]); + assert(SUCCEEDED(hr) && "GPUQuery creation failed!"); + } + } + else + { + hr = device->CreateQuery(&desc, &pQuery->resource_DX11[0]); + assert(SUCCEEDED(hr) && "GPUQuery creation failed!"); + } + + return hr; } @@ -2308,7 +2326,6 @@ void GraphicsDevice_DX11::BindUnorderedAccessResourceCS(const GPUUnorderedResour if (resource != nullptr) deviceContexts[threadID]->CSSetUnorderedAccessViews(slot, 1, &resource->unorderedAccessView_DX11, nullptr); } -const void* const __nullBlob[1024] = { 0 }; // this is initialized to nullptrs! void GraphicsDevice_DX11::UnBindResources(int slot, int num, GRAPHICSTHREAD threadID) { assert(num <= ARRAYSIZE(__nullBlob) && "Extend nullBlob to support more resource unbinding!"); @@ -2599,31 +2616,46 @@ void GraphicsDevice_DX11::SetScissorRects(UINT numRects, const Rect* rects, GRAP deviceContexts[threadID]->RSSetScissorRects(numRects, nullptr); } } + void GraphicsDevice_DX11::QueryBegin(GPUQuery *query, GRAPHICSTHREAD threadID) { - //query->result_passed = FALSE; - //query->result_passed_sample_count = 0; - deviceContexts[threadID]->Begin(query->resource_DX11); + const int _requestQueryID = (query->async ? REQUESTQUERYID : 0); + deviceContexts[threadID]->Begin(query->resource_DX11[_requestQueryID]); + query->active[_requestQueryID] = true; } void GraphicsDevice_DX11::QueryEnd(GPUQuery *query, GRAPHICSTHREAD threadID) { - deviceContexts[threadID]->End(query->resource_DX11); + const int _requestQueryID = (query->async ? REQUESTQUERYID : 0); + deviceContexts[threadID]->End(query->resource_DX11[_requestQueryID]); + query->active[_requestQueryID] = true; } bool GraphicsDevice_DX11::QueryRead(GPUQuery *query, GRAPHICSTHREAD threadID) { + const int _readQueryID = (query->async ? READQUERYID : 0); + const UINT _flags = (query->async ? D3D11_ASYNC_GETDATA_DONOTFLUSH : 0); + + if (!query->active[_readQueryID]) + { + return true; + } + assert(threadID == GRAPHICSTHREAD_IMMEDIATE && "A query can only be read on the immediate graphics thread!"); + HRESULT hr = S_OK; switch (query->desc.Type) { case GPU_QUERY_TYPE_OCCLUSION: - hr = deviceContexts[threadID]->GetData(query->resource_DX11, &query->result_passed_sample_count, sizeof(query->result_passed_sample_count), 0/*D3D11_ASYNC_GETDATA_DONOTFLUSH*/); + hr = deviceContexts[threadID]->GetData(query->resource_DX11[_readQueryID], &query->result_passed_sample_count, sizeof(query->result_passed_sample_count), _flags); query->result_passed = query->result_passed_sample_count != 0; break; case GPU_QUERY_TYPE_OCCLUSION_PREDICATE: default: - hr = deviceContexts[threadID]->GetData(query->resource_DX11, &query->result_passed, sizeof(query->result_passed), 0/*D3D11_ASYNC_GETDATA_DONOTFLUSH*/); + hr = deviceContexts[threadID]->GetData(query->resource_DX11[_readQueryID], &query->result_passed, sizeof(query->result_passed), _flags); break; } + + query->active[_readQueryID] = false; + return SUCCEEDED(hr); } diff --git a/WickedEngine/wiGraphicsDevice_DX11.h b/WickedEngine/wiGraphicsDevice_DX11.h index 2f05bca97..4cfc89a11 100644 --- a/WickedEngine/wiGraphicsDevice_DX11.h +++ b/WickedEngine/wiGraphicsDevice_DX11.h @@ -58,7 +58,7 @@ namespace wiGraphicsTypes virtual HRESULT CreateDepthStencilState(const DepthStencilStateDesc *pDepthStencilStateDesc, DepthStencilState *pDepthStencilState) override; virtual HRESULT CreateRasterizerState(const RasterizerStateDesc *pRasterizerStateDesc, RasterizerState *pRasterizerState) override; virtual HRESULT CreateSamplerState(const SamplerDesc *pSamplerDesc, Sampler *pSamplerState) override; - virtual HRESULT CreateQuery(const GPUQueryDesc *pDesc, GPUQuery *pQuery) override; + virtual HRESULT CreateQuery(const GPUQueryDesc *pDesc, GPUQuery *pQuery, bool async = true) override; virtual void PresentBegin() override; virtual void PresentEnd() override; diff --git a/WickedEngine/wiGraphicsResource.cpp b/WickedEngine/wiGraphicsResource.cpp index ccbc48488..beb456f13 100644 --- a/WickedEngine/wiGraphicsResource.cpp +++ b/WickedEngine/wiGraphicsResource.cpp @@ -193,10 +193,18 @@ namespace wiGraphicsTypes GPUQuery::GPUQuery() { - SAFE_INIT(resource_DX11); + for (int i = 0; i < ASYNC_LATENCY; ++i) + { + SAFE_INIT(resource_DX11[i]); + active[i] = false; + } + async = false; } GPUQuery::~GPUQuery() { - SAFE_RELEASE(resource_DX11); + for (int i = 0; i < ASYNC_LATENCY; ++i) + { + SAFE_RELEASE(resource_DX11[i]); + } } } diff --git a/WickedEngine/wiGraphicsResource.h b/WickedEngine/wiGraphicsResource.h index 7680f9d9e..1225d7769 100644 --- a/WickedEngine/wiGraphicsResource.h +++ b/WickedEngine/wiGraphicsResource.h @@ -264,17 +264,22 @@ namespace wiGraphicsTypes class GPUQuery { friend class GraphicsDevice_DX11; + public: + static const int ASYNC_LATENCY = 4; private: - ID3D11Query* resource_DX11; + ID3D11Query* resource_DX11[ASYNC_LATENCY]; GPUQueryDesc desc; - bool active; + bool active[ASYNC_LATENCY]; + + // async: shift query frames to avoid pipeline stalls from waiting for the GPU: + // we always request queries for some frames forward in time (QueryBegin, QueryEnd) + // so we always read the query which occured some frames behind because of that (QueryRead) + bool async; public: GPUQuery(); virtual ~GPUQuery(); - bool IsValid() { return resource_DX11 != nullptr; } - bool IsActive() { return active; } - void SetActive(bool value) { active = value; } + bool IsValid() { return resource_DX11[0] != nullptr; } GPUQueryDesc GetDesc() { return desc; } BOOL result_passed; diff --git a/WickedEngine/wiLoader.cpp b/WickedEngine/wiLoader.cpp index 46d71c069..30717e7fe 100644 --- a/WickedEngine/wiLoader.cpp +++ b/WickedEngine/wiLoader.cpp @@ -3677,11 +3677,8 @@ Object::Object(const string& name) :Transform() GPUQueryDesc desc; desc.Type = GPU_QUERY_TYPE_OCCLUSION_PREDICATE; desc.MiscFlags = 0; - for (int i = 0; i < ARRAYSIZE(occlusionQueries); ++i) - { - wiRenderer::GetDevice()->CreateQuery(&desc, &occlusionQueries[i]); - occlusionQueries[i].result_passed = TRUE; - } + wiRenderer::GetDevice()->CreateQuery(&desc, &occlusionQuery, true); + occlusionQuery.result_passed = TRUE; } Object::~Object() { } diff --git a/WickedEngine/wiLoader.h b/WickedEngine/wiLoader.h index 620c67208..7d5936934 100644 --- a/WickedEngine/wiLoader.h +++ b/WickedEngine/wiLoader.h @@ -443,8 +443,9 @@ struct Object : public Streamable, public Transform int physicsObjectI; - // occlusion results for the previous 3 frames - wiGraphicsTypes::GPUQuery occlusionQueries[3]; + // occlusion result + wiGraphicsTypes::GPUQuery occlusionQuery; + bool skipOcclusionQuery; // Is it deformed with an armature? bool isArmatureDeformed() const @@ -477,6 +478,7 @@ struct Object : public Streamable, public Transform color = XMFLOAT3(1, 1, 1); trailDistortTex = nullptr; trailTex = nullptr; + skipOcclusionQuery; } void EmitTrail(const XMFLOAT3& color, float fadeSpeed = 0.06f); void FadeTrail(); diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index c88096ddf..d6fb9f818 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -87,6 +87,7 @@ wiWaterPlane wiRenderer::waterPlane; #pragma endregion + wiRenderer::wiRenderer() { } @@ -110,11 +111,11 @@ void wiRenderer::Present(function drawToScreen1,function drawToS if(drawToScreen3!=nullptr) drawToScreen3(); - wiFrameRate::Frame(); - GetDevice()->PresentEnd(); *prevFrameCam = *cam; + + wiFrameRate::Frame(); } @@ -1389,6 +1390,7 @@ void wiRenderer::UpdatePerFrameData() FrameCulling& culling = x.second; culling.culledRenderer.clear(); + culling.culledRenderer_opaque.clear(); culling.culledRenderer_transparent.clear(); culling.culledHairParticleSystems.clear(); culling.culledLights.clear(); @@ -1404,6 +1406,7 @@ void wiRenderer::UpdatePerFrameData() for (Cullable* x : culledObjects) { Object* object = (Object*)x; + culling.culledRenderer[object->mesh].push_front(object); for (wiHairParticle* hair : object->hParticleSystems) { culling.culledHairParticleSystems.push_back(hair); @@ -1411,7 +1414,7 @@ void wiRenderer::UpdatePerFrameData() } if (object->GetRenderTypes() & RENDERTYPE_OPAQUE) { - culling.culledRenderer[object->mesh].push_front(object); + culling.culledRenderer_opaque[object->mesh].push_front(object); } if (!foundClosestReflector && camera == getCamera() && object->IsReflector()) { @@ -1733,15 +1736,15 @@ void wiRenderer::OcclusionCulling_Render(GRAPHICSTHREAD threadID) MiscCB cb; for (Object* instance : visibleInstances) { - GPUQuery& query = instance->occlusionQueries[0]; + GPUQuery& query = instance->occlusionQuery; if (instance->bounds.intersects(getCamera()->translation)) { // if the camera is inside the bounding box, then the object is most likely visible, so skip occlusion query query.result_passed = true; - query.SetActive(false); + instance->skipOcclusionQuery = true; } - else + else if(!instance->skipOcclusionQuery) { // render bounding box to later read the occlusion status GetDevice()->QueryBegin(&query, threadID); @@ -1749,7 +1752,7 @@ void wiRenderer::OcclusionCulling_Render(GRAPHICSTHREAD threadID) GetDevice()->UpdateBuffer(constantBuffers[CBTYPE_MISC], &cb, threadID); GetDevice()->Draw(36, threadID); GetDevice()->QueryEnd(&query, threadID); - query.SetActive(true); + instance->skipOcclusionQuery = false; } } } @@ -1778,18 +1781,8 @@ void wiRenderer::OcclusionCulling_Read() for (Object* instance : visibleInstances) { - GPUQuery& query = instance->occlusionQueries[0]; - if (!query.IsActive()) - { - continue; - } - - int queryFailCount = 0; - while (!GetDevice()->QueryRead(&query, GRAPHICSTHREAD_IMMEDIATE)) - { - queryFailCount++; - } - query.SetActive(false); + GPUQuery& query = instance->occlusionQuery; + while (!GetDevice()->QueryRead(&query, GRAPHICSTHREAD_IMMEDIATE)) {} } } @@ -3115,7 +3108,7 @@ void wiRenderer::RenderMeshes(const XMFLOAT3& eye, const CulledCollection& culle if (dither > 1.0f - FLT_EPSILON) continue; - if (disableOcclusionCulling || instance->occlusionQueries[0].result_passed == TRUE) + if (disableOcclusionCulling || instance->occlusionQuery.result_passed == TRUE) { mesh->AddRenderableInstance(Instance(XMMatrixTranspose(mesh->aabb.getAsBoxMatrix()*XMLoadFloat4x4(&instance->world)), dither, instance->color), k, threadID); ++k; @@ -3228,7 +3221,7 @@ void wiRenderer::RenderMeshes(const XMFLOAT3& eye, const CulledCollection& culle if (dither > 1.0f - FLT_EPSILON) continue; - if (disableOcclusionCulling || instance->occlusionQueries[0].result_passed == TRUE) + if (disableOcclusionCulling || instance->occlusionQuery.result_passed == TRUE) { if (mesh->softBody || instance->isArmatureDeformed()) mesh->AddRenderableInstance(Instance(XMMatrixIdentity(), dither, instance->color), k, threadID); @@ -3342,7 +3335,7 @@ void wiRenderer::DrawWorld(Camera* camera, bool tessellation, GRAPHICSTHREAD thr { const FrameCulling& culling = frameCullings[camera]; - const CulledCollection& culledRenderer = culling.culledRenderer; + const CulledCollection& culledRenderer = culling.culledRenderer_opaque; GetDevice()->EventBegin(L"DrawWorld"); @@ -3999,7 +3992,7 @@ wiRenderer::Picked wiRenderer::Pick(RAY& ray, int pickType, const string& layer, vector pickPoints; - RayIntersectMeshes(ray, culledObjects, pickPoints, pickType, true, layer, layerDisable); + RayIntersectMeshes(ray, culledObjects, pickPoints, pickType, true, layer, layerDisable, true); for (auto& model : GetScene().models) { @@ -4104,7 +4097,7 @@ RAY wiRenderer::getPickRay(long cursorX, long cursorY){ } void wiRenderer::RayIntersectMeshes(const RAY& ray, const CulledList& culledObjects, vector& points, - int pickType, bool dynamicObjects, const string& layer, const string& layerDisable) + int pickType, bool dynamicObjects, const string& layer, const string& layerDisable, bool onlyVisible) { if (culledObjects.empty()) { @@ -4125,7 +4118,8 @@ void wiRenderer::RayIntersectMeshes(const RAY& ray, const CulledList& culledObje XMVECTOR& rayOrigin = XMLoadFloat3(&ray.origin); XMVECTOR& rayDirection = XMVector3Normalize(XMLoadFloat3(&ray.direction)); - for (Cullable* culled : culledObjects){ + for (Cullable* culled : culledObjects) + { Object* object = (Object*)culled; if (!(pickType & object->GetRenderTypes())) @@ -4136,6 +4130,10 @@ void wiRenderer::RayIntersectMeshes(const RAY& ray, const CulledList& culledObje { continue; } + if (onlyVisible && object->occlusionQuery.result_passed != TRUE) + { + continue; + } // layer support if (checkLayers || dontcheckLayers) diff --git a/WickedEngine/wiRenderer.h b/WickedEngine/wiRenderer.h index 94f5cddda..12a3d458d 100644 --- a/WickedEngine/wiRenderer.h +++ b/WickedEngine/wiRenderer.h @@ -76,13 +76,9 @@ public: static wiGraphicsTypes::Texture *textures[TEXTYPE_LAST]; - //static int SHADOWMAPRES,SOFTSHADOW,POINTLIGHTSHADOW,POINTLIGHTSHADOWRES,SPOTLIGHTSHADOW,SPOTLIGHTSHADOWRES; static int SHADOWRES_2D, SHADOWRES_CUBE, SHADOWCOUNT_2D, SHADOWCOUNT_CUBE, SOFTSHADOWQUALITY_2D; static bool HAIRPARTICLEENABLED, EMITTERSENABLED; - //static void SetDirectionalLightShadowProps(int resolution, int softShadowQuality); - //static void SetPointLightShadowProps(int shadowMapCount, int resolution); - //static void SetSpotLightShadowProps(int count, int resolution); static void SetShadowProps2D(int resolution, int count, int softShadowQuality); static void SetShadowPropsCube(int resolution, int count); @@ -361,6 +357,7 @@ public: struct FrameCulling { CulledCollection culledRenderer; + CulledCollection culledRenderer_opaque; CulledCollection culledRenderer_transparent; vector culledHairParticleSystems; CulledList culledLights; @@ -491,7 +488,7 @@ public: static Picked Pick(RAY& ray, int pickType = PICK_OPAQUE, const string& layer = "", const string& layerDisable = ""); static RAY getPickRay(long cursorX, long cursorY); static void RayIntersectMeshes(const RAY& ray, const CulledList& culledObjects, vector& points, - int pickType = PICK_OPAQUE, bool dynamicObjects = true, const string& layer = "", const string& layerDisable = ""); + int pickType = PICK_OPAQUE, bool dynamicObjects = true, const string& layer = "", const string& layerDisable = "", bool onlyVisible = false); static void CalculateVertexAO(Object* object); static PHYSICS* physicsEngine; diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 61dbecb24..4ef9bcec0 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -7,7 +7,7 @@ namespace wiVersion // minor features, major updates const int minor = 9; // minor bug fixes, alterations, refactors, updates - const int revision = 37; + const int revision = 38; long GetVersion() diff --git a/features.txt b/features.txt index fde0c387f..efce65264 100644 --- a/features.txt +++ b/features.txt @@ -37,7 +37,7 @@ Spotlights + shadow maps Point lights + shadow cubemaps Diffuse, specular lighting for all lights Soft shadows -Rigid body physics simulation (HAVOK) [NOT PUBLIC] +Rigid body physics simulation (HAVOK) [PRIVATE] Rigid body physics simulation (BULLET) Soft body physics simulation (BULLET) Sound (Xaudio2) @@ -56,4 +56,5 @@ Color Grading Lua Scripting Dynamic environment mapping Impostor system -Tiled forward rendering +Tiled forward (Forward+) rendering +Occlusion culling with gpu queries