diff --git a/Documentation/WickedEngine-Documentation.md b/Documentation/WickedEngine-Documentation.md
index bd097c317..cc2abe5b6 100644
--- a/Documentation/WickedEngine-Documentation.md
+++ b/Documentation/WickedEngine-Documentation.md
@@ -532,14 +532,24 @@ Shaders still need to be created with `GraphicsDevice::CreateShader()` in a simi
Depending on the graphics device implementation, the shader code must be different format. For example, DirectX expects HLSL shaders, Vulkan expects SPIR-V shaders. The engine can only use precompiled shader bytecodes, shader compilation from high level source code is not supported. Usually shaders are compiled into bytecode and saved to files (with .cso extension) by Visual Studio if they are included in the project. These files can be loaded to memory and provided as input buffers to the CreateShader() function.
##### Render Passes
-Render passes are defining regions in GPU execution where a number of render targets or depth buffers will be used to render into them. Render targets and depth buffers are defined as `RenderPassAttachment`s. The `RenderPassAttachment`s have a pointer to the texture, state the resource type (`RENDER_TARGET` or `DEPTH_STENCIL`), state the [subresource](#subresources) index, the load and store operations, and the layout transitions for the textures.
+Render passes are defining regions in GPU execution where a number of render targets or depth buffers will be used to render into them. Render targets and depth buffers are defined as `RenderPassAttachment`s. The `RenderPassAttachment`s have a pointer to the texture, state the resource type (`RENDERTARGET`, `DEPTH_STENCIL` or `RESOLVE`), state the [subresource](#subresources) index, the load and store operations, and the layout transitions for the textures.
+
+- `RENDERTARGET`: The attachment will be used as a (color) render target. The order of these attachments define the shader color output order.
+- `DEPTH_STENCIL`: The attachment will be used as a depth (and/or stencil) buffer.
+- `RESOLVE`: The attachment will be used as MSAA resolve destination. The resolve source is chosen among the `RENDERTARGET` attachments in the same render pass, in the order they were declared in. The declaration order of the `RENDERTARGET` and `RESOLVE` attachment must match to correctly deduce source and destination targets for resolve operations.
- Load Operation:
Defines how the texture contents are initialized at the start of the render pass. `LOADOP_LOAD` says that the previous texture content will be retained. `LOADOP_CLEAR` says that the previous contents of the texture will be lost and instead the texture clear color will be used to fill the texture. `LOADOP_DONTCARE` says that the texture contents are undefined, so this should only be used when the developer can ensure that the whole texture will be rendered to and not leaving any region empty (in which case, undefined results will be present in the texture).
- Store operation:
Defines how the texture contents are handled after the render pass ends. `STOREOP_STORE` means that the contents will be preserved. `STOREOP_DONTCARE` means that the contents won't be necessarily preserved, they are only temporarily valid within the duration of the render pass, which can save some memory bandwidth on some platforms (specifically tile based rendering architectures, like mobile GPUs).
- Layout transition:
-Define the `intial_layout` and `final_layout` members to have an implicit transition performed as part of the render pass, that works like an [IMAGE_BARRIER](#gpu-barriers), but can be more optimal.
+Define the `intial_layout`, `subpass_layout` (only for `RENDERTARGET` or `DEPTH_STENCIL`) and `final_layout` members to have an implicit transition performed as part of the render pass, that works like an [IMAGE_BARRIER](#gpu-barriers), but can be more optimal. The `initial_layout` states the starting state of the resource. The resource will be transitioned from `initial_layout` to `subpass_layout` within the render pass. The `subpass_layout` states how the resource is accessed within the render pass. For `RENDERTARGET`, this must be `IMAGE_LAYOUT_RENDERTARGET`, for `DEPTH_STENCIL` type, it must be either `IMAGE_LAYOUT_DEPTHSTENCIL` or `IMAGE_LAYOUT_DEPTHSTENCIL_READONLY`. For `RESOLVE` type, the subpass_layout have no meaning, it is implicitly defined. At the end of the render pass, the resources will be transitioned from `subpass_layout` to `final_layout`.
+
+Notes:
+- When `RenderPassBegin()` is called, `RenderPassEnd()` must be called after on the same command list before the command list gets [submitted](#work-submission).
+- It is not allowed to call `CopyResource()`, `CopyTexture2D()`, etc. inside a render pass.
+- It is not allowed to call `Dispatch()` and `DispatchIndirect()` inside a render pass.
+- It is not allowed to call `UpdateBuffer()` inside the render pass unless the buffer is `USAGE_DYNAMIC` and is a `BIND_CONSTANT_BUFFER`.
##### GPU Barriers
`GPUBarrier`s can be used to state dependencies between GPU workloads. There are different kinds of barriers:
@@ -547,7 +557,7 @@ Define the `intial_layout` and `final_layout` members to have an implicit transi
- MEMORY_BARRIER
Memory barriers are used to wait for UAV writes to finish, or in other words to wait for shaders to finish that are writing to a BIND_UNORDERED_ACCESS resource. The `GPUBarrier::memory.resource` member is a pointer to the GPUResource to wait on. If it is nullptr, than the barrier means "wait for every UAV write that is in flight to finish".
- IMAGE_BARRIER
-Image barriers are stating resource state transition for [textures](#textures). The most common use case for example is to transition from `IMAGE_LAYOUT_RENDERTARGET` to `IMAGE_LAYOUT_SHADER_RESOURCE`, which means that the [RenderPass](#renderpass) that writes to the texture as render target must finish before the barrier, and the texture can be used as a read only shader resource after the barrier. There are other cases that can be indicated using the `GPUBarrier::image.layout_before` and `GPUBarrier::image.layout_after` states. The `GPUBarrier::image.resource` is a pointer to the resource which will have its state changed.
+Image barriers are stating resource state transition for [textures](#textures). The most common use case for example is to transition from `IMAGE_LAYOUT_RENDERTARGET` to `IMAGE_LAYOUT_SHADER_RESOURCE`, which means that the [RenderPass](#render-passes) that writes to the texture as render target must finish before the barrier, and the texture can be used as a read only shader resource after the barrier. There are other cases that can be indicated using the `GPUBarrier::image.layout_before` and `GPUBarrier::image.layout_after` states. The `GPUBarrier::image.resource` is a pointer to the resource which will have its state changed. If the texture's `layout` (as part of the TextureDesc) is not `IMAGE_LAYOUT_GENERAL` or `IMAGE_LAYOUT_SHADER_RESOURCE`, the layout must be transitioned to `IMAGE_LAYOUT_SHADER_RESOURCE` before binding as shader resource. The image layout can also be transitioned using a [RenderPass](#render-passes), which should be preferred to `GPUBarrier`s.
- BUFFER_BARRIER
Similar to `IMAGE_BARRIER`, but for [GPU Buffer](#gpu-buffers) state transitions.
diff --git a/README.md b/README.md
index 08747eb94..d34079cae 100644
--- a/README.md
+++ b/README.md
@@ -67,13 +67,13 @@ If you wish to integrate Wicked Engine into your own project, you can use it as
- ./WickedEngine
3. Linker -> General -> Additional Library Directories:
- Directory of your built .lib file (For example ./x64/Release)
-4. Also be sure to compile with a non-DLL runtime library for Release builds:
+4. Compile with a non-DLL runtime library for Release builds:
- Project settings -> C/C++ -> Code Generation -> Runtime Library -> Multi threaded
5. If you want to create a UWP application, link against the WickedEngine_UWP library.
When your project settings are set up, put `#include "WickedEngine.h"` in your source. This will enable the use of all the engine features and link the necessary binaries. After this, you should already be able to build your project.
-If you have trouble, you can always look at or copy the project settings for Editor, Tests and Template application projects to get an idea how to link with Wicked Engine.
+If you have trouble, you can look at or copy the project settings for Editor, Tests and Template application projects to get an idea how to link with Wicked Engine.
Initialization example (C++):
@@ -223,7 +223,7 @@ You can specify command line arguments to switch between render devices or other
* *DX12 will try to load shaders from WickedEngine/shaders/hlsl6 directory.
-HLSL6 shaders can be compiled by Rebuilding the Shaders_HLSL6 project from within Visual Studio.
+HLSL6 shaders can be compiled by Rebuilding the Shaders_HLSL6 project from within Visual Studio (Python 3 required for building).
* **Vulkan support will be built into the application if the Vulkan SDK is installed on the build machine.
Vulkan will try to load shaders from WickedEngine/shaders/spirv directory.
diff --git a/WickedEngine/wiGraphicsDevice.h b/WickedEngine/wiGraphicsDevice.h
index ee39afeac..46f870f10 100644
--- a/WickedEngine/wiGraphicsDevice.h
+++ b/WickedEngine/wiGraphicsDevice.h
@@ -64,7 +64,7 @@ namespace wiGraphics
virtual void ClearPipelineStateCache() {};
inline bool GetVSyncEnabled() const { return VSYNC; }
- inline void SetVSyncEnabled(bool value) { VSYNC = value; }
+ virtual void SetVSyncEnabled(bool value) { VSYNC = value; }
inline uint64_t GetFrameCount() const { return FRAMECOUNT; }
// Returns native resolution width of back buffer in pixels:
diff --git a/WickedEngine/wiGraphicsDevice_DX11.cpp b/WickedEngine/wiGraphicsDevice_DX11.cpp
index d32888308..5f42fad7d 100644
--- a/WickedEngine/wiGraphicsDevice_DX11.cpp
+++ b/WickedEngine/wiGraphicsDevice_DX11.cpp
@@ -2661,26 +2661,30 @@ void GraphicsDevice_DX11::RenderPassEnd(CommandList cmd)
int dst_counter = 0;
for (auto& attachment : active_renderpass[cmd]->desc.attachments)
{
- if (attachment.type != RenderPassAttachment::RESOLVE || attachment.texture == nullptr)
- continue;
- auto dst_internal = to_internal(attachment.texture);
-
- int src_counter = 0;
- for (auto& src : active_renderpass[cmd]->desc.attachments)
+ if (attachment.type == RenderPassAttachment::RESOLVE)
{
- if (src.type == RenderPassAttachment::RENDERTARGET && src.texture != nullptr)
+ if (attachment.texture != nullptr)
{
- if (src_counter == dst_counter)
- {
- auto src_internal = to_internal(src.texture);
- deviceContexts[cmd]->ResolveSubresource(dst_internal->resource.Get(), 0, src_internal->resource.Get(), 0, _ConvertFormat(attachment.texture->desc.Format));
- break;
- }
- src_counter++;
- }
- }
+ auto dst_internal = to_internal(attachment.texture);
- dst_counter++;
+ int src_counter = 0;
+ for (auto& src : active_renderpass[cmd]->desc.attachments)
+ {
+ if (src.type == RenderPassAttachment::RENDERTARGET && src.texture != nullptr)
+ {
+ if (src_counter == dst_counter)
+ {
+ auto src_internal = to_internal(src.texture);
+ deviceContexts[cmd]->ResolveSubresource(dst_internal->resource.Get(), 0, src_internal->resource.Get(), 0, _ConvertFormat(attachment.texture->desc.Format));
+ break;
+ }
+ src_counter++;
+ }
+ }
+ }
+
+ dst_counter++;
+ }
}
active_renderpass[cmd] = nullptr;
}
diff --git a/WickedEngine/wiGraphicsDevice_DX12.cpp b/WickedEngine/wiGraphicsDevice_DX12.cpp
index a7dd1981c..41db6cef8 100644
--- a/WickedEngine/wiGraphicsDevice_DX12.cpp
+++ b/WickedEngine/wiGraphicsDevice_DX12.cpp
@@ -32,9 +32,6 @@
#include
#include
-// Uncomment this to enable DX12 renderpass feature:
-#define DX12_REAL_RENDERPASS
-
using namespace Microsoft::WRL;
namespace wiGraphics
@@ -1020,10 +1017,6 @@ namespace DX12_Internal
std::vector geometries;
D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO info = {};
GPUBuffer scratch;
-
- ~BVH_DX12() override
- {
- }
};
struct RTPipelineState_DX12
{
@@ -1044,6 +1037,13 @@ namespace DX12_Internal
allocationhandler->destroylocker.unlock();
}
};
+ struct RenderPass_DX12
+ {
+ D3D12_RESOURCE_BARRIER barrierdescs_begin[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT] = {};
+ uint32_t num_barriers_begin = 0;
+ D3D12_RESOURCE_BARRIER barrierdescs_end[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT] = {};
+ uint32_t num_barriers_end = 0;
+ };
Resource_DX12* to_internal(const GPUResource* param)
{
@@ -1081,6 +1081,10 @@ namespace DX12_Internal
{
return static_cast(param->internal_state.get());
}
+ RenderPass_DX12* to_internal(const RenderPass* param)
+ {
+ return static_cast(param->internal_state.get());
+ }
}
using namespace DX12_Internal;
@@ -2863,7 +2867,8 @@ using namespace DX12_Internal;
}
bool GraphicsDevice_DX12::CreateRenderPass(const RenderPassDesc* pDesc, RenderPass* renderpass)
{
- renderpass->internal_state = allocationhandler;
+ auto internal_state = std::make_shared();
+ renderpass->internal_state = internal_state;
renderpass->desc = *pDesc;
@@ -2875,6 +2880,69 @@ using namespace DX12_Internal;
wiHelper::hash_combine(renderpass->hash, attachment.texture->desc.SampleCount);
}
+
+ // Beginning barriers:
+ for (auto& attachment : renderpass->desc.attachments)
+ {
+ if (attachment.texture == nullptr)
+ continue;
+
+ auto texture_internal = to_internal(attachment.texture);
+
+ D3D12_RESOURCE_BARRIER& barrierdesc = internal_state->barrierdescs_begin[internal_state->num_barriers_begin++];
+
+ barrierdesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
+ barrierdesc.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
+ barrierdesc.Transition.pResource = texture_internal->resource.Get();
+ barrierdesc.Transition.StateBefore = _ConvertImageLayout(attachment.initial_layout);
+ if (attachment.type == RenderPassAttachment::RESOLVE)
+ {
+ barrierdesc.Transition.StateAfter = D3D12_RESOURCE_STATE_RESOLVE_DEST;
+ }
+ else
+ {
+ barrierdesc.Transition.StateAfter = _ConvertImageLayout(attachment.subpass_layout);
+ }
+ barrierdesc.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
+
+ if (barrierdesc.Transition.StateBefore == barrierdesc.Transition.StateAfter)
+ {
+ internal_state->num_barriers_begin--;
+ continue;
+ }
+ }
+
+ // Ending barriers:
+ for (auto& attachment : renderpass->desc.attachments)
+ {
+ if (attachment.texture == nullptr)
+ continue;
+
+ auto texture_internal = to_internal(attachment.texture);
+
+ D3D12_RESOURCE_BARRIER& barrierdesc = internal_state->barrierdescs_end[internal_state->num_barriers_end++];
+
+ barrierdesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
+ barrierdesc.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
+ barrierdesc.Transition.pResource = texture_internal->resource.Get();
+ if (attachment.type == RenderPassAttachment::RESOLVE)
+ {
+ barrierdesc.Transition.StateBefore = D3D12_RESOURCE_STATE_RESOLVE_DEST;
+ }
+ else
+ {
+ barrierdesc.Transition.StateBefore = _ConvertImageLayout(attachment.subpass_layout);
+ }
+ barrierdesc.Transition.StateAfter = _ConvertImageLayout(attachment.final_layout);
+ barrierdesc.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
+
+ if (barrierdesc.Transition.StateBefore == barrierdesc.Transition.StateAfter)
+ {
+ internal_state->num_barriers_end--;
+ continue;
+ }
+ }
+
return true;
}
bool GraphicsDevice_DX12::CreateRaytracingAccelerationStructure(const RaytracingAccelerationStructureDesc* pDesc, RaytracingAccelerationStructure* bvh)
@@ -3560,8 +3628,6 @@ using namespace DX12_Internal;
const float clearcolor[] = { 0,0,0,1 };
device->CreateRenderTargetView(GetFrameResources().backBuffer.Get(), nullptr, rtv_descriptor_heap_start);
-#ifdef DX12_REAL_RENDERPASS
-
D3D12_RENDER_PASS_RENDER_TARGET_DESC RTV = {};
RTV.cpuDescriptor = rtv_descriptor_heap_start;
RTV.BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR;
@@ -3572,21 +3638,12 @@ using namespace DX12_Internal;
RTV.EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE;
GetDirectCommandList(cmd)->BeginRenderPass(1, &RTV, nullptr, D3D12_RENDER_PASS_FLAG_ALLOW_UAV_WRITES);
-#else
-
- GetDirectCommandList(cmd)->OMSetRenderTargets(1, &rtv_descriptor_heap_start, TRUE, nullptr);
- GetDirectCommandList(cmd)->ClearRenderTargetView(rtv_descriptor_heap_start, clearcolor, 0, nullptr);
-
-#endif // DX12_REAL_RENDERPASS
-
}
void GraphicsDevice_DX12::PresentEnd(CommandList cmd)
{
copyQueueLock.lock();
-#ifdef DX12_REAL_RENDERPASS
GetDirectCommandList(cmd)->EndRenderPass();
-#endif // DX12_REAL_RENDERPASS
HRESULT result;
@@ -3798,55 +3855,31 @@ using namespace DX12_Internal;
void GraphicsDevice_DX12::RenderPassBegin(const RenderPass* renderpass, CommandList cmd)
{
active_renderpass[cmd] = renderpass;
+
+ auto internal_state = to_internal(active_renderpass[cmd]);
+ if (internal_state->num_barriers_begin > 0)
+ {
+ GetDirectCommandList(cmd)->ResourceBarrier(internal_state->num_barriers_begin, internal_state->barrierdescs_begin);
+ }
+
const RenderPassDesc& desc = renderpass->GetDesc();
- // Perform render pass transitions:
- D3D12_RESOURCE_BARRIER barrierdescs[9];
- uint32_t numBarriers = 0;
- for (auto& attachment : desc.attachments)
- {
- if (attachment.type == RenderPassAttachment::RESOLVE || attachment.texture == nullptr)
- continue;
-
- auto internal_state = to_internal(attachment.texture);
-
- D3D12_RESOURCE_BARRIER& barrierdesc = barrierdescs[numBarriers++];
-
- barrierdesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
- barrierdesc.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
- barrierdesc.Transition.pResource = internal_state->resource.Get();
- barrierdesc.Transition.StateBefore = _ConvertImageLayout(attachment.initial_layout);
- barrierdesc.Transition.StateAfter = _ConvertImageLayout(attachment.subpass_layout);
- barrierdesc.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
-
- if (barrierdesc.Transition.StateBefore == barrierdesc.Transition.StateAfter)
- {
- numBarriers--;
- continue;
- }
- }
- if (numBarriers > 0)
- {
- GetDirectCommandList(cmd)->ResourceBarrier(numBarriers, barrierdescs);
- }
-
D3D12_CPU_DESCRIPTOR_HANDLE descriptors_RTV = rtv_descriptor_heap_start;
descriptors_RTV.ptr += rtv_descriptor_size * D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT * cmd;
D3D12_CPU_DESCRIPTOR_HANDLE descriptors_DSV = dsv_descriptor_heap_start;
descriptors_DSV.ptr += dsv_descriptor_size * cmd;
-#ifdef DX12_REAL_RENDERPASS
-
uint32_t rt_count = 0;
D3D12_RENDER_PASS_RENDER_TARGET_DESC RTVs[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT] = {};
bool dsv = false;
D3D12_RENDER_PASS_DEPTH_STENCIL_DESC DSV = {};
+ int resolve_dst_counter = 0;
for (auto& attachment : desc.attachments)
{
const Texture* texture = attachment.texture;
int subresource = attachment.subresource;
- auto internal_state = to_internal(texture);
+ auto texture_internal = to_internal(texture);
D3D12_CLEAR_VALUE clear_value;
clear_value.Format = _ConvertFormat(texture->desc.Format);
@@ -3856,14 +3889,14 @@ using namespace DX12_Internal;
RTVs[rt_count].cpuDescriptor = descriptors_RTV;
RTVs[rt_count].cpuDescriptor.ptr += rtv_descriptor_size * rt_count;
- if (subresource < 0 || internal_state->subresources_rtv.empty())
+ if (subresource < 0 || texture_internal->subresources_rtv.empty())
{
- device->CreateRenderTargetView(internal_state->resource.Get(), &internal_state->rtv, RTVs[rt_count].cpuDescriptor);
+ device->CreateRenderTargetView(texture_internal->resource.Get(), &texture_internal->rtv, RTVs[rt_count].cpuDescriptor);
}
else
{
- assert(internal_state->subresources_rtv.size() > size_t(subresource) && "Invalid RTV subresource!");
- device->CreateRenderTargetView(internal_state->resource.Get(), &internal_state->subresources_rtv[subresource], RTVs[rt_count].cpuDescriptor);
+ assert(texture_internal->subresources_rtv.size() > size_t(subresource) && "Invalid RTV subresource!");
+ device->CreateRenderTargetView(texture_internal->resource.Get(), &texture_internal->subresources_rtv[subresource], RTVs[rt_count].cpuDescriptor);
}
switch (attachment.loadop)
@@ -3904,14 +3937,14 @@ using namespace DX12_Internal;
DSV.cpuDescriptor = descriptors_DSV;
- if (subresource < 0 || internal_state->subresources_dsv.empty())
+ if (subresource < 0 || texture_internal->subresources_dsv.empty())
{
- device->CreateDepthStencilView(internal_state->resource.Get(), &internal_state->dsv, DSV.cpuDescriptor);
+ device->CreateDepthStencilView(texture_internal->resource.Get(), &texture_internal->dsv, DSV.cpuDescriptor);
}
else
{
- assert(internal_state->subresources_dsv.size() > size_t(subresource) && "Invalid DSV subresource!");
- device->CreateDepthStencilView(internal_state->resource.Get(), &internal_state->subresources_dsv[subresource], DSV.cpuDescriptor);
+ assert(texture_internal->subresources_dsv.size() > size_t(subresource) && "Invalid DSV subresource!");
+ device->CreateDepthStencilView(texture_internal->resource.Get(), &texture_internal->subresources_dsv[subresource], DSV.cpuDescriptor);
}
switch (attachment.loadop)
@@ -3948,157 +3981,57 @@ using namespace DX12_Internal;
break;
}
}
+ else if (attachment.type == RenderPassAttachment::RESOLVE)
+ {
+ if (texture != nullptr)
+ {
+ int resolve_src_counter = 0;
+ for (auto& src : active_renderpass[cmd]->desc.attachments)
+ {
+ if (src.type == RenderPassAttachment::RENDERTARGET && src.texture != nullptr)
+ {
+ if (resolve_src_counter == resolve_dst_counter)
+ {
+ auto src_internal = to_internal(src.texture);
+
+ D3D12_RENDER_PASS_RENDER_TARGET_DESC& src_RTV = RTVs[resolve_src_counter];
+ src_RTV.EndingAccess.Resolve.PreserveResolveSource = src_RTV.EndingAccess.Type == D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE;
+ src_RTV.EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE;
+ src_RTV.EndingAccess.Resolve.Format = clear_value.Format;
+ src_RTV.EndingAccess.Resolve.ResolveMode = D3D12_RESOLVE_MODE_AVERAGE;
+ src_RTV.EndingAccess.Resolve.SubresourceCount = 1;
+ src_RTV.EndingAccess.Resolve.pDstResource = texture_internal->resource.Get();
+ src_RTV.EndingAccess.Resolve.pSrcResource = src_internal->resource.Get();
+
+ // Due to a API bug, this resolve_subresources array must be kept alive between BeginRenderpass() and EndRenderpass()!
+ src_RTV.EndingAccess.Resolve.pSubresourceParameters = &resolve_subresources[cmd][resolve_src_counter];
+ resolve_subresources[cmd][resolve_src_counter].SrcRect.left = 0;
+ resolve_subresources[cmd][resolve_src_counter].SrcRect.right = (LONG)texture->desc.Width;
+ resolve_subresources[cmd][resolve_src_counter].SrcRect.bottom = (LONG)texture->desc.Height;
+ resolve_subresources[cmd][resolve_src_counter].SrcRect.top = 0;
+
+ break;
+ }
+ resolve_src_counter++;
+ }
+ }
+ }
+ resolve_dst_counter++;
+ }
+
}
GetDirectCommandList(cmd)->BeginRenderPass(rt_count, RTVs, dsv ? &DSV : nullptr, D3D12_RENDER_PASS_FLAG_ALLOW_UAV_WRITES);
-#else
-
- uint32_t rt_count = 0;
- D3D12_RENDER_TARGET_VIEW_DESC RTVs[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT] = {};
- D3D12_DEPTH_STENCIL_VIEW_DESC* DSV = nullptr;
- for (auto& attachment : desc.attachments)
- {
- const Texture* texture = attachment.texture;
- int subresource = attachment.subresource;
- auto internal_state = to_internal(texture);
-
- if (attachment.type == RenderPassAttachment::RENDERTARGET)
- {
- if (subresource < 0 || internal_state->subresources_rtv.empty())
- {
- RTVs[rt_count] = internal_state->rtv;
- }
- else
- {
- assert(internal_state->subresources_rtv.size() > size_t(subresource) && "Invalid RTV subresource!");
- RTVs[rt_count] = internal_state->subresources_rtv[subresource];
- }
-
- D3D12_CPU_DESCRIPTOR_HANDLE descriptor = descriptors_RTV;
- descriptor.ptr += rtv_descriptor_size * rt_count;
- device->CreateRenderTargetView(internal_state->resource.Get(), &RTVs[rt_count], descriptor);
-
- if (attachment.loadop == RenderPassAttachment::LOADOP_CLEAR)
- {
- GetDirectCommandList(cmd)->ClearRenderTargetView(descriptor, texture->desc.clear.color, 0, nullptr);
- }
-
- rt_count++;
- }
- else if (attachment.type == RenderPassAttachment::DEPTH_STENCIL)
- {
- if (subresource < 0 || internal_state->subresources_dsv.empty())
- {
- DSV = &internal_state->dsv;
- }
- else
- {
- assert(internal_state->subresources_dsv.size() > size_t(subresource) && "Invalid DSV subresource!");
- DSV = &internal_state->subresources_dsv[subresource];
- }
-
- D3D12_CPU_DESCRIPTOR_HANDLE descriptor = descriptors_DSV;
- device->CreateDepthStencilView(internal_state->resource.Get(), DSV, descriptor);
-
- if (attachment.loadop == RenderPassAttachment::LOADOP_CLEAR)
- {
- uint32_t _flags = D3D12_CLEAR_FLAG_DEPTH;
- if (IsFormatStencilSupport(texture->desc.Format))
- _flags |= D3D12_CLEAR_FLAG_STENCIL;
- GetDirectCommandList(cmd)->ClearDepthStencilView(descriptor, (D3D12_CLEAR_FLAGS)_flags, texture->desc.clear.depthstencil.depth, texture->desc.clear.depthstencil.stencil, 0, nullptr);
- }
- }
- }
-
- GetDirectCommandList(cmd)->OMSetRenderTargets(rt_count, &descriptors_RTV, TRUE, DSV == nullptr ? nullptr : &descriptors_DSV);
-
-#endif // DX12_REAL_RENDERPASS
}
void GraphicsDevice_DX12::RenderPassEnd(CommandList cmd)
{
-#ifdef DX12_REAL_RENDERPASS
GetDirectCommandList(cmd)->EndRenderPass();
-#else
- GetDirectCommandList(cmd)->OMSetRenderTargets(0, nullptr, FALSE, nullptr);
-#endif // DX12_REAL_RENDERPASS
-
- // Perform render pass transitions:
- D3D12_RESOURCE_BARRIER barrierdescs[9];
- uint32_t numBarriers = 0;
- for (auto& attachment : active_renderpass[cmd]->desc.attachments)
+ auto internal_state = to_internal(active_renderpass[cmd]);
+ if (internal_state->num_barriers_end > 0)
{
- auto internal_state = to_internal(attachment.texture);
-
- D3D12_RESOURCE_BARRIER& barrierdesc = barrierdescs[numBarriers++];
-
- barrierdesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
- barrierdesc.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
- barrierdesc.Transition.pResource = internal_state->resource.Get();
- barrierdesc.Transition.StateBefore = _ConvertImageLayout(attachment.subpass_layout);
- barrierdesc.Transition.StateAfter = _ConvertImageLayout(attachment.final_layout);
- barrierdesc.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
-
- if (barrierdesc.Transition.StateBefore == barrierdesc.Transition.StateAfter)
- {
- numBarriers--;
- continue;
- }
- }
- if (numBarriers > 0)
- {
- GetDirectCommandList(cmd)->ResourceBarrier(numBarriers, barrierdescs);
- }
-
- // Perform resolves:
- int dst_counter = 0;
- for (auto& attachment : active_renderpass[cmd]->desc.attachments)
- {
- if (attachment.type != RenderPassAttachment::RESOLVE || attachment.texture == nullptr)
- continue;
- auto dst_internal = to_internal(attachment.texture);
-
- int src_counter = 0;
- for (auto& src : active_renderpass[cmd]->desc.attachments)
- {
- if (src.type == RenderPassAttachment::RENDERTARGET && src.texture != nullptr)
- {
- if (src_counter == dst_counter)
- {
- auto src_internal = to_internal(src.texture);
-
- D3D12_RESOURCE_BARRIER barrierdescs[2];
-
- barrierdescs[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
- barrierdescs[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
- barrierdescs[0].Transition.pResource = src_internal->resource.Get();
- barrierdescs[0].Transition.StateBefore = _ConvertImageLayout(src.final_layout);
- barrierdescs[0].Transition.StateAfter = D3D12_RESOURCE_STATE_RESOLVE_SOURCE;
- barrierdescs[0].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
-
- barrierdescs[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
- barrierdescs[1].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
- barrierdescs[1].Transition.pResource = dst_internal->resource.Get();
- barrierdescs[1].Transition.StateBefore = _ConvertImageLayout(attachment.final_layout);
- barrierdescs[1].Transition.StateAfter = D3D12_RESOURCE_STATE_RESOLVE_DEST;
- barrierdescs[1].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
-
- GetDirectCommandList(cmd)->ResourceBarrier(arraysize(barrierdescs), barrierdescs);
-
- GetDirectCommandList(cmd)->ResolveSubresource(dst_internal->resource.Get(), 0, src_internal->resource.Get(), 0, _ConvertFormat(attachment.texture->desc.Format));
-
- std::swap(barrierdescs[0].Transition.StateBefore, barrierdescs[0].Transition.StateAfter);
- std::swap(barrierdescs[1].Transition.StateBefore, barrierdescs[1].Transition.StateAfter);
- GetDirectCommandList(cmd)->ResourceBarrier(arraysize(barrierdescs), barrierdescs);
-
- break;
- }
- src_counter++;
- }
- }
-
- dst_counter++;
+ GetDirectCommandList(cmd)->ResourceBarrier(internal_state->num_barriers_end, internal_state->barrierdescs_end);
}
active_renderpass[cmd] = nullptr;
diff --git a/WickedEngine/wiGraphicsDevice_DX12.h b/WickedEngine/wiGraphicsDevice_DX12.h
index c44cd6a29..2e2d728ea 100644
--- a/WickedEngine/wiGraphicsDevice_DX12.h
+++ b/WickedEngine/wiGraphicsDevice_DX12.h
@@ -157,6 +157,7 @@ namespace wiGraphics
const PipelineState* active_pso[COMMANDLIST_COUNT] = {};
const Shader* active_cs[COMMANDLIST_COUNT] = {};
const RenderPass* active_renderpass[COMMANDLIST_COUNT] = {};
+ D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS resolve_subresources[COMMANDLIST_COUNT][D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT] = {};
bool dirty_pso[COMMANDLIST_COUNT] = {};
void pso_validate(CommandList cmd);
diff --git a/WickedEngine/wiGraphicsDevice_Vulkan.cpp b/WickedEngine/wiGraphicsDevice_Vulkan.cpp
index 70ab83016..35d75df14 100644
--- a/WickedEngine/wiGraphicsDevice_Vulkan.cpp
+++ b/WickedEngine/wiGraphicsDevice_Vulkan.cpp
@@ -1320,7 +1320,14 @@ using namespace Vulkan_Internal;
{
imageInfos.back().imageView = to_internal(texture)->srv;
}
- imageInfos.back().imageLayout = _ConvertImageLayout(texture->desc.layout);
+
+ VkImageLayout layout = _ConvertImageLayout(texture->desc.layout);
+ if (layout != VK_IMAGE_LAYOUT_GENERAL && layout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
+ {
+ // Means texture initial layout is not compatible, so it must have been transitioned
+ layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ }
+ imageInfos.back().imageLayout = layout;
}
}
break;
@@ -1377,7 +1384,6 @@ using namespace Vulkan_Internal;
{
imageInfos.back().imageView = to_internal(texture)->uav;
}
- imageInfos.back().imageLayout = _ConvertImageLayout(texture->desc.layout);
}
}
break;
@@ -2598,7 +2604,19 @@ using namespace Vulkan_Internal;
createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
- createInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR;
+ createInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR; // The only one that is always supported
+ if (!VSYNC)
+ {
+ // The immediate present mode is not necessarily supported:
+ for (auto& presentmode : swapChainSupport.presentModes)
+ {
+ if (presentmode == VK_PRESENT_MODE_IMMEDIATE_KHR)
+ {
+ createInfo.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
+ break;
+ }
+ }
+ }
createInfo.clipped = VK_TRUE;
createInfo.oldSwapchain = VK_NULL_HANDLE;
@@ -3972,22 +3990,29 @@ using namespace Vulkan_Internal;
}
else if (attachment.type == RenderPassAttachment::RESOLVE)
{
- if (subresource < 0 || texture_internal_state->subresources_srv.empty())
+ if (attachment.texture == nullptr)
{
- attachments[validAttachmentCount] = texture_internal_state->srv;
+ resolveAttachmentRefs[resolvecount].attachment = VK_ATTACHMENT_UNUSED;
}
else
{
- assert(texture_internal_state->subresources_srv.size() > size_t(subresource) && "Invalid SRV subresource!");
- attachments[validAttachmentCount] = texture_internal_state->subresources_srv[subresource];
- }
- if (attachments[validAttachmentCount] == VK_NULL_HANDLE)
- {
- continue;
+ if (subresource < 0 || texture_internal_state->subresources_srv.empty())
+ {
+ attachments[validAttachmentCount] = texture_internal_state->srv;
+ }
+ else
+ {
+ assert(texture_internal_state->subresources_srv.size() > size_t(subresource) && "Invalid SRV subresource!");
+ attachments[validAttachmentCount] = texture_internal_state->subresources_srv[subresource];
+ }
+ if (attachments[validAttachmentCount] == VK_NULL_HANDLE)
+ {
+ continue;
+ }
+ resolveAttachmentRefs[resolvecount].attachment = validAttachmentCount;
+ resolveAttachmentRefs[resolvecount].layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
}
- resolveAttachmentRefs[resolvecount].attachment = validAttachmentCount;
- resolveAttachmentRefs[resolvecount].layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
resolvecount++;
subpass.pResolveAttachments = resolveAttachmentRefs;
}
diff --git a/WickedEngine/wiGraphicsDevice_Vulkan.h b/WickedEngine/wiGraphicsDevice_Vulkan.h
index f8319b871..ca6e5f429 100644
--- a/WickedEngine/wiGraphicsDevice_Vulkan.h
+++ b/WickedEngine/wiGraphicsDevice_Vulkan.h
@@ -259,6 +259,8 @@ namespace wiGraphics
Texture GetBackBuffer() override;
+ void SetVSyncEnabled(bool value) override { VSYNC = value; CreateBackBufferResources(); };
+
///////////////Thread-sensitive////////////////////////
void RenderPassBegin(const RenderPass* renderpass, CommandList cmd) override;
diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp
index 374d6f51b..9b5d72dfd 100644
--- a/WickedEngine/wiVersion.cpp
+++ b/WickedEngine/wiVersion.cpp
@@ -9,7 +9,7 @@ namespace wiVersion
// minor features, major updates, breaking API changes
const int minor = 46;
// minor bug fixes, alterations, refactors, updates
- const int revision = 1;
+ const int revision = 2;
const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);