Files
renderdoc/renderdoc/driver/d3d11/d3d11_msaa_array_conv.cpp
T

851 lines
28 KiB
C++

/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2019-2021 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#include "d3d11_context.h"
#include "d3d11_debug.h"
#include "d3d11_renderstate.h"
#include "d3d11_resources.h"
struct Tex2DMSToArrayStateTracker
{
Tex2DMSToArrayStateTracker(WrappedID3D11DeviceContext *wrappedContext)
{
m_WrappedContext = wrappedContext;
D3D11RenderState *rs = wrappedContext->GetCurrentPipelineState();
// first copy the properties. We don't need to keep refs as the objects won't be deleted by
// being unbound and we won't do anything with them
Layout = rs->IA.Layout;
memcpy(&VS, &rs->VS, sizeof(VS));
memcpy(&PS, &rs->PS, sizeof(PS));
memcpy(CSUAVs, rs->CSUAVs, sizeof(CSUAVs));
memcpy(&RS, &rs->RS, sizeof(RS));
memcpy(&OM, &rs->OM, sizeof(OM));
RDCCOMPILE_ASSERT(sizeof(VS) == sizeof(rs->VS), "Struct sizes have changed, ensure full copy");
RDCCOMPILE_ASSERT(sizeof(RS) == sizeof(rs->RS), "Struct sizes have changed, ensure full copy");
RDCCOMPILE_ASSERT(sizeof(OM) == sizeof(rs->OM), "Struct sizes have changed, ensure full copy");
// now unwrap everything in place.
Layout = UNWRAP(WrappedID3D11InputLayout, Layout);
VS.Shader = UNWRAP(WrappedID3D11Shader<ID3D11VertexShader>, VS.Shader);
PS.Shader = UNWRAP(WrappedID3D11Shader<ID3D11PixelShader>, PS.Shader);
// only need to save/restore constant buffer 0
PS.ConstantBuffers[0] = UNWRAP(WrappedID3D11Buffer, PS.ConstantBuffers[0]);
// same for the first 16 SRVs
for(int i = 0; i < 16; i++)
PS.SRVs[i] = UNWRAP(WrappedID3D11ShaderResourceView1, PS.SRVs[i]);
for(int i = 0; i < D3D11_SHADER_MAX_INTERFACES; i++)
{
VS.Instances[i] = UNWRAP(WrappedID3D11ClassInstance, VS.Instances[i]);
PS.Instances[i] = UNWRAP(WrappedID3D11ClassInstance, PS.Instances[i]);
}
for(int i = 0; i < D3D11_1_UAV_SLOT_COUNT; i++)
CSUAVs[i] = UNWRAP(WrappedID3D11UnorderedAccessView1, CSUAVs[i]);
RS.State = UNWRAP(WrappedID3D11RasterizerState2, RS.State);
OM.DepthStencilState = UNWRAP(WrappedID3D11DepthStencilState, OM.DepthStencilState);
OM.BlendState = UNWRAP(WrappedID3D11BlendState1, OM.BlendState);
OM.DepthView = UNWRAP(WrappedID3D11DepthStencilView, OM.DepthView);
for(int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
OM.RenderTargets[i] = UNWRAP(WrappedID3D11RenderTargetView1, OM.RenderTargets[i]);
for(int i = 0; i < D3D11_1_UAV_SLOT_COUNT; i++)
OM.UAVs[i] = UNWRAP(WrappedID3D11UnorderedAccessView1, OM.UAVs[i]);
}
~Tex2DMSToArrayStateTracker()
{
ID3D11DeviceContext *context = m_WrappedContext->GetReal();
ID3D11DeviceContext1 *context1 = m_WrappedContext->GetReal1();
context->IASetInputLayout(Layout);
context->VSSetShader((ID3D11VertexShader *)VS.Shader, VS.Instances, VS.NumInstances);
context->PSSetShaderResources(0, 16, PS.SRVs);
context->PSSetShader((ID3D11PixelShader *)PS.Shader, PS.Instances, PS.NumInstances);
if(m_WrappedContext->IsFL11_1())
context1->PSSetConstantBuffers1(0, 1, PS.ConstantBuffers, PS.CBOffsets, PS.CBCounts);
else
context->PSSetConstantBuffers(0, 1, PS.ConstantBuffers);
UINT UAV_keepcounts[D3D11_1_UAV_SLOT_COUNT] = {(UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1,
(UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1};
if(m_WrappedContext->IsFL11_1())
context->CSSetUnorderedAccessViews(0, D3D11_1_UAV_SLOT_COUNT, CSUAVs, UAV_keepcounts);
else
context->CSSetUnorderedAccessViews(0, D3D11_PS_CS_UAV_REGISTER_COUNT, CSUAVs, UAV_keepcounts);
context->RSSetState(RS.State);
context->RSSetViewports(RS.NumViews, RS.Viewports);
context->OMSetBlendState(OM.BlendState, OM.BlendFactor, OM.SampleMask);
context->OMSetDepthStencilState(OM.DepthStencilState, OM.StencRef);
if(m_WrappedContext->IsFL11_1())
context->OMSetRenderTargetsAndUnorderedAccessViews(
OM.UAVStartSlot, OM.RenderTargets, OM.DepthView, OM.UAVStartSlot,
D3D11_1_UAV_SLOT_COUNT - OM.UAVStartSlot, OM.UAVs, UAV_keepcounts);
else
context->OMSetRenderTargetsAndUnorderedAccessViews(
OM.UAVStartSlot, OM.RenderTargets, OM.DepthView, OM.UAVStartSlot,
D3D11_PS_CS_UAV_REGISTER_COUNT - OM.UAVStartSlot, OM.UAVs, UAV_keepcounts);
}
WrappedID3D11DeviceContext *m_WrappedContext;
ID3D11InputLayout *Layout;
struct shader
{
ID3D11DeviceChild *Shader;
ID3D11Buffer *ConstantBuffers[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT];
UINT CBOffsets[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT];
UINT CBCounts[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT];
ID3D11ShaderResourceView *SRVs[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT];
ID3D11SamplerState *Samplers[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT];
ID3D11ClassInstance *Instances[D3D11_SHADER_MAX_INTERFACES];
UINT NumInstances;
bool Used_CB(uint32_t slot) const;
bool Used_SRV(uint32_t slot) const;
bool Used_UAV(uint32_t slot) const;
} VS, PS;
ID3D11UnorderedAccessView *CSUAVs[D3D11_1_UAV_SLOT_COUNT];
struct rasterizer
{
UINT NumViews, NumScissors;
D3D11_VIEWPORT Viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
D3D11_RECT Scissors[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
ID3D11RasterizerState *State;
} RS;
struct outmerger
{
ID3D11DepthStencilState *DepthStencilState;
UINT StencRef;
ID3D11BlendState *BlendState;
FLOAT BlendFactor[4];
UINT SampleMask;
ID3D11DepthStencilView *DepthView;
ID3D11RenderTargetView *RenderTargets[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT];
UINT UAVStartSlot;
ID3D11UnorderedAccessView *UAVs[D3D11_1_UAV_SLOT_COUNT];
} OM;
};
void D3D11DebugManager::CopyArrayToTex2DMS(ID3D11Texture2D *destMS, ID3D11Texture2D *srcArray,
UINT selectedSlice)
{
if(!CopyArrayToMSPS)
{
RDCWARN("Can't copy array to MSAA texture, contents will be undefined.");
return;
}
bool singleSliceMode = (selectedSlice != ~0U);
D3D11MarkerRegion copy("CopyArrayToTex2DMS");
// unlike CopyTex2DMSToArray we can use the wrapped context here, but for consistency
// we accept unwrapped parameters.
D3D11RenderStateTracker tracker(m_pImmediateContext);
// copy to textures with right bind flags for operation
D3D11_TEXTURE2D_DESC descArr;
srcArray->GetDesc(&descArr);
D3D11_TEXTURE2D_DESC descMS;
destMS->GetDesc(&descMS);
UINT sampleMask = ~0U;
if(singleSliceMode)
{
sampleMask = 1U << (selectedSlice % descMS.SampleDesc.Count);
selectedSlice /= descMS.SampleDesc.Count;
}
bool depthFormat = IsDepthFormat(descMS.Format);
bool intFormat =
IsUIntFormat(descMS.Format) || IsIntFormat(descMS.Format) || IsTypelessFormat(descMS.Format);
ID3D11Texture2D *rtvResource = NULL;
ID3D11Texture2D *srvResource = NULL;
D3D11_TEXTURE2D_DESC rtvResDesc = descMS;
D3D11_TEXTURE2D_DESC srvResDesc = descArr;
rtvResDesc.BindFlags = depthFormat ? D3D11_BIND_DEPTH_STENCIL : D3D11_BIND_RENDER_TARGET;
srvResDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
if(depthFormat)
{
rtvResDesc.Format = GetTypelessFormat(rtvResDesc.Format);
srvResDesc.Format = GetTypelessFormat(srvResDesc.Format);
}
rtvResDesc.Usage = D3D11_USAGE_DEFAULT;
srvResDesc.Usage = D3D11_USAGE_DEFAULT;
rtvResDesc.CPUAccessFlags = 0;
srvResDesc.CPUAccessFlags = 0;
HRESULT hr = S_OK;
hr = m_pDevice->CreateTexture2D(&rtvResDesc, NULL, &rtvResource);
if(FAILED(hr))
{
RDCERR("0xHRESULT: %s", ToStr(hr).c_str());
return;
}
hr = m_pDevice->CreateTexture2D(&srvResDesc, NULL, &srvResource);
if(FAILED(hr))
{
RDCERR("0xHRESULT: %s", ToStr(hr).c_str());
return;
}
// if we're doing a partial update, need to preserve what was in the destination texture
if(singleSliceMode)
m_pImmediateContext->GetReal()->CopyResource(UNWRAP(WrappedID3D11Texture2D1, rtvResource),
destMS);
m_pImmediateContext->GetReal()->CopyResource(UNWRAP(WrappedID3D11Texture2D1, srvResource),
srcArray);
ID3D11UnorderedAccessView *uavs[D3D11_1_UAV_SLOT_COUNT] = {NULL};
const UINT numUAVs =
m_pImmediateContext->IsFL11_1() ? D3D11_1_UAV_SLOT_COUNT : D3D11_PS_CS_UAV_REGISTER_COUNT;
UINT uavCounts[D3D11_1_UAV_SLOT_COUNT];
memset(&uavCounts[0], 0xff, sizeof(uavCounts));
m_pImmediateContext->CSSetUnorderedAccessViews(0, numUAVs, uavs, uavCounts);
m_pImmediateContext->VSSetShader(MSArrayCopyVS, NULL, 0);
if(depthFormat)
m_pImmediateContext->PSSetShader(DepthCopyArrayToMSPS, NULL, 0);
else if(intFormat)
m_pImmediateContext->PSSetShader(CopyArrayToMSPS, NULL, 0);
else
m_pImmediateContext->PSSetShader(FloatCopyArrayToMSPS, NULL, 0);
m_pImmediateContext->HSSetShader(NULL, NULL, 0);
m_pImmediateContext->DSSetShader(NULL, NULL, 0);
m_pImmediateContext->GSSetShader(NULL, NULL, 0);
D3D11_VIEWPORT view = {0.0f, 0.0f, (float)descArr.Width, (float)descArr.Height, 0.0f, 1.0f};
m_pImmediateContext->RSSetState(NULL);
m_pImmediateContext->RSSetViewports(1, &view);
m_pImmediateContext->IASetInputLayout(NULL);
m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
float blendFactor[] = {1.0f, 1.0f, 1.0f, 1.0f};
m_pImmediateContext->OMSetBlendState(NULL, blendFactor, sampleMask);
{
D3D11_DEPTH_STENCIL_DESC dsDesc;
ID3D11DepthStencilState *dsState = NULL;
RDCEraseEl(dsDesc);
dsDesc.DepthEnable = TRUE;
dsDesc.DepthFunc = D3D11_COMPARISON_ALWAYS;
dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
if(depthFormat)
dsDesc.StencilEnable = FALSE;
else
dsDesc.StencilEnable = TRUE;
dsDesc.BackFace.StencilFailOp = dsDesc.BackFace.StencilPassOp =
dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
dsDesc.FrontFace.StencilFailOp = dsDesc.FrontFace.StencilPassOp =
dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
dsDesc.StencilReadMask = dsDesc.StencilWriteMask = 0xff;
m_pDevice->CreateDepthStencilState(&dsDesc, &dsState);
m_pImmediateContext->OMSetDepthStencilState(dsState, 0);
SAFE_RELEASE(dsState);
}
ID3D11DepthStencilView *dsvMS = NULL;
ID3D11RenderTargetView *rtvMS = NULL;
ID3D11ShaderResourceView *srvArray = NULL;
D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY;
rtvDesc.Format = depthFormat ? GetUIntTypedFormat(descMS.Format)
: GetTypedFormat(descMS.Format, CompType::UInt);
rtvDesc.Texture2DMSArray.ArraySize = descMS.ArraySize;
rtvDesc.Texture2DMSArray.FirstArraySlice = 0;
D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY;
dsvDesc.Flags = 0;
dsvDesc.Format = GetDepthTypedFormat(descMS.Format);
dsvDesc.Texture2DMSArray.ArraySize = descMS.ArraySize;
dsvDesc.Texture2DMSArray.FirstArraySlice = 0;
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
srvDesc.Format = depthFormat ? GetUIntTypedFormat(descArr.Format)
: GetTypedFormat(descArr.Format, CompType::UInt);
srvDesc.Texture2DArray.ArraySize = descArr.ArraySize;
srvDesc.Texture2DArray.FirstArraySlice = 0;
srvDesc.Texture2DArray.MipLevels = descArr.MipLevels;
srvDesc.Texture2DArray.MostDetailedMip = 0;
bool stencil = false;
DXGI_FORMAT stencilFormat = DXGI_FORMAT_UNKNOWN;
if(depthFormat)
{
switch(descArr.Format)
{
case DXGI_FORMAT_D32_FLOAT:
case DXGI_FORMAT_R32_FLOAT:
case DXGI_FORMAT_R32_TYPELESS: srvDesc.Format = DXGI_FORMAT_R32_FLOAT; break;
case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
case DXGI_FORMAT_R32G8X24_TYPELESS:
case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
srvDesc.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
stencilFormat = DXGI_FORMAT_X32_TYPELESS_G8X24_UINT;
stencil = true;
break;
case DXGI_FORMAT_D24_UNORM_S8_UINT:
case DXGI_FORMAT_R24G8_TYPELESS:
case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
srvDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
stencilFormat = DXGI_FORMAT_X24_TYPELESS_G8_UINT;
stencil = true;
break;
case DXGI_FORMAT_D16_UNORM:
case DXGI_FORMAT_R16_TYPELESS: srvDesc.Format = DXGI_FORMAT_R16_UNORM; break;
default: break;
}
}
hr = m_pDevice->CreateShaderResourceView(srvResource, &srvDesc, &srvArray);
if(FAILED(hr))
{
RDCERR("0xHRESULT: %s", ToStr(hr).c_str());
return;
}
ID3D11ShaderResourceView *srvs[10] = {NULL};
srvs[0] = srvArray;
m_pImmediateContext->PSSetShaderResources(1, 10, srvs);
// loop over every array slice in MS texture
for(UINT slice = 0; slice < descMS.ArraySize; slice++)
{
if(singleSliceMode)
slice = selectedSlice;
uint32_t cdata[4] = {descMS.SampleDesc.Count, 1000, 0, slice};
ID3D11Buffer *cbuf = MakeCBuffer(cdata, sizeof(cdata));
m_pImmediateContext->PSSetConstantBuffers(0, 1, &cbuf);
rtvDesc.Texture2DMSArray.FirstArraySlice = slice;
rtvDesc.Texture2DMSArray.ArraySize = 1;
dsvDesc.Texture2DMSArray.FirstArraySlice = slice;
dsvDesc.Texture2DMSArray.ArraySize = 1;
if(depthFormat)
hr = m_pDevice->CreateDepthStencilView(rtvResource, &dsvDesc, &dsvMS);
else
hr = m_pDevice->CreateRenderTargetView(rtvResource, &rtvDesc, &rtvMS);
if(FAILED(hr))
{
SAFE_RELEASE(srvArray);
RDCERR("0xHRESULT: %s", ToStr(hr).c_str());
return;
}
if(depthFormat)
m_pImmediateContext->OMSetRenderTargetsAndUnorderedAccessViews(0, NULL, dsvMS, 0, 0, NULL,
NULL);
else
m_pImmediateContext->OMSetRenderTargetsAndUnorderedAccessViews(1, &rtvMS, NULL, 0, 0, NULL,
NULL);
m_pImmediateContext->Draw(3, 0);
SAFE_RELEASE(rtvMS);
SAFE_RELEASE(dsvMS);
if(singleSliceMode)
break;
}
SAFE_RELEASE(srvArray);
if(stencil)
{
srvDesc.Format = stencilFormat;
hr = m_pDevice->CreateShaderResourceView(srvResource, &srvDesc, &srvArray);
if(FAILED(hr))
{
RDCERR("0xHRESULT: %s", ToStr(hr).c_str());
return;
}
m_pImmediateContext->PSSetShaderResources(11, 1, &srvArray);
D3D11_DEPTH_STENCIL_DESC dsDesc;
ID3D11DepthStencilState *dsState = NULL;
RDCEraseEl(dsDesc);
dsDesc.DepthEnable = FALSE;
dsDesc.DepthFunc = D3D11_COMPARISON_ALWAYS;
dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
dsDesc.StencilEnable = TRUE;
dsDesc.BackFace.StencilFailOp = dsDesc.BackFace.StencilPassOp =
dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE;
dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
dsDesc.FrontFace.StencilFailOp = dsDesc.FrontFace.StencilPassOp =
dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE;
dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
dsDesc.StencilReadMask = dsDesc.StencilWriteMask = 0xff;
dsvDesc.Flags = D3D11_DSV_READ_ONLY_DEPTH;
dsvDesc.Texture2DArray.ArraySize = 1;
m_pDevice->CreateDepthStencilState(&dsDesc, &dsState);
// loop over every array slice in MS texture
for(UINT slice = 0; slice < descMS.ArraySize; slice++)
{
if(singleSliceMode)
slice = selectedSlice;
dsvDesc.Texture2DMSArray.FirstArraySlice = slice;
hr = m_pDevice->CreateDepthStencilView(rtvResource, &dsvDesc, &dsvMS);
if(FAILED(hr))
{
SAFE_RELEASE(srvArray);
SAFE_RELEASE(dsState);
RDCERR("0xHRESULT: %s", ToStr(hr).c_str());
return;
}
m_pImmediateContext->OMSetRenderTargetsAndUnorderedAccessViews(0, NULL, dsvMS, 0, 0, NULL,
NULL);
// loop over every stencil value (zzzzzz, no shader stencil read/write)
for(UINT stencilval = 0; stencilval < 256; stencilval++)
{
uint32_t cdata[4] = {descMS.SampleDesc.Count, stencilval, 0, slice};
ID3D11Buffer *cbuf = MakeCBuffer(cdata, sizeof(cdata));
m_pImmediateContext->PSSetConstantBuffers(0, 1, &cbuf);
m_pImmediateContext->OMSetDepthStencilState(dsState, stencilval);
m_pImmediateContext->Draw(3, 0);
}
SAFE_RELEASE(dsvMS);
m_pImmediateContext->Flush();
if(singleSliceMode)
break;
}
SAFE_RELEASE(srvArray);
SAFE_RELEASE(dsState);
}
m_pImmediateContext->GetReal()->CopyResource(destMS, UNWRAP(WrappedID3D11Texture2D1, rtvResource));
SAFE_RELEASE(rtvResource);
SAFE_RELEASE(srvResource);
}
void D3D11DebugManager::CopyTex2DMSToArray(ID3D11Texture2D *destArray, ID3D11Texture2D *srcMS)
{
if(!CopyMSToArrayPS)
{
RDCWARN("Can't copy array to MSAA texture, contents will be undefined.");
return;
}
// we have to use exclusively the unwrapped context here as this might be happening during
// capture and we don't want to serialise any of this work, and the parameters might not exist
// as wrapped objects for that reason
// use the wrapped context's state tracked to avoid needing our own tracking, just restore it to
// the unwrapped context
Tex2DMSToArrayStateTracker tracker(m_pImmediateContext);
D3D11MarkerRegion copy("CopyTex2DMSToArray");
ID3D11Device *dev = m_pDevice->GetReal();
ID3D11DeviceContext *ctx = m_pImmediateContext->GetReal();
// copy to textures with right bind flags for operation
D3D11_TEXTURE2D_DESC descMS;
srcMS->GetDesc(&descMS);
D3D11_TEXTURE2D_DESC descArr;
destArray->GetDesc(&descArr);
ID3D11Texture2D *rtvResource = NULL;
ID3D11Texture2D *srvResource = NULL;
D3D11_TEXTURE2D_DESC rtvResDesc = descArr;
D3D11_TEXTURE2D_DESC srvResDesc = descMS;
bool depthFormat = IsDepthFormat(descMS.Format);
bool intFormat =
IsUIntFormat(descMS.Format) || IsIntFormat(descMS.Format) || IsTypelessFormat(descMS.Format);
rtvResDesc.BindFlags = depthFormat ? D3D11_BIND_DEPTH_STENCIL : D3D11_BIND_RENDER_TARGET;
srvResDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
if(depthFormat)
{
rtvResDesc.Format = GetTypelessFormat(rtvResDesc.Format);
srvResDesc.Format = GetTypelessFormat(srvResDesc.Format);
}
rtvResDesc.Usage = D3D11_USAGE_DEFAULT;
srvResDesc.Usage = D3D11_USAGE_DEFAULT;
rtvResDesc.CPUAccessFlags = 0;
srvResDesc.CPUAccessFlags = 0;
HRESULT hr = S_OK;
hr = dev->CreateTexture2D(&rtvResDesc, NULL, &rtvResource);
if(FAILED(hr))
{
RDCERR("0xHRESULT: %s", ToStr(hr).c_str());
return;
}
hr = dev->CreateTexture2D(&srvResDesc, NULL, &srvResource);
if(FAILED(hr))
{
RDCERR("0xHRESULT: %s", ToStr(hr).c_str());
return;
}
ctx->CopyResource(srvResource, srcMS);
ID3D11UnorderedAccessView *uavs[D3D11_1_UAV_SLOT_COUNT] = {NULL};
UINT uavCounts[D3D11_1_UAV_SLOT_COUNT];
memset(&uavCounts[0], 0xff, sizeof(uavCounts));
const UINT numUAVs =
m_pImmediateContext->IsFL11_1() ? D3D11_1_UAV_SLOT_COUNT : D3D11_PS_CS_UAV_REGISTER_COUNT;
ctx->CSSetUnorderedAccessViews(0, numUAVs, uavs, uavCounts);
ctx->VSSetShader(UNWRAP(WrappedID3D11Shader<ID3D11VertexShader>, MSArrayCopyVS), NULL, 0);
if(depthFormat)
ctx->PSSetShader(UNWRAP(WrappedID3D11Shader<ID3D11PixelShader>, DepthCopyMSToArrayPS), NULL, 0);
else if(intFormat)
ctx->PSSetShader(UNWRAP(WrappedID3D11Shader<ID3D11PixelShader>, CopyMSToArrayPS), NULL, 0);
else
ctx->PSSetShader(UNWRAP(WrappedID3D11Shader<ID3D11PixelShader>, FloatCopyMSToArrayPS), NULL, 0);
D3D11_VIEWPORT view = {0.0f, 0.0f, (float)descArr.Width, (float)descArr.Height, 0.0f, 1.0f};
ctx->RSSetState(NULL);
ctx->RSSetViewports(1, &view);
ctx->IASetInputLayout(NULL);
ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
float blendFactor[] = {1.0f, 1.0f, 1.0f, 1.0f};
ctx->OMSetBlendState(NULL, blendFactor, ~0U);
{
D3D11_DEPTH_STENCIL_DESC dsDesc;
ID3D11DepthStencilState *dsState = NULL;
RDCEraseEl(dsDesc);
dsDesc.DepthEnable = TRUE;
dsDesc.DepthFunc = D3D11_COMPARISON_ALWAYS;
dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
if(depthFormat)
dsDesc.StencilEnable = FALSE;
else
dsDesc.StencilEnable = TRUE;
dsDesc.BackFace.StencilFailOp = dsDesc.BackFace.StencilPassOp =
dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
dsDesc.FrontFace.StencilFailOp = dsDesc.FrontFace.StencilPassOp =
dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
dsDesc.StencilReadMask = dsDesc.StencilWriteMask = 0xff;
dev->CreateDepthStencilState(&dsDesc, &dsState);
ctx->OMSetDepthStencilState(dsState, 0);
SAFE_RELEASE(dsState);
}
ID3D11RenderTargetView *rtvArray = NULL;
ID3D11DepthStencilView *dsvArray = NULL;
ID3D11ShaderResourceView *srvMS = NULL;
D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
rtvDesc.Format = depthFormat ? GetUIntTypedFormat(descArr.Format)
: GetTypedFormat(descArr.Format, CompType::UInt);
rtvDesc.Texture2DArray.FirstArraySlice = 0;
rtvDesc.Texture2DArray.ArraySize = 1;
rtvDesc.Texture2DArray.MipSlice = 0;
D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
dsvDesc.Format = GetDepthTypedFormat(descArr.Format);
dsvDesc.Flags = 0;
dsvDesc.Texture2DArray.FirstArraySlice = 0;
dsvDesc.Texture2DArray.ArraySize = 1;
dsvDesc.Texture2DArray.MipSlice = 0;
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY;
srvDesc.Format = depthFormat ? GetUIntTypedFormat(descMS.Format)
: GetTypedFormat(descMS.Format, CompType::UInt);
srvDesc.Texture2DMSArray.ArraySize = descMS.ArraySize;
srvDesc.Texture2DMSArray.FirstArraySlice = 0;
bool stencil = false;
DXGI_FORMAT stencilFormat = DXGI_FORMAT_UNKNOWN;
if(depthFormat)
{
switch(descMS.Format)
{
case DXGI_FORMAT_D32_FLOAT:
case DXGI_FORMAT_R32_FLOAT:
case DXGI_FORMAT_R32_TYPELESS: srvDesc.Format = DXGI_FORMAT_R32_FLOAT; break;
case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
case DXGI_FORMAT_R32G8X24_TYPELESS:
case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
srvDesc.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
stencilFormat = DXGI_FORMAT_X32_TYPELESS_G8X24_UINT;
stencil = true;
break;
case DXGI_FORMAT_D24_UNORM_S8_UINT:
case DXGI_FORMAT_R24G8_TYPELESS:
case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
srvDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
stencilFormat = DXGI_FORMAT_X24_TYPELESS_G8_UINT;
stencil = true;
break;
case DXGI_FORMAT_D16_UNORM:
case DXGI_FORMAT_R16_TYPELESS: srvDesc.Format = DXGI_FORMAT_R16_UNORM; break;
default: break;
}
}
hr = dev->CreateShaderResourceView(srvResource, &srvDesc, &srvMS);
if(FAILED(hr))
{
RDCERR("0xHRESULT: %s", ToStr(hr).c_str());
return;
}
ID3D11ShaderResourceView *srvs[16] = {NULL};
int srvIndex = 0;
for(int i = 0; i < 8; i++)
if(descMS.SampleDesc.Count == UINT(1 << i))
srvIndex = i;
srvs[srvIndex] = srvMS;
ctx->PSSetShaderResources(0, 16, srvs);
// loop over every array slice in MS texture
for(UINT slice = 0; slice < descMS.ArraySize; slice++)
{
// loop over every multi sample
for(UINT sample = 0; sample < descMS.SampleDesc.Count; sample++)
{
uint32_t cdata[4] = {descMS.SampleDesc.Count, 1000, sample, slice};
ID3D11Buffer *cbuf = UNWRAP(WrappedID3D11Buffer, MakeCBuffer(cdata, sizeof(cdata)));
ctx->PSSetConstantBuffers(0, 1, &cbuf);
rtvDesc.Texture2DArray.FirstArraySlice = slice * descMS.SampleDesc.Count + sample;
dsvDesc.Texture2DArray.FirstArraySlice = slice * descMS.SampleDesc.Count + sample;
if(depthFormat)
hr = dev->CreateDepthStencilView(rtvResource, &dsvDesc, &dsvArray);
else
hr = dev->CreateRenderTargetView(rtvResource, &rtvDesc, &rtvArray);
if(FAILED(hr))
{
SAFE_RELEASE(rtvArray);
SAFE_RELEASE(dsvArray);
RDCERR("0xHRESULT: %s", ToStr(hr).c_str());
return;
}
if(depthFormat)
ctx->OMSetRenderTargetsAndUnorderedAccessViews(0, NULL, dsvArray, 0, 0, NULL, NULL);
else
ctx->OMSetRenderTargetsAndUnorderedAccessViews(1, &rtvArray, NULL, 0, 0, NULL, NULL);
ctx->Draw(3, 0);
SAFE_RELEASE(rtvArray);
SAFE_RELEASE(dsvArray);
ctx->Flush();
}
}
SAFE_RELEASE(srvMS);
if(stencil)
{
srvDesc.Format = stencilFormat;
hr = dev->CreateShaderResourceView(srvResource, &srvDesc, &srvMS);
if(FAILED(hr))
{
RDCERR("0xHRESULT: %s", ToStr(hr).c_str());
return;
}
ctx->PSSetShaderResources(10 + srvIndex, 1, &srvMS);
D3D11_DEPTH_STENCIL_DESC dsDesc;
ID3D11DepthStencilState *dsState = NULL;
RDCEraseEl(dsDesc);
dsDesc.DepthEnable = FALSE;
dsDesc.DepthFunc = D3D11_COMPARISON_ALWAYS;
dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
dsDesc.StencilEnable = TRUE;
dsDesc.BackFace.StencilFailOp = dsDesc.BackFace.StencilPassOp =
dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE;
dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
dsDesc.FrontFace.StencilFailOp = dsDesc.FrontFace.StencilPassOp =
dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE;
dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
dsDesc.StencilReadMask = dsDesc.StencilWriteMask = 0xff;
dsvDesc.Flags = D3D11_DSV_READ_ONLY_DEPTH;
dsvDesc.Texture2DArray.ArraySize = 1;
dev->CreateDepthStencilState(&dsDesc, &dsState);
// loop over every array slice in MS texture
for(UINT slice = 0; slice < descMS.ArraySize; slice++)
{
// loop over every multi sample
for(UINT sample = 0; sample < descMS.SampleDesc.Count; sample++)
{
dsvDesc.Texture2DArray.FirstArraySlice = slice * descMS.SampleDesc.Count + sample;
hr = dev->CreateDepthStencilView(rtvResource, &dsvDesc, &dsvArray);
if(FAILED(hr))
{
SAFE_RELEASE(dsState);
SAFE_RELEASE(srvMS);
RDCERR("0xHRESULT: %s", ToStr(hr).c_str());
return;
}
ctx->OMSetRenderTargetsAndUnorderedAccessViews(0, NULL, dsvArray, 0, 0, NULL, NULL);
// loop over every stencil value (zzzzzz, no shader stencil read/write)
for(UINT stencilval = 0; stencilval < 256; stencilval++)
{
uint32_t cdata[4] = {descMS.SampleDesc.Count, stencilval, sample, slice};
ID3D11Buffer *cbuf = UNWRAP(WrappedID3D11Buffer, MakeCBuffer(cdata, sizeof(cdata)));
ctx->PSSetConstantBuffers(0, 1, &cbuf);
ctx->OMSetDepthStencilState(dsState, stencilval);
ctx->Draw(3, 0);
}
ctx->Flush();
SAFE_RELEASE(dsvArray);
}
}
SAFE_RELEASE(dsState);
SAFE_RELEASE(srvMS);
}
ctx->CopyResource(destArray, rtvResource);
SAFE_RELEASE(rtvResource);
SAFE_RELEASE(srvResource);
}