mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-07-08 08:40:55 +00:00
2003 lines
68 KiB
C++
2003 lines
68 KiB
C++
/******************************************************************************
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2019-2024 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 "d3d12_common.h"
|
|
#include "driver/dxgi/dxgi_common.h"
|
|
#include "driver/dxgi/dxgi_wrapped.h"
|
|
#include "d3d12_manager.h"
|
|
#include "d3d12_resources.h"
|
|
|
|
D3D12MarkerRegion::D3D12MarkerRegion(ID3D12GraphicsCommandList *l, const rdcstr &marker)
|
|
{
|
|
list = l;
|
|
queue = NULL;
|
|
|
|
D3D12MarkerRegion::Begin(list, marker);
|
|
}
|
|
|
|
D3D12MarkerRegion::D3D12MarkerRegion(ID3D12CommandQueue *q, const rdcstr &marker)
|
|
{
|
|
list = NULL;
|
|
queue = q;
|
|
|
|
D3D12MarkerRegion::Begin(queue, marker);
|
|
}
|
|
|
|
D3D12MarkerRegion::~D3D12MarkerRegion()
|
|
{
|
|
if(list)
|
|
D3D12MarkerRegion::End(list);
|
|
if(queue)
|
|
D3D12MarkerRegion::End(queue);
|
|
}
|
|
|
|
void D3D12MarkerRegion::Begin(ID3D12GraphicsCommandList *list, const rdcstr &marker)
|
|
{
|
|
if(list)
|
|
{
|
|
// Some debuggers (but not all) will assume the event string is null-terminated, and
|
|
// display one less character than specified by the size. Append a space to pad the
|
|
// output without visibly changing the event marker for other debuggers.
|
|
rdcwstr text = StringFormat::UTF82Wide(marker + " ");
|
|
UINT size = UINT(text.length() * sizeof(wchar_t));
|
|
list->BeginEvent(0, text.c_str(), size);
|
|
}
|
|
}
|
|
|
|
void D3D12MarkerRegion::Begin(ID3D12CommandQueue *queue, const rdcstr &marker)
|
|
{
|
|
if(queue)
|
|
{
|
|
rdcwstr text = StringFormat::UTF82Wide(marker + " ");
|
|
UINT size = UINT(text.length() * sizeof(wchar_t));
|
|
queue->BeginEvent(0, text.c_str(), size);
|
|
}
|
|
}
|
|
|
|
void D3D12MarkerRegion::Set(ID3D12GraphicsCommandList *list, const rdcstr &marker)
|
|
{
|
|
if(list)
|
|
{
|
|
rdcwstr text = StringFormat::UTF82Wide(marker + " ");
|
|
UINT size = UINT(text.length() * sizeof(wchar_t));
|
|
list->SetMarker(0, text.c_str(), size);
|
|
}
|
|
}
|
|
|
|
void D3D12MarkerRegion::Set(ID3D12CommandQueue *queue, const rdcstr &marker)
|
|
{
|
|
if(queue)
|
|
{
|
|
rdcwstr text = StringFormat::UTF82Wide(marker + " ");
|
|
UINT size = UINT(text.length() * sizeof(wchar_t));
|
|
queue->SetMarker(0, text.c_str(), size);
|
|
}
|
|
}
|
|
|
|
void D3D12MarkerRegion::End(ID3D12GraphicsCommandList *list)
|
|
{
|
|
list->EndEvent();
|
|
}
|
|
|
|
void D3D12MarkerRegion::End(ID3D12CommandQueue *queue)
|
|
{
|
|
queue->EndEvent();
|
|
}
|
|
|
|
void BarrierSet::Configure(ID3D12Resource *res, const SubresourceStateVector &states,
|
|
AccessType access)
|
|
{
|
|
bool allowCommon = false;
|
|
D3D12_RESOURCE_STATES resourceState;
|
|
D3D12_BARRIER_LAYOUT resourceLayout;
|
|
D3D12_BARRIER_ACCESS resourceAccess;
|
|
D3D12_BARRIER_SYNC resourceSync;
|
|
|
|
// we assume wrapped resources
|
|
RDCASSERT(WrappedID3D12Resource::IsAlloc(res));
|
|
|
|
const bool isBuffer = (res->GetDesc().Dimension == D3D12_RESOURCE_DIMENSION_BUFFER);
|
|
|
|
switch(access)
|
|
{
|
|
case SRVAccess:
|
|
resourceState = D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE;
|
|
resourceLayout = D3D12_BARRIER_LAYOUT_SHADER_RESOURCE;
|
|
resourceAccess = D3D12_BARRIER_ACCESS_SHADER_RESOURCE;
|
|
resourceSync = D3D12_BARRIER_SYNC_ALL_SHADING;
|
|
// common layouts allow shader resource access with no layout change
|
|
allowCommon = true;
|
|
break;
|
|
case ResolveSourceAccess:
|
|
resourceState = D3D12_RESOURCE_STATE_RESOLVE_SOURCE;
|
|
resourceLayout = D3D12_BARRIER_LAYOUT_RESOLVE_SOURCE;
|
|
resourceAccess = D3D12_BARRIER_ACCESS_RESOLVE_SOURCE;
|
|
resourceSync = D3D12_BARRIER_SYNC_RESOLVE;
|
|
break;
|
|
default:
|
|
// should not happen but is the neatest solution to uninitialised variable warnings
|
|
case CopySourceAccess:
|
|
resourceState = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
|
resourceLayout = D3D12_BARRIER_LAYOUT_COPY_SOURCE;
|
|
resourceAccess = D3D12_BARRIER_ACCESS_COPY_SOURCE;
|
|
resourceSync = D3D12_BARRIER_SYNC_COPY;
|
|
// common layouts allow shader resource access with no layout change
|
|
allowCommon = true;
|
|
break;
|
|
case CopyDestAccess:
|
|
resourceState = D3D12_RESOURCE_STATE_COPY_DEST;
|
|
resourceLayout = D3D12_BARRIER_LAYOUT_COPY_DEST;
|
|
resourceAccess = D3D12_BARRIER_ACCESS_COPY_DEST;
|
|
resourceSync = D3D12_BARRIER_SYNC_COPY;
|
|
// common layouts allow shader resource access with no layout change
|
|
allowCommon = true;
|
|
break;
|
|
}
|
|
|
|
barriers.reserve(states.size());
|
|
newBarriers.reserve(states.size());
|
|
for(size_t i = 0; i < states.size(); i++)
|
|
{
|
|
if(states[i].IsStates())
|
|
{
|
|
D3D12_RESOURCE_BARRIER b;
|
|
|
|
b.Transition.StateBefore = states[i].ToStates();
|
|
|
|
// skip unneeded barriers
|
|
if((resourceState != D3D12_RESOURCE_STATE_COMMON &&
|
|
(b.Transition.StateBefore & resourceState) == resourceState) ||
|
|
b.Transition.StateBefore == resourceState)
|
|
continue;
|
|
|
|
b.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
b.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
b.Transition.pResource = res;
|
|
b.Transition.Subresource = (UINT)i;
|
|
b.Transition.StateAfter = resourceState;
|
|
|
|
barriers.push_back(b);
|
|
}
|
|
// buffers don't need any transitions with the new layouts
|
|
else if(!isBuffer)
|
|
{
|
|
D3D12_TEXTURE_BARRIER b = {};
|
|
|
|
b.LayoutBefore = states[i].ToLayout();
|
|
|
|
// as long as the layout matches we don't need any extra access/sync since we're in a
|
|
// different command buffer.
|
|
if(b.LayoutBefore == resourceLayout ||
|
|
(allowCommon && (b.LayoutBefore == D3D12_BARRIER_LAYOUT_COMMON ||
|
|
b.LayoutBefore == D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COMMON ||
|
|
b.LayoutBefore == D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_COMMON)))
|
|
continue;
|
|
|
|
b.AccessBefore = D3D12_BARRIER_ACCESS_COMMON;
|
|
b.SyncBefore = D3D12_BARRIER_SYNC_ALL;
|
|
|
|
if(b.LayoutBefore == D3D12_BARRIER_LAYOUT_UNDEFINED)
|
|
b.AccessBefore = D3D12_BARRIER_ACCESS_NO_ACCESS;
|
|
|
|
b.AccessAfter = resourceAccess;
|
|
b.SyncAfter = resourceSync;
|
|
b.LayoutAfter = resourceLayout;
|
|
b.Flags = D3D12_TEXTURE_BARRIER_FLAG_NONE;
|
|
b.Subresources.IndexOrFirstMipLevel = (UINT)i;
|
|
b.pResource = res;
|
|
|
|
newBarriers.push_back(b);
|
|
}
|
|
}
|
|
}
|
|
|
|
void BarrierSet::Apply(ID3D12GraphicsCommandListX *list)
|
|
{
|
|
D3D12_BARRIER_GROUP group;
|
|
group.NumBarriers = (UINT)newBarriers.size();
|
|
group.Type = D3D12_BARRIER_TYPE_TEXTURE;
|
|
group.pTextureBarriers = newBarriers.data();
|
|
|
|
if(!barriers.empty())
|
|
list->ResourceBarrier((UINT)barriers.size(), &barriers[0]);
|
|
// we unconditionally call new barriers, because they can only appear if a new layout was
|
|
// previously used (otherwise we stick to old states). This will only break if we're replaying
|
|
// a capture that used new layouts but new barrier support isn't present.
|
|
if(!newBarriers.empty())
|
|
list->Barrier(1, &group);
|
|
if(!newToOldBarriers.empty())
|
|
list->ResourceBarrier((UINT)newToOldBarriers.size(), &newToOldBarriers[0]);
|
|
}
|
|
|
|
void BarrierSet::Unapply(ID3D12GraphicsCommandListX *list)
|
|
{
|
|
D3D12_BARRIER_GROUP group;
|
|
group.NumBarriers = (UINT)newBarriers.size();
|
|
group.Type = D3D12_BARRIER_TYPE_TEXTURE;
|
|
group.pTextureBarriers = newBarriers.data();
|
|
|
|
// real resource back to itself
|
|
for(size_t i = 0; i < barriers.size(); i++)
|
|
std::swap(barriers[i].Transition.StateBefore, barriers[i].Transition.StateAfter);
|
|
for(size_t i = 0; i < newBarriers.size(); i++)
|
|
{
|
|
std::swap(newBarriers[i].AccessBefore, newBarriers[i].AccessAfter);
|
|
std::swap(newBarriers[i].SyncBefore, newBarriers[i].SyncAfter);
|
|
std::swap(newBarriers[i].LayoutBefore, newBarriers[i].LayoutAfter);
|
|
}
|
|
|
|
if(!barriers.empty())
|
|
list->ResourceBarrier((UINT)barriers.size(), &barriers[0]);
|
|
if(!newBarriers.empty())
|
|
list->Barrier(1, &group);
|
|
// if we had new-to-old barriers we should not ever be unapplying that barrier set as it's
|
|
// one-way.
|
|
RDCASSERT(newToOldBarriers.empty());
|
|
}
|
|
|
|
bool EnableD3D12DebugLayer(D3D12DevConfiguration *devConfig,
|
|
PFN_D3D12_GET_DEBUG_INTERFACE getDebugInterface)
|
|
{
|
|
ID3D12Debug *debug = NULL;
|
|
if(devConfig)
|
|
{
|
|
if(devConfig->debug)
|
|
{
|
|
debug = devConfig->debug;
|
|
debug->AddRef();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(!getDebugInterface)
|
|
getDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress(
|
|
GetModuleHandleA("d3d12.dll"), "D3D12GetDebugInterface");
|
|
|
|
if(!getDebugInterface)
|
|
{
|
|
RDCERR("Couldn't find D3D12GetDebugInterface!");
|
|
return false;
|
|
}
|
|
|
|
HRESULT hr = getDebugInterface(__uuidof(ID3D12Debug), (void **)&debug);
|
|
|
|
if(FAILED(hr))
|
|
SAFE_RELEASE(debug);
|
|
|
|
if(hr == DXGI_ERROR_SDK_COMPONENT_MISSING)
|
|
{
|
|
RDCWARN("Debug layer not available: DXGI_ERROR_SDK_COMPONENT_MISSING");
|
|
}
|
|
else if(FAILED(hr))
|
|
{
|
|
RDCERR("Couldn't enable debug layer: %x", hr);
|
|
}
|
|
}
|
|
|
|
if(debug)
|
|
{
|
|
debug->EnableDebugLayer();
|
|
|
|
RDCDEBUG("Enabling debug layer");
|
|
|
|
// enable this to get GPU-based validation, where available, whenever we enable API validation
|
|
#if 0
|
|
ID3D12Debug1 *debug1 = NULL;
|
|
hr = debug->QueryInterface(__uuidof(ID3D12Debug1), (void **)&debug1);
|
|
|
|
if(SUCCEEDED(hr) && debug1)
|
|
{
|
|
RDCDEBUG("Enabling GPU-based validation");
|
|
debug1->SetEnableGPUBasedValidation(true);
|
|
SAFE_RELEASE(debug1);
|
|
}
|
|
else
|
|
{
|
|
RDCDEBUG("GPU-based validation not available");
|
|
}
|
|
#endif
|
|
|
|
SAFE_RELEASE(debug);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
HRESULT EnumAdapterByLuid(IDXGIFactory1 *factory, LUID luid, IDXGIAdapter **pAdapter)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
*pAdapter = NULL;
|
|
|
|
for(UINT i = 0; i < 10; i++)
|
|
{
|
|
IDXGIAdapter *adapter = NULL;
|
|
hr = factory->EnumAdapters(i, &adapter);
|
|
if(hr == S_OK && adapter)
|
|
{
|
|
DXGI_ADAPTER_DESC desc;
|
|
adapter->GetDesc(&desc);
|
|
|
|
if(desc.AdapterLuid.LowPart == luid.LowPart && desc.AdapterLuid.HighPart == luid.HighPart)
|
|
{
|
|
*pAdapter = adapter;
|
|
return S_OK;
|
|
}
|
|
|
|
adapter->Release();
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
bool D3D12InitParams::IsSupportedVersion(uint64_t ver)
|
|
{
|
|
if(ver == CurrentVersion)
|
|
return true;
|
|
|
|
// 0x4 -> 0x5 - CPU_DESCRIPTOR_HANDLE serialised inline as D3D12Descriptor in appropriate
|
|
// list-recording functions
|
|
if(ver == 0x4)
|
|
return true;
|
|
|
|
// 0x5 -> 0x6 - Multiply by number of planes in format when serialising initial states -
|
|
// i.e. stencil is saved with depth in initial states.
|
|
if(ver == 0x5)
|
|
return true;
|
|
|
|
// 0x6 -> 0x7 - Fixed serialisation of D3D12_WRITEBUFFERIMMEDIATE_PARAMETER to properly replay the
|
|
// GPU address
|
|
if(ver == 0x6)
|
|
return true;
|
|
|
|
// 0x7 -> 0x8 - Added serialisation of adapter descriptor in D3D12InitParams
|
|
if(ver == 0x7)
|
|
return true;
|
|
|
|
// 0x8 -> 0x9 - Added serialisation of usedDXIL in D3D12InitParams
|
|
if(ver == 0x8)
|
|
return true;
|
|
|
|
// 0x9 -> 0xA - Added serialisation of vendor extension use in D3D12InitParams
|
|
if(ver == 0x9)
|
|
return true;
|
|
|
|
// 0xA -> 0xB - Added support for sparse/reserved/tiled resources
|
|
if(ver == 0xA)
|
|
return true;
|
|
|
|
// 0xB -> 0xC - Serialised D3D12 SDK version
|
|
if(ver == 0xB)
|
|
return true;
|
|
|
|
// 0xC -> 0xD - Serialised encoded PIX marker color
|
|
if(ver == 0xC)
|
|
return true;
|
|
|
|
// 0xD -> 0xE - Initial contents of sparse resources only serialise subresources with mapped pages
|
|
if(ver == 0xD)
|
|
return true;
|
|
|
|
// 0xE -> 0xF - Sampler descriptors are now serialised as D3D12_SAMPLER_DESC2 in a backwards
|
|
// compatible manner
|
|
if(ver == 0xE)
|
|
return true;
|
|
|
|
// 0xF -> 0x10 - Expanded PSO desc is serialised with new rasterizer/depth-stencil descs
|
|
if(ver == 0xF)
|
|
return true;
|
|
|
|
// 0x10 -> 0x11 - Expanded PSO desc is serialised with amplification and mesh shader descs
|
|
if(ver == 0x10)
|
|
return true;
|
|
|
|
// 0x11 -> 0x12 - Descriptor heaps serialise the original pointer to their descriptor array for GPU unwrapping
|
|
if(ver == 0x11)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
template <typename SerialiserType>
|
|
void DoSerialise(SerialiserType &ser, D3D12InitParams &el)
|
|
{
|
|
SERIALISE_MEMBER(MinimumFeatureLevel);
|
|
|
|
if(ser.VersionAtLeast(0x8))
|
|
{
|
|
SERIALISE_MEMBER(AdapterDesc);
|
|
}
|
|
else
|
|
{
|
|
RDCEraseEl(el.AdapterDesc);
|
|
}
|
|
|
|
if(ser.VersionAtLeast(0x9))
|
|
{
|
|
SERIALISE_MEMBER(usedDXIL);
|
|
}
|
|
|
|
if(ser.VersionAtLeast(0xA))
|
|
{
|
|
SERIALISE_MEMBER(VendorExtensions);
|
|
SERIALISE_MEMBER(VendorUAV);
|
|
SERIALISE_MEMBER(VendorUAVSpace);
|
|
}
|
|
else
|
|
{
|
|
el.VendorExtensions = GPUVendor::Unknown;
|
|
el.VendorUAV = ~0U;
|
|
el.VendorUAVSpace = ~0U;
|
|
}
|
|
|
|
if(ser.VersionAtLeast(0xC))
|
|
{
|
|
SERIALISE_MEMBER(SDKVersion);
|
|
}
|
|
else
|
|
{
|
|
el.SDKVersion = 0;
|
|
}
|
|
}
|
|
|
|
INSTANTIATE_SERIALISE_TYPE(D3D12InitParams);
|
|
|
|
FloatVector DecodePIXColor(UINT64 Color)
|
|
{
|
|
if((Color & 0xff000000) != 0xff000000)
|
|
{
|
|
// indexed thing, look up our fixed array
|
|
static const uint32_t fixedColors[] = {
|
|
0xffff0000, 0xff0000ff, 0xff00ff00, 0xff00ffff, 0xffff00ff, 0xff008000, 0xff800080,
|
|
0xff00008b, 0xfff08080, 0xff3cb371, 0xffb8860b, 0xffbdb76b, 0xff32cd32, 0xffb03060,
|
|
0xffff8c00, 0xff9400d3, 0xff00fa9a, 0xffdc143c, 0xff00bfff, 0xffadff2f, 0xffda70d6,
|
|
0xffd8bfd8, 0xff1e90ff, 0xffffff54, 0xffff1493, 0xff7b68ee, 0xfffafad2, 0xff2f4f4f,
|
|
0xff556b2f, 0xff8b4513, 0xff483d8b, 0xff5f9ea0,
|
|
};
|
|
|
|
Color = fixedColors[Color % ARRAY_COUNT(fixedColors)];
|
|
}
|
|
|
|
FloatVector ret;
|
|
ret.x = float(((Color >> 16) & 0xff)) / 255.0f;
|
|
ret.y = float(((Color >> 8) & 0xff)) / 255.0f;
|
|
ret.z = float(((Color >> 0) & 0xff)) / 255.0f;
|
|
ret.w = 1.0f;
|
|
|
|
return ret;
|
|
}
|
|
|
|
TextureType MakeTextureDim(D3D12_SRV_DIMENSION dim)
|
|
{
|
|
switch(dim)
|
|
{
|
|
case D3D12_SRV_DIMENSION_UNKNOWN: return TextureType::Unknown;
|
|
case D3D12_SRV_DIMENSION_BUFFER: return TextureType::Buffer;
|
|
case D3D12_SRV_DIMENSION_RAYTRACING_ACCELERATION_STRUCTURE: return TextureType::Buffer;
|
|
case D3D12_SRV_DIMENSION_TEXTURE1D: return TextureType::Texture1D;
|
|
case D3D12_SRV_DIMENSION_TEXTURE1DARRAY: return TextureType::Texture1DArray;
|
|
case D3D12_SRV_DIMENSION_TEXTURE2D: return TextureType::Texture2D;
|
|
case D3D12_SRV_DIMENSION_TEXTURE2DARRAY: return TextureType::Texture2DArray;
|
|
case D3D12_SRV_DIMENSION_TEXTURE2DMS: return TextureType::Texture2DMS;
|
|
case D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY: return TextureType::Texture2DMSArray;
|
|
case D3D12_SRV_DIMENSION_TEXTURE3D: return TextureType::Texture3D;
|
|
case D3D12_SRV_DIMENSION_TEXTURECUBE: return TextureType::TextureCube;
|
|
case D3D12_SRV_DIMENSION_TEXTURECUBEARRAY: return TextureType::TextureCubeArray;
|
|
default: break;
|
|
}
|
|
|
|
return TextureType::Unknown;
|
|
}
|
|
|
|
TextureType MakeTextureDim(D3D12_RTV_DIMENSION dim)
|
|
{
|
|
switch(dim)
|
|
{
|
|
case D3D12_RTV_DIMENSION_UNKNOWN: return TextureType::Unknown;
|
|
case D3D12_RTV_DIMENSION_BUFFER: return TextureType::Buffer;
|
|
case D3D12_RTV_DIMENSION_TEXTURE1D: return TextureType::Texture1D;
|
|
case D3D12_RTV_DIMENSION_TEXTURE1DARRAY: return TextureType::Texture1DArray;
|
|
case D3D12_RTV_DIMENSION_TEXTURE2D: return TextureType::Texture2D;
|
|
case D3D12_RTV_DIMENSION_TEXTURE2DARRAY: return TextureType::Texture2DArray;
|
|
case D3D12_RTV_DIMENSION_TEXTURE2DMS: return TextureType::Texture2DMS;
|
|
case D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY: return TextureType::Texture2DMSArray;
|
|
case D3D12_RTV_DIMENSION_TEXTURE3D: return TextureType::Texture3D;
|
|
default: break;
|
|
}
|
|
|
|
return TextureType::Unknown;
|
|
}
|
|
|
|
TextureType MakeTextureDim(D3D12_DSV_DIMENSION dim)
|
|
{
|
|
switch(dim)
|
|
{
|
|
case D3D12_DSV_DIMENSION_UNKNOWN: return TextureType::Unknown;
|
|
case D3D12_DSV_DIMENSION_TEXTURE1D: return TextureType::Texture1D;
|
|
case D3D12_DSV_DIMENSION_TEXTURE1DARRAY: return TextureType::Texture1DArray;
|
|
case D3D12_DSV_DIMENSION_TEXTURE2D: return TextureType::Texture2D;
|
|
case D3D12_DSV_DIMENSION_TEXTURE2DARRAY: return TextureType::Texture2DArray;
|
|
case D3D12_DSV_DIMENSION_TEXTURE2DMS: return TextureType::Texture2DMS;
|
|
case D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY: return TextureType::Texture2DMSArray;
|
|
default: break;
|
|
}
|
|
|
|
return TextureType::Unknown;
|
|
}
|
|
|
|
TextureType MakeTextureDim(D3D12_UAV_DIMENSION dim)
|
|
{
|
|
switch(dim)
|
|
{
|
|
case D3D12_UAV_DIMENSION_UNKNOWN: return TextureType::Unknown;
|
|
case D3D12_UAV_DIMENSION_BUFFER: return TextureType::Buffer;
|
|
case D3D12_UAV_DIMENSION_TEXTURE1D: return TextureType::Texture1D;
|
|
case D3D12_UAV_DIMENSION_TEXTURE1DARRAY: return TextureType::Texture1DArray;
|
|
case D3D12_UAV_DIMENSION_TEXTURE2D: return TextureType::Texture2D;
|
|
case D3D12_UAV_DIMENSION_TEXTURE2DARRAY: return TextureType::Texture2DArray;
|
|
case D3D12_UAV_DIMENSION_TEXTURE2DMS: return TextureType::Texture2DMS;
|
|
case D3D12_UAV_DIMENSION_TEXTURE2DMSARRAY: return TextureType::Texture2DMSArray;
|
|
case D3D12_UAV_DIMENSION_TEXTURE3D: return TextureType::Texture3D;
|
|
default: break;
|
|
}
|
|
|
|
return TextureType::Unknown;
|
|
}
|
|
|
|
AddressMode MakeAddressMode(D3D12_TEXTURE_ADDRESS_MODE addr)
|
|
{
|
|
switch(addr)
|
|
{
|
|
case D3D12_TEXTURE_ADDRESS_MODE_WRAP: return AddressMode::Wrap;
|
|
case D3D12_TEXTURE_ADDRESS_MODE_MIRROR: return AddressMode::Mirror;
|
|
case D3D12_TEXTURE_ADDRESS_MODE_CLAMP: return AddressMode::ClampEdge;
|
|
case D3D12_TEXTURE_ADDRESS_MODE_BORDER: return AddressMode::ClampBorder;
|
|
case D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE: return AddressMode::MirrorOnce;
|
|
default: break;
|
|
}
|
|
|
|
return AddressMode::Wrap;
|
|
}
|
|
|
|
CompareFunction MakeCompareFunc(D3D12_COMPARISON_FUNC func)
|
|
{
|
|
switch(func)
|
|
{
|
|
case D3D12_COMPARISON_FUNC_NONE:
|
|
case D3D12_COMPARISON_FUNC_NEVER: return CompareFunction::Never;
|
|
case D3D12_COMPARISON_FUNC_LESS: return CompareFunction::Less;
|
|
case D3D12_COMPARISON_FUNC_EQUAL: return CompareFunction::Equal;
|
|
case D3D12_COMPARISON_FUNC_LESS_EQUAL: return CompareFunction::LessEqual;
|
|
case D3D12_COMPARISON_FUNC_GREATER: return CompareFunction::Greater;
|
|
case D3D12_COMPARISON_FUNC_NOT_EQUAL: return CompareFunction::NotEqual;
|
|
case D3D12_COMPARISON_FUNC_GREATER_EQUAL: return CompareFunction::GreaterEqual;
|
|
case D3D12_COMPARISON_FUNC_ALWAYS: return CompareFunction::AlwaysTrue;
|
|
default: break;
|
|
}
|
|
|
|
return CompareFunction::AlwaysTrue;
|
|
}
|
|
|
|
TextureFilter MakeFilter(D3D12_FILTER filter)
|
|
{
|
|
TextureFilter ret;
|
|
|
|
ret.filter = FilterFunction::Normal;
|
|
|
|
if(filter >= D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT &&
|
|
filter <= D3D12_FILTER_COMPARISON_ANISOTROPIC)
|
|
{
|
|
ret.filter = FilterFunction::Comparison;
|
|
// the first 0x7f is the min/mag/mip filtering
|
|
filter = D3D12_FILTER(filter & 0x7f);
|
|
}
|
|
else if(filter >= D3D12_FILTER_MINIMUM_MIN_MAG_MIP_POINT &&
|
|
filter <= D3D12_FILTER_MINIMUM_ANISOTROPIC)
|
|
{
|
|
ret.filter = FilterFunction::Minimum;
|
|
// the first 0x7f is the min/mag/mip filtering
|
|
filter = D3D12_FILTER(filter & 0x7f);
|
|
}
|
|
else if(filter >= D3D12_FILTER_MAXIMUM_MIN_MAG_MIP_POINT &&
|
|
filter <= D3D12_FILTER_MAXIMUM_ANISOTROPIC)
|
|
{
|
|
ret.filter = FilterFunction::Maximum;
|
|
// the first 0x7f is the min/mag/mip filtering
|
|
filter = D3D12_FILTER(filter & 0x7f);
|
|
}
|
|
|
|
switch(filter)
|
|
{
|
|
case D3D12_FILTER_ANISOTROPIC:
|
|
ret.minify = ret.magnify = ret.mip = FilterMode::Anisotropic;
|
|
break;
|
|
case D3D12_FILTER_MIN_MAG_ANISOTROPIC_MIP_POINT:
|
|
ret.minify = ret.magnify = FilterMode::Anisotropic;
|
|
ret.mip = FilterMode::Point;
|
|
break;
|
|
case D3D12_FILTER_MIN_MAG_MIP_POINT:
|
|
ret.minify = ret.magnify = ret.mip = FilterMode::Point;
|
|
break;
|
|
case D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR:
|
|
ret.minify = ret.magnify = FilterMode::Point;
|
|
ret.mip = FilterMode::Linear;
|
|
break;
|
|
case D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT:
|
|
ret.minify = FilterMode::Point;
|
|
ret.magnify = FilterMode::Linear;
|
|
ret.mip = FilterMode::Point;
|
|
break;
|
|
case D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR:
|
|
ret.minify = FilterMode::Point;
|
|
ret.magnify = ret.mip = FilterMode::Linear;
|
|
break;
|
|
case D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT:
|
|
ret.minify = FilterMode::Linear;
|
|
ret.magnify = ret.mip = FilterMode::Point;
|
|
break;
|
|
case D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR:
|
|
ret.minify = FilterMode::Linear;
|
|
ret.magnify = FilterMode::Point;
|
|
ret.mip = FilterMode::Linear;
|
|
break;
|
|
case D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT:
|
|
ret.minify = ret.magnify = FilterMode::Linear;
|
|
ret.mip = FilterMode::Point;
|
|
break;
|
|
case D3D12_FILTER_MIN_MAG_MIP_LINEAR:
|
|
ret.minify = ret.magnify = ret.mip = FilterMode::Linear;
|
|
break;
|
|
default: break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
DescriptorFlags MakeDescriptorFlags(D3D12_BUFFER_SRV_FLAGS flags)
|
|
{
|
|
DescriptorFlags ret = DescriptorFlags::NoFlags;
|
|
|
|
if(flags & D3D12_BUFFER_SRV_FLAG_RAW)
|
|
ret |= DescriptorFlags::RawBuffer;
|
|
|
|
return ret;
|
|
}
|
|
|
|
DescriptorFlags MakeDescriptorFlags(D3D12_BUFFER_UAV_FLAGS flags)
|
|
{
|
|
DescriptorFlags ret = DescriptorFlags::NoFlags;
|
|
|
|
if(flags & D3D12_BUFFER_UAV_FLAG_RAW)
|
|
ret |= DescriptorFlags::RawBuffer;
|
|
|
|
return ret;
|
|
}
|
|
|
|
LogicOperation MakeLogicOp(D3D12_LOGIC_OP op)
|
|
{
|
|
switch(op)
|
|
{
|
|
case D3D12_LOGIC_OP_CLEAR: return LogicOperation::Clear;
|
|
case D3D12_LOGIC_OP_AND: return LogicOperation::And;
|
|
case D3D12_LOGIC_OP_AND_REVERSE: return LogicOperation::AndReverse;
|
|
case D3D12_LOGIC_OP_COPY: return LogicOperation::Copy;
|
|
case D3D12_LOGIC_OP_AND_INVERTED: return LogicOperation::AndInverted;
|
|
case D3D12_LOGIC_OP_NOOP: return LogicOperation::NoOp;
|
|
case D3D12_LOGIC_OP_XOR: return LogicOperation::Xor;
|
|
case D3D12_LOGIC_OP_OR: return LogicOperation::Or;
|
|
case D3D12_LOGIC_OP_NOR: return LogicOperation::Nor;
|
|
case D3D12_LOGIC_OP_EQUIV: return LogicOperation::Equivalent;
|
|
case D3D12_LOGIC_OP_INVERT: return LogicOperation::Invert;
|
|
case D3D12_LOGIC_OP_OR_REVERSE: return LogicOperation::OrReverse;
|
|
case D3D12_LOGIC_OP_COPY_INVERTED: return LogicOperation::CopyInverted;
|
|
case D3D12_LOGIC_OP_OR_INVERTED: return LogicOperation::OrInverted;
|
|
case D3D12_LOGIC_OP_NAND: return LogicOperation::Nand;
|
|
case D3D12_LOGIC_OP_SET: return LogicOperation::Set;
|
|
default: break;
|
|
}
|
|
|
|
return LogicOperation::NoOp;
|
|
}
|
|
|
|
BlendMultiplier MakeBlendMultiplier(D3D12_BLEND blend, bool alpha)
|
|
{
|
|
switch(blend)
|
|
{
|
|
case D3D12_BLEND_ZERO: return BlendMultiplier::Zero;
|
|
case D3D12_BLEND_ONE: return BlendMultiplier::One;
|
|
case D3D12_BLEND_SRC_COLOR: return BlendMultiplier::SrcCol;
|
|
case D3D12_BLEND_INV_SRC_COLOR: return BlendMultiplier::InvSrcCol;
|
|
case D3D12_BLEND_DEST_COLOR: return BlendMultiplier::DstCol;
|
|
case D3D12_BLEND_INV_DEST_COLOR: return BlendMultiplier::InvDstCol;
|
|
case D3D12_BLEND_SRC_ALPHA: return BlendMultiplier::SrcAlpha;
|
|
case D3D12_BLEND_INV_SRC_ALPHA: return BlendMultiplier::InvSrcAlpha;
|
|
case D3D12_BLEND_DEST_ALPHA: return BlendMultiplier::DstAlpha;
|
|
case D3D12_BLEND_INV_DEST_ALPHA: return BlendMultiplier::InvDstAlpha;
|
|
case D3D12_BLEND_BLEND_FACTOR:
|
|
return alpha ? BlendMultiplier::FactorAlpha : BlendMultiplier::FactorRGB;
|
|
case D3D12_BLEND_INV_BLEND_FACTOR:
|
|
return alpha ? BlendMultiplier::InvFactorAlpha : BlendMultiplier::InvFactorRGB;
|
|
case D3D12_BLEND_SRC_ALPHA_SAT: return BlendMultiplier::SrcAlphaSat;
|
|
case D3D12_BLEND_SRC1_COLOR: return BlendMultiplier::Src1Col;
|
|
case D3D12_BLEND_INV_SRC1_COLOR: return BlendMultiplier::InvSrc1Col;
|
|
case D3D12_BLEND_SRC1_ALPHA: return BlendMultiplier::Src1Alpha;
|
|
case D3D12_BLEND_INV_SRC1_ALPHA: return BlendMultiplier::InvSrc1Alpha;
|
|
case D3D12_BLEND_ALPHA_FACTOR: return BlendMultiplier::FactorAlpha;
|
|
case D3D12_BLEND_INV_ALPHA_FACTOR: return BlendMultiplier::InvFactorAlpha;
|
|
default: break;
|
|
}
|
|
|
|
return BlendMultiplier::One;
|
|
}
|
|
|
|
BlendOperation MakeBlendOp(D3D12_BLEND_OP op)
|
|
{
|
|
switch(op)
|
|
{
|
|
case D3D12_BLEND_OP_ADD: return BlendOperation::Add;
|
|
case D3D12_BLEND_OP_SUBTRACT: return BlendOperation::Subtract;
|
|
case D3D12_BLEND_OP_REV_SUBTRACT: return BlendOperation::ReversedSubtract;
|
|
case D3D12_BLEND_OP_MIN: return BlendOperation::Minimum;
|
|
case D3D12_BLEND_OP_MAX: return BlendOperation::Maximum;
|
|
default: break;
|
|
}
|
|
|
|
return BlendOperation::Add;
|
|
}
|
|
|
|
StencilOperation MakeStencilOp(D3D12_STENCIL_OP op)
|
|
{
|
|
switch(op)
|
|
{
|
|
case D3D12_STENCIL_OP_KEEP: return StencilOperation::Keep;
|
|
case D3D12_STENCIL_OP_ZERO: return StencilOperation::Zero;
|
|
case D3D12_STENCIL_OP_REPLACE: return StencilOperation::Replace;
|
|
case D3D12_STENCIL_OP_INCR_SAT: return StencilOperation::IncSat;
|
|
case D3D12_STENCIL_OP_DECR_SAT: return StencilOperation::DecSat;
|
|
case D3D12_STENCIL_OP_INVERT: return StencilOperation::Invert;
|
|
case D3D12_STENCIL_OP_INCR: return StencilOperation::IncWrap;
|
|
case D3D12_STENCIL_OP_DECR: return StencilOperation::DecWrap;
|
|
default: break;
|
|
}
|
|
|
|
return StencilOperation::Keep;
|
|
}
|
|
|
|
uint32_t ArgumentTypeByteSize(const D3D12_INDIRECT_ARGUMENT_DESC &arg)
|
|
{
|
|
switch(arg.Type)
|
|
{
|
|
case D3D12_INDIRECT_ARGUMENT_TYPE_DRAW: return sizeof(D3D12_DRAW_ARGUMENTS);
|
|
case D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED: return sizeof(D3D12_DRAW_INDEXED_ARGUMENTS);
|
|
case D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH: return sizeof(D3D12_DISPATCH_ARGUMENTS);
|
|
case D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH_MESH: return sizeof(D3D12_DISPATCH_MESH_ARGUMENTS);
|
|
case D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT:
|
|
return sizeof(uint32_t) * arg.Constant.Num32BitValuesToSet;
|
|
case D3D12_INDIRECT_ARGUMENT_TYPE_VERTEX_BUFFER_VIEW: return sizeof(D3D12_VERTEX_BUFFER_VIEW);
|
|
case D3D12_INDIRECT_ARGUMENT_TYPE_INDEX_BUFFER_VIEW: return sizeof(D3D12_INDEX_BUFFER_VIEW);
|
|
case D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT_BUFFER_VIEW:
|
|
case D3D12_INDIRECT_ARGUMENT_TYPE_SHADER_RESOURCE_VIEW:
|
|
case D3D12_INDIRECT_ARGUMENT_TYPE_UNORDERED_ACCESS_VIEW:
|
|
return sizeof(D3D12_GPU_VIRTUAL_ADDRESS);
|
|
default: RDCERR("Unexpected argument type! %d", arg.Type); break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
UINT GetResourceNumMipLevels(const D3D12_RESOURCE_DESC *desc)
|
|
{
|
|
switch(desc->Dimension)
|
|
{
|
|
default:
|
|
case D3D12_RESOURCE_DIMENSION_UNKNOWN:
|
|
RDCERR("Unexpected resource dimension! %d", desc->Dimension);
|
|
break;
|
|
case D3D12_RESOURCE_DIMENSION_BUFFER: return 1;
|
|
case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
|
|
{
|
|
if(desc->MipLevels)
|
|
return desc->MipLevels;
|
|
UINT w = RDCMAX(1U, UINT(desc->Width));
|
|
UINT count = 1;
|
|
while(w > 1)
|
|
{
|
|
++count;
|
|
w = RDCMAX(1U, w >> 1U);
|
|
}
|
|
return count;
|
|
}
|
|
case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
|
|
{
|
|
if(desc->MipLevels)
|
|
return desc->MipLevels;
|
|
UINT w = RDCMAX(1U, UINT(desc->Width));
|
|
UINT h = RDCMAX(1U, desc->Height);
|
|
UINT count = 1;
|
|
while(w > 1 || h > 1)
|
|
{
|
|
++count;
|
|
w = RDCMAX(1U, w >> 1U);
|
|
h = RDCMAX(1U, h >> 1U);
|
|
}
|
|
return count;
|
|
}
|
|
case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
|
|
{
|
|
if(desc->MipLevels)
|
|
return desc->MipLevels;
|
|
UINT w = RDCMAX(1U, UINT(desc->Width));
|
|
UINT h = RDCMAX(1U, desc->Height);
|
|
UINT d = RDCMAX(1U, UINT(desc->DepthOrArraySize));
|
|
UINT count = 1;
|
|
while(w > 1 || h > 1 || d > 1)
|
|
{
|
|
++count;
|
|
w = RDCMAX(1U, w >> 1U);
|
|
h = RDCMAX(1U, h >> 1U);
|
|
d = RDCMAX(1U, d >> 1U);
|
|
}
|
|
return count;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
UINT GetNumSubresources(ID3D12Device *dev, const D3D12_RESOURCE_DESC *desc)
|
|
{
|
|
D3D12_FEATURE_DATA_FORMAT_INFO formatInfo = {};
|
|
formatInfo.Format = desc->Format;
|
|
dev->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO, &formatInfo, sizeof(formatInfo));
|
|
|
|
UINT planes = RDCMAX((UINT8)1, formatInfo.PlaneCount);
|
|
|
|
switch(desc->Dimension)
|
|
{
|
|
default:
|
|
case D3D12_RESOURCE_DIMENSION_UNKNOWN:
|
|
RDCERR("Unexpected resource dimension! %d", desc->Dimension);
|
|
break;
|
|
case D3D12_RESOURCE_DIMENSION_BUFFER: return planes;
|
|
case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
|
|
case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
|
|
return RDCMAX((UINT16)1, desc->DepthOrArraySize) * GetResourceNumMipLevels(desc) * planes;
|
|
case D3D12_RESOURCE_DIMENSION_TEXTURE3D: return GetResourceNumMipLevels(desc) * planes;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
UINT D3D12CalcSubresource(UINT MipSlice, UINT ArraySlice, UINT PlaneSlice, UINT MipLevels,
|
|
UINT ArraySize)
|
|
{
|
|
return MipSlice + (ArraySlice * MipLevels) + (PlaneSlice * MipLevels * ArraySize);
|
|
}
|
|
|
|
ShaderStageMask ConvertVisibility(D3D12_SHADER_VISIBILITY ShaderVisibility)
|
|
{
|
|
switch(ShaderVisibility)
|
|
{
|
|
case D3D12_SHADER_VISIBILITY_ALL: return ShaderStageMask::All;
|
|
case D3D12_SHADER_VISIBILITY_VERTEX: return ShaderStageMask::Vertex;
|
|
case D3D12_SHADER_VISIBILITY_HULL: return ShaderStageMask::Hull;
|
|
case D3D12_SHADER_VISIBILITY_DOMAIN: return ShaderStageMask::Domain;
|
|
case D3D12_SHADER_VISIBILITY_GEOMETRY: return ShaderStageMask::Geometry;
|
|
case D3D12_SHADER_VISIBILITY_PIXEL: return ShaderStageMask::Pixel;
|
|
case D3D12_SHADER_VISIBILITY_AMPLIFICATION: return ShaderStageMask::Amplification;
|
|
case D3D12_SHADER_VISIBILITY_MESH: return ShaderStageMask::Mesh;
|
|
default: RDCERR("Unexpected visibility %u", ShaderVisibility); break;
|
|
}
|
|
|
|
return ShaderStageMask::Unknown;
|
|
}
|
|
|
|
// from PIXEventsCommon.h of winpixeventruntime
|
|
enum PIXEventType
|
|
{
|
|
ePIXEvent_EndEvent = 0x000,
|
|
ePIXEvent_BeginEvent_VarArgs = 0x001,
|
|
ePIXEvent_BeginEvent_NoArgs = 0x002,
|
|
ePIXEvent_SetMarker_VarArgs = 0x007,
|
|
ePIXEvent_SetMarker_NoArgs = 0x008,
|
|
|
|
ePIXEvent_EndEvent_OnContext = 0x010,
|
|
ePIXEvent_BeginEvent_OnContext_VarArgs = 0x011,
|
|
ePIXEvent_BeginEvent_OnContext_NoArgs = 0x012,
|
|
ePIXEvent_SetMarker_OnContext_VarArgs = 0x017,
|
|
ePIXEvent_SetMarker_OnContext_NoArgs = 0x018,
|
|
};
|
|
|
|
inline void PIX3DecodeEventInfo(const UINT64 BlobData, UINT64 &Timestamp, PIXEventType &EventType)
|
|
{
|
|
static const UINT64 PIXEventsBlockEndMarker = 0x00000000000FFF80;
|
|
|
|
static const UINT64 PIXEventsTypeReadMask = 0x00000000000FFC00;
|
|
static const UINT64 PIXEventsTypeWriteMask = 0x00000000000003FF;
|
|
static const UINT64 PIXEventsTypeBitShift = 10;
|
|
|
|
static const UINT64 PIXEventsTimestampReadMask = 0xFFFFFFFFFFF00000;
|
|
static const UINT64 PIXEventsTimestampWriteMask = 0x00000FFFFFFFFFFF;
|
|
static const UINT64 PIXEventsTimestampBitShift = 20;
|
|
|
|
Timestamp = (BlobData >> PIXEventsTimestampBitShift) & PIXEventsTimestampWriteMask;
|
|
EventType = PIXEventType((BlobData >> PIXEventsTypeBitShift) & PIXEventsTypeWriteMask);
|
|
}
|
|
|
|
inline void PIX3DecodeStringInfo(const UINT64 BlobData, UINT64 &Alignment, UINT64 &CopyChunkSize,
|
|
bool &IsANSI, bool &IsShortcut)
|
|
{
|
|
static const UINT64 PIXEventsStringAlignmentWriteMask = 0x000000000000000F;
|
|
static const UINT64 PIXEventsStringAlignmentReadMask = 0xF000000000000000;
|
|
static const UINT64 PIXEventsStringAlignmentBitShift = 60;
|
|
|
|
static const UINT64 PIXEventsStringCopyChunkSizeWriteMask = 0x000000000000001F;
|
|
static const UINT64 PIXEventsStringCopyChunkSizeReadMask = 0x0F80000000000000;
|
|
static const UINT64 PIXEventsStringCopyChunkSizeBitShift = 55;
|
|
|
|
static const UINT64 PIXEventsStringIsANSIWriteMask = 0x0000000000000001;
|
|
static const UINT64 PIXEventsStringIsANSIReadMask = 0x0040000000000000;
|
|
static const UINT64 PIXEventsStringIsANSIBitShift = 54;
|
|
|
|
static const UINT64 PIXEventsStringIsShortcutWriteMask = 0x0000000000000001;
|
|
static const UINT64 PIXEventsStringIsShortcutReadMask = 0x0020000000000000;
|
|
static const UINT64 PIXEventsStringIsShortcutBitShift = 53;
|
|
|
|
Alignment = (BlobData >> PIXEventsStringAlignmentBitShift) & PIXEventsStringAlignmentWriteMask;
|
|
CopyChunkSize =
|
|
(BlobData >> PIXEventsStringCopyChunkSizeBitShift) & PIXEventsStringCopyChunkSizeWriteMask;
|
|
IsANSI = (BlobData >> PIXEventsStringIsANSIBitShift) & PIXEventsStringIsANSIWriteMask;
|
|
IsShortcut = (BlobData >> PIXEventsStringIsShortcutBitShift) & PIXEventsStringIsShortcutWriteMask;
|
|
}
|
|
|
|
const UINT64 *PIX3DecodeStringParam(const UINT64 *pData, rdcstr &DecodedString)
|
|
{
|
|
UINT64 alignment;
|
|
UINT64 copyChunkSize;
|
|
bool isANSI;
|
|
bool isShortcut;
|
|
PIX3DecodeStringInfo(*pData, alignment, copyChunkSize, isANSI, isShortcut);
|
|
++pData;
|
|
|
|
UINT totalStringBytes = 0;
|
|
if(isANSI)
|
|
{
|
|
const char *c = (const char *)pData;
|
|
UINT formatStringCharCount = UINT(strlen((const char *)pData));
|
|
DecodedString = rdcstr(c, formatStringCharCount);
|
|
totalStringBytes = formatStringCharCount + 1;
|
|
}
|
|
else
|
|
{
|
|
const wchar_t *w = (const wchar_t *)pData;
|
|
UINT formatStringCharCount = UINT(wcslen((const wchar_t *)pData));
|
|
DecodedString = StringFormat::Wide2UTF8(rdcwstr(w, formatStringCharCount));
|
|
totalStringBytes = (formatStringCharCount + 1) * sizeof(wchar_t);
|
|
}
|
|
|
|
UINT64 byteChunks = ((totalStringBytes + copyChunkSize - 1) / copyChunkSize) * copyChunkSize;
|
|
UINT64 stringQWordCount = (byteChunks + 7) / 8;
|
|
pData += stringQWordCount;
|
|
|
|
return pData;
|
|
}
|
|
|
|
rdcstr PIX3SprintfParams(const rdcstr &Format, const UINT64 *pData)
|
|
{
|
|
rdcstr finalString;
|
|
rdcstr formatPart;
|
|
int32_t lastFind = 0;
|
|
|
|
for(int32_t found = Format.indexOf('%'); found >= 0;)
|
|
{
|
|
finalString += Format.substr(lastFind, found - lastFind);
|
|
|
|
int32_t endOfFormat = Format.find_first_of("%diufFeEgGxXoscpaAn", found + 1);
|
|
if(endOfFormat < 0)
|
|
{
|
|
finalString += "<FORMAT_ERROR>";
|
|
break;
|
|
}
|
|
|
|
formatPart = Format.substr(found, (endOfFormat - found) + 1);
|
|
|
|
// strings
|
|
if(formatPart.back() == 's')
|
|
{
|
|
rdcstr stringParam;
|
|
pData = PIX3DecodeStringParam(pData, stringParam);
|
|
finalString += stringParam;
|
|
}
|
|
// numerical values
|
|
else
|
|
{
|
|
finalString += StringFormat::Fmt(formatPart.c_str(), *pData);
|
|
++pData;
|
|
}
|
|
|
|
lastFind = endOfFormat + 1;
|
|
found = Format.indexOf('%', lastFind);
|
|
}
|
|
|
|
finalString += Format.substr(lastFind);
|
|
|
|
return finalString;
|
|
}
|
|
|
|
rdcstr PIX3DecodeEventString(const UINT64 *pData, UINT64 &color)
|
|
{
|
|
// event header
|
|
UINT64 timestamp;
|
|
PIXEventType eventType;
|
|
PIX3DecodeEventInfo(*pData, timestamp, eventType);
|
|
++pData;
|
|
|
|
// convert setmarker event types to beginevent event types because they're identical and it makes
|
|
// for easier processing.
|
|
if(eventType == ePIXEvent_SetMarker_NoArgs)
|
|
eventType = ePIXEvent_BeginEvent_NoArgs;
|
|
|
|
if(eventType == ePIXEvent_SetMarker_VarArgs)
|
|
eventType = ePIXEvent_BeginEvent_VarArgs;
|
|
|
|
if(eventType != ePIXEvent_BeginEvent_NoArgs && eventType != ePIXEvent_BeginEvent_VarArgs)
|
|
{
|
|
RDCERR("Unexpected/unsupported PIX3Event %u type in PIXDecodeMarkerEventString", eventType);
|
|
return "";
|
|
}
|
|
|
|
// color
|
|
color = *pData;
|
|
++pData;
|
|
|
|
// format string
|
|
rdcstr formatString;
|
|
pData = PIX3DecodeStringParam(pData, formatString);
|
|
|
|
if(eventType == ePIXEvent_BeginEvent_NoArgs)
|
|
return formatString;
|
|
|
|
// sprintf remaining args
|
|
formatString = PIX3SprintfParams(formatString, pData);
|
|
return formatString;
|
|
}
|
|
|
|
D3D12_SAMPLER_DESC2 ConvertStaticSampler(const D3D12_STATIC_SAMPLER_DESC1 &samp)
|
|
{
|
|
D3D12_SAMPLER_DESC2 desc;
|
|
desc.Filter = samp.Filter;
|
|
desc.AddressU = samp.AddressU;
|
|
desc.AddressV = samp.AddressV;
|
|
desc.AddressW = samp.AddressW;
|
|
desc.MipLODBias = samp.MipLODBias;
|
|
desc.MaxAnisotropy = samp.MaxAnisotropy;
|
|
desc.ComparisonFunc = samp.ComparisonFunc;
|
|
switch(samp.BorderColor)
|
|
{
|
|
default:
|
|
case D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK:
|
|
desc.FloatBorderColor[0] = desc.FloatBorderColor[1] = desc.FloatBorderColor[2] =
|
|
desc.FloatBorderColor[3] = 0.0f;
|
|
break;
|
|
case D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK:
|
|
desc.FloatBorderColor[0] = desc.FloatBorderColor[1] = desc.FloatBorderColor[2] = 0.0f;
|
|
desc.FloatBorderColor[3] = 1.0f;
|
|
break;
|
|
case D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE:
|
|
desc.FloatBorderColor[0] = desc.FloatBorderColor[1] = desc.FloatBorderColor[2] =
|
|
desc.FloatBorderColor[3] = 1.0f;
|
|
break;
|
|
case D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK_UINT:
|
|
desc.UintBorderColor[0] = desc.UintBorderColor[1] = desc.UintBorderColor[2] = 0;
|
|
desc.UintBorderColor[3] = 1;
|
|
// this flag is optional in D3D, add it here to ensure we can check it elsewhere
|
|
desc.Flags |= D3D12_SAMPLER_FLAG_UINT_BORDER_COLOR;
|
|
break;
|
|
case D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE_UINT:
|
|
desc.UintBorderColor[0] = desc.UintBorderColor[1] = desc.UintBorderColor[2] =
|
|
desc.UintBorderColor[3] = 1;
|
|
// this flag is optional in D3D, add it here to ensure we can check it elsewhere
|
|
desc.Flags |= D3D12_SAMPLER_FLAG_UINT_BORDER_COLOR;
|
|
break;
|
|
}
|
|
desc.MinLOD = samp.MinLOD;
|
|
desc.MaxLOD = samp.MaxLOD;
|
|
desc.Flags = samp.Flags;
|
|
return desc;
|
|
}
|
|
|
|
D3D12_DEPTH_STENCILOP_DESC1 Upconvert(const D3D12_DEPTH_STENCILOP_DESC &face)
|
|
{
|
|
D3D12_DEPTH_STENCILOP_DESC1 ret = {};
|
|
|
|
ret.StencilFunc = face.StencilFunc;
|
|
ret.StencilPassOp = face.StencilPassOp;
|
|
ret.StencilFailOp = face.StencilFailOp;
|
|
ret.StencilDepthFailOp = face.StencilDepthFailOp;
|
|
|
|
return ret;
|
|
}
|
|
|
|
D3D12_DEPTH_STENCILOP_DESC Downconvert(const D3D12_DEPTH_STENCILOP_DESC1 &face)
|
|
{
|
|
D3D12_DEPTH_STENCILOP_DESC ret;
|
|
|
|
ret.StencilFunc = face.StencilFunc;
|
|
ret.StencilPassOp = face.StencilPassOp;
|
|
ret.StencilFailOp = face.StencilFailOp;
|
|
ret.StencilDepthFailOp = face.StencilDepthFailOp;
|
|
|
|
return ret;
|
|
}
|
|
|
|
D3D12_DEPTH_STENCIL_DESC2 Upconvert(const D3D12_DEPTH_STENCIL_DESC1 &desc)
|
|
{
|
|
D3D12_DEPTH_STENCIL_DESC2 DepthStencilState;
|
|
|
|
DepthStencilState.DepthBoundsTestEnable = desc.DepthBoundsTestEnable;
|
|
DepthStencilState.DepthEnable = desc.DepthEnable;
|
|
DepthStencilState.DepthFunc = desc.DepthFunc;
|
|
DepthStencilState.DepthWriteMask = desc.DepthWriteMask;
|
|
DepthStencilState.StencilEnable = desc.StencilEnable;
|
|
DepthStencilState.FrontFace = Upconvert(desc.FrontFace);
|
|
DepthStencilState.BackFace = Upconvert(desc.BackFace);
|
|
|
|
// duplicate this across both faces when it's not independent
|
|
DepthStencilState.FrontFace.StencilReadMask = desc.StencilReadMask;
|
|
DepthStencilState.FrontFace.StencilWriteMask = desc.StencilWriteMask;
|
|
DepthStencilState.BackFace.StencilReadMask = desc.StencilReadMask;
|
|
DepthStencilState.BackFace.StencilWriteMask = desc.StencilWriteMask;
|
|
|
|
return DepthStencilState;
|
|
}
|
|
|
|
D3D12_RASTERIZER_DESC2 Upconvert(const D3D12_RASTERIZER_DESC &desc)
|
|
{
|
|
D3D12_RASTERIZER_DESC2
|
|
RasterizerState;
|
|
|
|
RasterizerState.FillMode = desc.FillMode;
|
|
RasterizerState.CullMode = desc.CullMode;
|
|
RasterizerState.FrontCounterClockwise = desc.FrontCounterClockwise;
|
|
RasterizerState.DepthBias = FLOAT(desc.DepthBias);
|
|
RasterizerState.DepthBiasClamp = desc.DepthBiasClamp;
|
|
RasterizerState.SlopeScaledDepthBias = desc.SlopeScaledDepthBias;
|
|
RasterizerState.DepthClipEnable = desc.DepthClipEnable;
|
|
RasterizerState.ForcedSampleCount = desc.ForcedSampleCount;
|
|
RasterizerState.ConservativeRaster = desc.ConservativeRaster;
|
|
|
|
if(desc.MultisampleEnable)
|
|
RasterizerState.LineRasterizationMode = D3D12_LINE_RASTERIZATION_MODE_QUADRILATERAL_WIDE;
|
|
else if(desc.AntialiasedLineEnable)
|
|
RasterizerState.LineRasterizationMode = D3D12_LINE_RASTERIZATION_MODE_ALPHA_ANTIALIASED;
|
|
else
|
|
RasterizerState.LineRasterizationMode = D3D12_LINE_RASTERIZATION_MODE_ALIASED;
|
|
|
|
return RasterizerState;
|
|
}
|
|
|
|
D3D12_UNWRAPPED_STATE_OBJECT_DESC::D3D12_UNWRAPPED_STATE_OBJECT_DESC(
|
|
const D3D12_STATE_OBJECT_DESC &wrappedDesc)
|
|
{
|
|
Type = wrappedDesc.Type;
|
|
NumSubobjects = wrappedDesc.NumSubobjects;
|
|
|
|
size_t numRoots = 0, numColls = 0, numAssocs = 0;
|
|
|
|
subobjects.resize(NumSubobjects);
|
|
for(size_t i = 0; i < subobjects.size(); i++)
|
|
{
|
|
subobjects[i] = wrappedDesc.pSubobjects[i];
|
|
if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE ||
|
|
subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE)
|
|
{
|
|
numRoots++;
|
|
}
|
|
else if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_EXISTING_COLLECTION)
|
|
{
|
|
numColls++;
|
|
}
|
|
else if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION)
|
|
{
|
|
numAssocs++;
|
|
}
|
|
}
|
|
|
|
unwrappedRootsigObjs.resize(numRoots);
|
|
unwrappedCollObjs.resize(numColls);
|
|
rebasedAssocs.reserve(numAssocs);
|
|
|
|
for(size_t i = 0, r = 0, c = 0; i < subobjects.size(); i++)
|
|
{
|
|
if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE ||
|
|
subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE)
|
|
{
|
|
D3D12_GLOBAL_ROOT_SIGNATURE *rootsig = (D3D12_GLOBAL_ROOT_SIGNATURE *)subobjects[i].pDesc;
|
|
unwrappedRootsigObjs[r].pGlobalRootSignature = Unwrap(rootsig->pGlobalRootSignature);
|
|
subobjects[i].pDesc = &unwrappedRootsigObjs[r++];
|
|
}
|
|
else if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_EXISTING_COLLECTION)
|
|
{
|
|
D3D12_EXISTING_COLLECTION_DESC *coll = (D3D12_EXISTING_COLLECTION_DESC *)subobjects[i].pDesc;
|
|
unwrappedCollObjs[c] = *coll;
|
|
unwrappedCollObjs[c].pExistingCollection = Unwrap(unwrappedCollObjs[c].pExistingCollection);
|
|
subobjects[i].pDesc = &unwrappedCollObjs[c++];
|
|
}
|
|
else if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION)
|
|
{
|
|
D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION assoc =
|
|
*(D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION *)subobjects[i].pDesc;
|
|
|
|
size_t idx = assoc.pSubobjectToAssociate - wrappedDesc.pSubobjects;
|
|
assoc.pSubobjectToAssociate = subobjects.data() + idx;
|
|
rebasedAssocs.push_back(assoc);
|
|
subobjects[i].pDesc = &rebasedAssocs.back();
|
|
}
|
|
}
|
|
|
|
pSubobjects = subobjects.data();
|
|
}
|
|
|
|
D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC::D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC(
|
|
const D3D12_GRAPHICS_PIPELINE_STATE_DESC &graphics)
|
|
{
|
|
pRootSignature = graphics.pRootSignature;
|
|
VS = graphics.VS;
|
|
PS = graphics.PS;
|
|
DS = graphics.DS;
|
|
HS = graphics.HS;
|
|
GS = graphics.GS;
|
|
StreamOutput = graphics.StreamOutput;
|
|
BlendState = graphics.BlendState;
|
|
SampleMask = graphics.SampleMask;
|
|
|
|
{
|
|
RasterizerState.FillMode = graphics.RasterizerState.FillMode;
|
|
RasterizerState.CullMode = graphics.RasterizerState.CullMode;
|
|
RasterizerState.FrontCounterClockwise = graphics.RasterizerState.FrontCounterClockwise;
|
|
RasterizerState.DepthBias = FLOAT(graphics.RasterizerState.DepthBias);
|
|
RasterizerState.DepthBiasClamp = graphics.RasterizerState.DepthBiasClamp;
|
|
RasterizerState.SlopeScaledDepthBias = graphics.RasterizerState.SlopeScaledDepthBias;
|
|
RasterizerState.DepthClipEnable = graphics.RasterizerState.DepthClipEnable;
|
|
RasterizerState.ForcedSampleCount = graphics.RasterizerState.ForcedSampleCount;
|
|
RasterizerState.ConservativeRaster = graphics.RasterizerState.ConservativeRaster;
|
|
|
|
if(graphics.RasterizerState.MultisampleEnable)
|
|
RasterizerState.LineRasterizationMode = D3D12_LINE_RASTERIZATION_MODE_QUADRILATERAL_WIDE;
|
|
else if(graphics.RasterizerState.AntialiasedLineEnable)
|
|
RasterizerState.LineRasterizationMode = D3D12_LINE_RASTERIZATION_MODE_ALPHA_ANTIALIASED;
|
|
else
|
|
RasterizerState.LineRasterizationMode = D3D12_LINE_RASTERIZATION_MODE_ALIASED;
|
|
}
|
|
|
|
{
|
|
DepthStencilState.DepthEnable = graphics.DepthStencilState.DepthEnable;
|
|
DepthStencilState.DepthWriteMask = graphics.DepthStencilState.DepthWriteMask;
|
|
DepthStencilState.DepthFunc = graphics.DepthStencilState.DepthFunc;
|
|
DepthStencilState.StencilEnable = graphics.DepthStencilState.StencilEnable;
|
|
|
|
DepthStencilState.FrontFace = Upconvert(graphics.DepthStencilState.FrontFace);
|
|
DepthStencilState.BackFace = Upconvert(graphics.DepthStencilState.BackFace);
|
|
|
|
// this is not separate, so duplicate it
|
|
DepthStencilState.FrontFace.StencilReadMask = graphics.DepthStencilState.StencilReadMask;
|
|
DepthStencilState.FrontFace.StencilWriteMask = graphics.DepthStencilState.StencilWriteMask;
|
|
DepthStencilState.BackFace.StencilReadMask = graphics.DepthStencilState.StencilReadMask;
|
|
DepthStencilState.BackFace.StencilWriteMask = graphics.DepthStencilState.StencilWriteMask;
|
|
|
|
// DepthBounds defaults to disabled
|
|
DepthStencilState.DepthBoundsTestEnable = FALSE;
|
|
}
|
|
InputLayout = graphics.InputLayout;
|
|
IBStripCutValue = graphics.IBStripCutValue;
|
|
PrimitiveTopologyType = graphics.PrimitiveTopologyType;
|
|
RTVFormats.NumRenderTargets = graphics.NumRenderTargets;
|
|
memcpy(RTVFormats.RTFormats, graphics.RTVFormats, 8 * sizeof(DXGI_FORMAT));
|
|
DSVFormat = graphics.DSVFormat;
|
|
SampleDesc = graphics.SampleDesc;
|
|
NodeMask = graphics.NodeMask;
|
|
CachedPSO = graphics.CachedPSO;
|
|
Flags = graphics.Flags;
|
|
|
|
// default state
|
|
ViewInstancing.Flags = D3D12_VIEW_INSTANCING_FLAG_NONE;
|
|
ViewInstancing.pViewInstanceLocations = NULL;
|
|
ViewInstancing.ViewInstanceCount = 0;
|
|
}
|
|
|
|
D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC::D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC(
|
|
const D3D12_COMPUTE_PIPELINE_STATE_DESC &compute)
|
|
{
|
|
pRootSignature = compute.pRootSignature;
|
|
CS = compute.CS;
|
|
NodeMask = compute.NodeMask;
|
|
CachedPSO = compute.CachedPSO;
|
|
Flags = compute.Flags;
|
|
}
|
|
|
|
// this awkward construction is to account for UINT and pointer aligned data on both 32-bit and
|
|
// 64-bit.
|
|
struct D3D12_PSO_SUBOBJECT
|
|
{
|
|
D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type;
|
|
};
|
|
|
|
struct D3D12_U32_PSO_SUBOBJECT
|
|
{
|
|
D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type;
|
|
|
|
union U32Data
|
|
{
|
|
UINT SampleMask;
|
|
DXGI_FORMAT DSVFormat;
|
|
UINT NodeMask;
|
|
D3D12_BLEND_DESC BlendState;
|
|
D3D12_RASTERIZER_DESC RasterizerState;
|
|
D3D12_RASTERIZER_DESC1 RasterizerState1;
|
|
D3D12_RASTERIZER_DESC2 RasterizerState2;
|
|
D3D12_DEPTH_STENCIL_DESC DepthStencilState;
|
|
D3D12_DEPTH_STENCIL_DESC1 DepthStencilState1;
|
|
D3D12_DEPTH_STENCIL_DESC2 DepthStencilState2;
|
|
D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue;
|
|
D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType;
|
|
D3D12_RT_FORMAT_ARRAY RTVFormats;
|
|
DXGI_SAMPLE_DESC SampleDesc;
|
|
D3D12_PIPELINE_STATE_FLAGS Flags;
|
|
} data;
|
|
};
|
|
|
|
struct D3D12_PTR_PSO_SUBOBJECT
|
|
{
|
|
D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type;
|
|
|
|
#if ENABLED(RDOC_X64)
|
|
UINT padding;
|
|
#endif
|
|
|
|
union PTRData
|
|
{
|
|
ID3D12RootSignature *pRootSignature;
|
|
D3D12_SHADER_BYTECODE shader;
|
|
D3D12_STREAM_OUTPUT_DESC StreamOutput;
|
|
D3D12_INPUT_LAYOUT_DESC InputLayout;
|
|
D3D12_CACHED_PIPELINE_STATE CachedPSO;
|
|
D3D12_VIEW_INSTANCING_DESC ViewInstancing;
|
|
} data;
|
|
};
|
|
|
|
D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC::D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC(
|
|
const D3D12_PIPELINE_STATE_STREAM_DESC &stream)
|
|
{
|
|
// ensure data is naturally aligned.
|
|
RDCCOMPILE_ASSERT(offsetof(D3D12_U32_PSO_SUBOBJECT, data.SampleMask) == 4,
|
|
"D3D12_U32_PSO_SUBOBJECT UINT data is misaligned");
|
|
RDCCOMPILE_ASSERT(offsetof(D3D12_PTR_PSO_SUBOBJECT, data.pRootSignature) == sizeof(void *),
|
|
"D3D12_PTR_PSO_SUBOBJECT Pointer data is misaligned");
|
|
RDCCOMPILE_ASSERT(offsetof(D3D12_PSO_SUBOBJECT, type) == 0,
|
|
"D3D12_PSO_SUBOBJECT type member is misaligned");
|
|
RDCCOMPILE_ASSERT(offsetof(D3D12_U32_PSO_SUBOBJECT, type) == 0,
|
|
"D3D12_U32_PSO_SUBOBJECT type member is misaligned");
|
|
RDCCOMPILE_ASSERT(offsetof(D3D12_PTR_PSO_SUBOBJECT, type) == 0,
|
|
"D3D12_PTR_PSO_SUBOBJECT type member is misaligned");
|
|
|
|
// first set default state
|
|
pRootSignature = NULL;
|
|
RDCEraseEl(VS);
|
|
RDCEraseEl(HS);
|
|
RDCEraseEl(DS);
|
|
RDCEraseEl(GS);
|
|
RDCEraseEl(PS);
|
|
RDCEraseEl(CS);
|
|
RDCEraseEl(AS);
|
|
RDCEraseEl(MS);
|
|
NodeMask = 0;
|
|
RDCEraseEl(CachedPSO);
|
|
Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
|
|
SampleMask = ~0U;
|
|
RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
|
|
RasterizerState.CullMode = D3D12_CULL_MODE_BACK;
|
|
RasterizerState.FrontCounterClockwise = FALSE;
|
|
RasterizerState.DepthBias = 0;
|
|
RasterizerState.DepthBiasClamp = 0.0f;
|
|
RasterizerState.SlopeScaledDepthBias = 0.0f;
|
|
RasterizerState.DepthClipEnable = TRUE;
|
|
RasterizerState.LineRasterizationMode = D3D12_LINE_RASTERIZATION_MODE_ALIASED;
|
|
RasterizerState.ForcedSampleCount = 0;
|
|
RasterizerState.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
|
|
|
|
RDCEraseEl(StreamOutput);
|
|
|
|
BlendState.AlphaToCoverageEnable = FALSE;
|
|
BlendState.IndependentBlendEnable = FALSE;
|
|
|
|
for(int i = 0; i < 8; i++)
|
|
{
|
|
BlendState.RenderTarget[i].BlendEnable = FALSE;
|
|
BlendState.RenderTarget[i].LogicOpEnable = FALSE;
|
|
BlendState.RenderTarget[i].SrcBlend = D3D12_BLEND_ONE;
|
|
BlendState.RenderTarget[i].DestBlend = D3D12_BLEND_ZERO;
|
|
BlendState.RenderTarget[i].BlendOp = D3D12_BLEND_OP_ADD;
|
|
BlendState.RenderTarget[i].SrcBlendAlpha = D3D12_BLEND_ONE;
|
|
BlendState.RenderTarget[i].DestBlendAlpha = D3D12_BLEND_ZERO;
|
|
BlendState.RenderTarget[i].LogicOp = D3D12_LOGIC_OP_NOOP;
|
|
BlendState.RenderTarget[i].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
|
|
}
|
|
|
|
{
|
|
// Per D3D12 headers, depth is disabled if no DSV format is specified. We track this below
|
|
// and enable depth if DSVFormat is specified without dpeth stencil state.
|
|
DepthStencilState.DepthEnable = FALSE;
|
|
DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
|
|
DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
|
|
DepthStencilState.StencilEnable = FALSE;
|
|
DepthStencilState.FrontFace.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;
|
|
DepthStencilState.FrontFace.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK;
|
|
DepthStencilState.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
|
|
DepthStencilState.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
|
|
DepthStencilState.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
|
|
DepthStencilState.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP;
|
|
|
|
DepthStencilState.BackFace = DepthStencilState.FrontFace;
|
|
|
|
// DepthBounds defaults to disabled
|
|
DepthStencilState.DepthBoundsTestEnable = FALSE;
|
|
}
|
|
|
|
RDCEraseEl(InputLayout);
|
|
IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;
|
|
// Per D3D12 headers, if primitive topology is absent from the PSO stream, it defaults to triangle
|
|
PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
|
RDCEraseEl(RTVFormats);
|
|
DSVFormat = DXGI_FORMAT_UNKNOWN;
|
|
SampleDesc.Count = 1;
|
|
SampleDesc.Quality = 0;
|
|
|
|
ViewInstancing.Flags = D3D12_VIEW_INSTANCING_FLAG_NONE;
|
|
ViewInstancing.pViewInstanceLocations = NULL;
|
|
ViewInstancing.ViewInstanceCount = 0;
|
|
|
|
bool SeenDSS = false;
|
|
|
|
#define ITER_ADV(objtype) \
|
|
iter = iter + sizeof(obj->type); \
|
|
iter = AlignUpPtr(iter, alignof(objtype)); \
|
|
iter += sizeof(objtype);
|
|
|
|
byte *iter = (byte *)stream.pPipelineStateSubobjectStream;
|
|
byte *end = iter + stream.SizeInBytes;
|
|
while(iter < end)
|
|
{
|
|
D3D12_PSO_SUBOBJECT *obj = (D3D12_PSO_SUBOBJECT *)iter;
|
|
D3D12_U32_PSO_SUBOBJECT *u32 = (D3D12_U32_PSO_SUBOBJECT *)obj;
|
|
D3D12_PTR_PSO_SUBOBJECT *ptr = (D3D12_PTR_PSO_SUBOBJECT *)obj;
|
|
switch(obj->type)
|
|
{
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE:
|
|
{
|
|
pRootSignature = ptr->data.pRootSignature;
|
|
ITER_ADV(ID3D12RootSignature *);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS:
|
|
{
|
|
VS = ptr->data.shader;
|
|
ITER_ADV(D3D12_SHADER_BYTECODE);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS:
|
|
{
|
|
PS = ptr->data.shader;
|
|
ITER_ADV(D3D12_SHADER_BYTECODE);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS:
|
|
{
|
|
HS = ptr->data.shader;
|
|
ITER_ADV(D3D12_SHADER_BYTECODE);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS:
|
|
{
|
|
DS = ptr->data.shader;
|
|
ITER_ADV(D3D12_SHADER_BYTECODE);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS:
|
|
{
|
|
GS = ptr->data.shader;
|
|
ITER_ADV(D3D12_SHADER_BYTECODE);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS:
|
|
{
|
|
CS = ptr->data.shader;
|
|
ITER_ADV(D3D12_SHADER_BYTECODE);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS:
|
|
{
|
|
AS = ptr->data.shader;
|
|
ITER_ADV(D3D12_SHADER_BYTECODE);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS:
|
|
{
|
|
MS = ptr->data.shader;
|
|
ITER_ADV(D3D12_SHADER_BYTECODE);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_STREAM_OUTPUT:
|
|
{
|
|
StreamOutput = ptr->data.StreamOutput;
|
|
ITER_ADV(D3D12_STREAM_OUTPUT_DESC);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND:
|
|
{
|
|
BlendState = u32->data.BlendState;
|
|
ITER_ADV(D3D12_BLEND_DESC);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK:
|
|
{
|
|
SampleMask = u32->data.SampleMask;
|
|
ITER_ADV(UINT);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER:
|
|
{
|
|
RasterizerState = Upconvert(u32->data.RasterizerState);
|
|
|
|
ITER_ADV(D3D12_RASTERIZER_DESC);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER1:
|
|
{
|
|
RasterizerState.FillMode = u32->data.RasterizerState1.FillMode;
|
|
RasterizerState.CullMode = u32->data.RasterizerState1.CullMode;
|
|
RasterizerState.FrontCounterClockwise = u32->data.RasterizerState1.FrontCounterClockwise;
|
|
RasterizerState.DepthBias = FLOAT(u32->data.RasterizerState1.DepthBias);
|
|
RasterizerState.DepthBiasClamp = u32->data.RasterizerState1.DepthBiasClamp;
|
|
RasterizerState.SlopeScaledDepthBias = u32->data.RasterizerState1.SlopeScaledDepthBias;
|
|
RasterizerState.DepthClipEnable = u32->data.RasterizerState1.DepthClipEnable;
|
|
RasterizerState.ForcedSampleCount = u32->data.RasterizerState1.ForcedSampleCount;
|
|
RasterizerState.ConservativeRaster = u32->data.RasterizerState1.ConservativeRaster;
|
|
|
|
if(u32->data.RasterizerState1.MultisampleEnable)
|
|
RasterizerState.LineRasterizationMode = D3D12_LINE_RASTERIZATION_MODE_QUADRILATERAL_WIDE;
|
|
else if(u32->data.RasterizerState1.AntialiasedLineEnable)
|
|
RasterizerState.LineRasterizationMode = D3D12_LINE_RASTERIZATION_MODE_ALPHA_ANTIALIASED;
|
|
else
|
|
RasterizerState.LineRasterizationMode = D3D12_LINE_RASTERIZATION_MODE_ALIASED;
|
|
|
|
ITER_ADV(D3D12_RASTERIZER_DESC1);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER2:
|
|
{
|
|
RasterizerState = u32->data.RasterizerState2;
|
|
|
|
ITER_ADV(D3D12_RASTERIZER_DESC2);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL:
|
|
{
|
|
const D3D12_DEPTH_STENCIL_DESC &dsdesc = u32->data.DepthStencilState;
|
|
DepthStencilState.DepthEnable = dsdesc.DepthEnable;
|
|
DepthStencilState.DepthWriteMask = dsdesc.DepthWriteMask;
|
|
DepthStencilState.DepthFunc = dsdesc.DepthFunc;
|
|
DepthStencilState.StencilEnable = dsdesc.StencilEnable;
|
|
DepthStencilState.FrontFace = Upconvert(dsdesc.FrontFace);
|
|
DepthStencilState.BackFace = Upconvert(dsdesc.BackFace);
|
|
|
|
// duplicate this across both faces when it's not independent
|
|
DepthStencilState.FrontFace.StencilReadMask = dsdesc.StencilReadMask;
|
|
DepthStencilState.FrontFace.StencilWriteMask = dsdesc.StencilWriteMask;
|
|
DepthStencilState.BackFace.StencilReadMask = dsdesc.StencilReadMask;
|
|
DepthStencilState.BackFace.StencilWriteMask = dsdesc.StencilWriteMask;
|
|
SeenDSS = true;
|
|
ITER_ADV(D3D12_DEPTH_STENCIL_DESC);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT:
|
|
{
|
|
InputLayout = ptr->data.InputLayout;
|
|
ITER_ADV(D3D12_INPUT_LAYOUT_DESC);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE:
|
|
{
|
|
IBStripCutValue = u32->data.IBStripCutValue;
|
|
ITER_ADV(D3D12_INDEX_BUFFER_STRIP_CUT_VALUE);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY:
|
|
{
|
|
PrimitiveTopologyType = u32->data.PrimitiveTopologyType;
|
|
ITER_ADV(D3D12_PRIMITIVE_TOPOLOGY_TYPE);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS:
|
|
{
|
|
RTVFormats = u32->data.RTVFormats;
|
|
ITER_ADV(D3D12_RT_FORMAT_ARRAY);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT:
|
|
{
|
|
DSVFormat = u32->data.DSVFormat;
|
|
if(!SeenDSS && DSVFormat != DXGI_FORMAT_UNKNOWN)
|
|
DepthStencilState.DepthEnable = TRUE;
|
|
|
|
ITER_ADV(DXGI_FORMAT);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC:
|
|
{
|
|
SampleDesc = u32->data.SampleDesc;
|
|
ITER_ADV(DXGI_SAMPLE_DESC);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK:
|
|
{
|
|
NodeMask = u32->data.NodeMask;
|
|
ITER_ADV(UINT);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO:
|
|
{
|
|
CachedPSO = ptr->data.CachedPSO;
|
|
ITER_ADV(D3D12_CACHED_PIPELINE_STATE);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS:
|
|
{
|
|
Flags = u32->data.Flags;
|
|
ITER_ADV(D3D12_PIPELINE_STATE_FLAGS);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1:
|
|
{
|
|
DepthStencilState = Upconvert(u32->data.DepthStencilState1);
|
|
|
|
SeenDSS = true;
|
|
ITER_ADV(D3D12_DEPTH_STENCIL_DESC1);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL2:
|
|
{
|
|
DepthStencilState = u32->data.DepthStencilState2;
|
|
SeenDSS = true;
|
|
ITER_ADV(D3D12_DEPTH_STENCIL_DESC2);
|
|
break;
|
|
}
|
|
case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING:
|
|
{
|
|
ViewInstancing = ptr->data.ViewInstancing;
|
|
ITER_ADV(D3D12_VIEW_INSTANCING_DESC);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
RDCERR("Unknown subobject type %d", obj->type);
|
|
break;
|
|
}
|
|
}
|
|
iter = AlignUpPtr(iter, sizeof(void *));
|
|
}
|
|
}
|
|
|
|
void D3D12_PACKED_PIPELINE_STATE_STREAM_DESC::Unwrap()
|
|
{
|
|
m_GraphicsStreamData.pRootSignature = ::Unwrap(m_GraphicsStreamData.pRootSignature);
|
|
m_ComputeStreamData.pRootSignature = ::Unwrap(m_ComputeStreamData.pRootSignature);
|
|
}
|
|
|
|
D3D12_PACKED_PIPELINE_STATE_STREAM_DESC &D3D12_PACKED_PIPELINE_STATE_STREAM_DESC::operator=(
|
|
const D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC &expanded)
|
|
{
|
|
if(expanded.CS.BytecodeLength > 0)
|
|
{
|
|
m_ComputeStreamData.pRootSignature = expanded.pRootSignature;
|
|
m_ComputeStreamData.CS = expanded.CS;
|
|
m_ComputeStreamData.NodeMask = expanded.NodeMask;
|
|
m_ComputeStreamData.CachedPSO = expanded.CachedPSO;
|
|
m_ComputeStreamData.Flags = expanded.Flags;
|
|
}
|
|
else
|
|
{
|
|
m_GraphicsStreamData.pRootSignature = expanded.pRootSignature;
|
|
m_GraphicsStreamData.VS = expanded.VS;
|
|
m_GraphicsStreamData.PS = expanded.PS;
|
|
m_GraphicsStreamData.DS = expanded.DS;
|
|
m_GraphicsStreamData.HS = expanded.HS;
|
|
m_GraphicsStreamData.GS = expanded.GS;
|
|
m_GraphicsStreamData.StreamOutput = expanded.StreamOutput;
|
|
m_GraphicsStreamData.BlendState = expanded.BlendState;
|
|
m_GraphicsStreamData.SampleMask = expanded.SampleMask;
|
|
m_GraphicsStreamData.InputLayout = expanded.InputLayout;
|
|
m_GraphicsStreamData.IBStripCutValue = expanded.IBStripCutValue;
|
|
m_GraphicsStreamData.PrimitiveTopologyType = expanded.PrimitiveTopologyType;
|
|
m_GraphicsStreamData.RTVFormats = expanded.RTVFormats;
|
|
m_GraphicsStreamData.DSVFormat = expanded.DSVFormat;
|
|
m_GraphicsStreamData.SampleDesc = expanded.SampleDesc;
|
|
m_GraphicsStreamData.NodeMask = expanded.NodeMask;
|
|
m_GraphicsStreamData.CachedPSO = expanded.CachedPSO;
|
|
m_GraphicsStreamData.Flags = expanded.Flags;
|
|
m_GraphicsStreamData.ViewInstancing = expanded.ViewInstancing;
|
|
AS = expanded.AS;
|
|
MS = expanded.MS;
|
|
|
|
byte *ptr = m_GraphicsStreamData.VariableVersionedData;
|
|
const byte *start = ptr;
|
|
D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type;
|
|
|
|
#define WRITE_VERSIONED_SUBOJBECT(subobjType, subobj) \
|
|
type = subobjType; \
|
|
memcpy(ptr, &type, sizeof(type)); \
|
|
ptr += sizeof(type); \
|
|
ptr = AlignUpPtr(ptr, alignof(decltype(subobj))); \
|
|
memcpy(ptr, &subobj, sizeof(subobj)); \
|
|
ptr += sizeof(subobj); \
|
|
ptr = AlignUpPtr(ptr, sizeof(void *));
|
|
|
|
// is the line rasterization mode narrow quadrilateral? if so we need version 2.
|
|
if(expanded.RasterizerState.LineRasterizationMode ==
|
|
D3D12_LINE_RASTERIZATION_MODE_QUADRILATERAL_NARROW)
|
|
{
|
|
WRITE_VERSIONED_SUBOJBECT(D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER2,
|
|
expanded.RasterizerState);
|
|
}
|
|
// otherwise is the depth bias not an int? then we need version 1
|
|
else if(FLOAT(INT(expanded.RasterizerState.DepthBias)) != expanded.RasterizerState.DepthBias)
|
|
{
|
|
D3D12_RASTERIZER_DESC1 desc1;
|
|
|
|
desc1.FillMode = expanded.RasterizerState.FillMode;
|
|
desc1.CullMode = expanded.RasterizerState.CullMode;
|
|
desc1.FrontCounterClockwise = expanded.RasterizerState.FrontCounterClockwise;
|
|
desc1.DepthBias = expanded.RasterizerState.DepthBias;
|
|
desc1.DepthBiasClamp = expanded.RasterizerState.DepthBiasClamp;
|
|
desc1.SlopeScaledDepthBias = expanded.RasterizerState.SlopeScaledDepthBias;
|
|
desc1.DepthClipEnable = expanded.RasterizerState.DepthClipEnable;
|
|
desc1.ForcedSampleCount = expanded.RasterizerState.ForcedSampleCount;
|
|
desc1.ConservativeRaster = expanded.RasterizerState.ConservativeRaster;
|
|
|
|
switch(expanded.RasterizerState.LineRasterizationMode)
|
|
{
|
|
case D3D12_LINE_RASTERIZATION_MODE_ALIASED:
|
|
desc1.MultisampleEnable = FALSE;
|
|
desc1.AntialiasedLineEnable = FALSE;
|
|
break;
|
|
case D3D12_LINE_RASTERIZATION_MODE_ALPHA_ANTIALIASED:
|
|
desc1.MultisampleEnable = FALSE;
|
|
desc1.AntialiasedLineEnable = TRUE;
|
|
break;
|
|
case D3D12_LINE_RASTERIZATION_MODE_QUADRILATERAL_WIDE:
|
|
case D3D12_LINE_RASTERIZATION_MODE_QUADRILATERAL_NARROW:
|
|
desc1.MultisampleEnable = TRUE;
|
|
desc1.AntialiasedLineEnable = FALSE;
|
|
break;
|
|
default:
|
|
desc1.MultisampleEnable = FALSE;
|
|
desc1.AntialiasedLineEnable = FALSE;
|
|
break;
|
|
}
|
|
|
|
WRITE_VERSIONED_SUBOJBECT(D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER1, desc1);
|
|
}
|
|
// if neither of those, we can use the old version
|
|
else
|
|
{
|
|
D3D12_RASTERIZER_DESC desc;
|
|
|
|
desc.FillMode = expanded.RasterizerState.FillMode;
|
|
desc.CullMode = expanded.RasterizerState.CullMode;
|
|
desc.FrontCounterClockwise = expanded.RasterizerState.FrontCounterClockwise;
|
|
desc.DepthBias = INT(expanded.RasterizerState.DepthBias);
|
|
desc.DepthBiasClamp = expanded.RasterizerState.DepthBiasClamp;
|
|
desc.SlopeScaledDepthBias = expanded.RasterizerState.SlopeScaledDepthBias;
|
|
desc.DepthClipEnable = expanded.RasterizerState.DepthClipEnable;
|
|
desc.ForcedSampleCount = expanded.RasterizerState.ForcedSampleCount;
|
|
desc.ConservativeRaster = expanded.RasterizerState.ConservativeRaster;
|
|
|
|
switch(expanded.RasterizerState.LineRasterizationMode)
|
|
{
|
|
case D3D12_LINE_RASTERIZATION_MODE_ALIASED:
|
|
desc.MultisampleEnable = FALSE;
|
|
desc.AntialiasedLineEnable = FALSE;
|
|
break;
|
|
case D3D12_LINE_RASTERIZATION_MODE_ALPHA_ANTIALIASED:
|
|
desc.MultisampleEnable = FALSE;
|
|
desc.AntialiasedLineEnable = TRUE;
|
|
break;
|
|
case D3D12_LINE_RASTERIZATION_MODE_QUADRILATERAL_WIDE:
|
|
case D3D12_LINE_RASTERIZATION_MODE_QUADRILATERAL_NARROW:
|
|
desc.MultisampleEnable = TRUE;
|
|
desc.AntialiasedLineEnable = FALSE;
|
|
break;
|
|
default:
|
|
desc.MultisampleEnable = FALSE;
|
|
desc.AntialiasedLineEnable = FALSE;
|
|
break;
|
|
}
|
|
|
|
WRITE_VERSIONED_SUBOJBECT(D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER, desc);
|
|
}
|
|
|
|
// do we have separate stencil masks? if so use the new type of D/S desc. Otherwise use the old
|
|
// one to ensure we don't fail when the new one isn't supported
|
|
if(expanded.DepthStencilState.StencilEnable &&
|
|
(expanded.DepthStencilState.FrontFace.StencilReadMask !=
|
|
expanded.DepthStencilState.BackFace.StencilReadMask ||
|
|
expanded.DepthStencilState.FrontFace.StencilWriteMask !=
|
|
expanded.DepthStencilState.BackFace.StencilWriteMask))
|
|
{
|
|
WRITE_VERSIONED_SUBOJBECT(D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL2,
|
|
expanded.DepthStencilState);
|
|
}
|
|
else
|
|
{
|
|
D3D12_DEPTH_STENCIL_DESC1 desc1;
|
|
|
|
desc1.DepthEnable = expanded.DepthStencilState.DepthEnable;
|
|
desc1.DepthFunc = expanded.DepthStencilState.DepthFunc;
|
|
desc1.DepthBoundsTestEnable = expanded.DepthStencilState.DepthBoundsTestEnable;
|
|
desc1.DepthWriteMask = expanded.DepthStencilState.DepthWriteMask;
|
|
desc1.StencilEnable = expanded.DepthStencilState.StencilEnable;
|
|
desc1.FrontFace = Downconvert(expanded.DepthStencilState.FrontFace);
|
|
desc1.BackFace = Downconvert(expanded.DepthStencilState.BackFace);
|
|
desc1.StencilReadMask = expanded.DepthStencilState.FrontFace.StencilReadMask;
|
|
desc1.StencilWriteMask = expanded.DepthStencilState.FrontFace.StencilWriteMask;
|
|
|
|
WRITE_VERSIONED_SUBOJBECT(D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1, desc1);
|
|
}
|
|
|
|
if(expanded.AS.BytecodeLength > 0)
|
|
{
|
|
WRITE_VERSIONED_SUBOJBECT(D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS, expanded.AS);
|
|
}
|
|
|
|
if(expanded.MS.BytecodeLength > 0)
|
|
{
|
|
WRITE_VERSIONED_SUBOJBECT(D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS, expanded.MS);
|
|
}
|
|
|
|
m_VariableVersionedDataLength = ptr - start;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
#if ENABLED(ENABLE_UNIT_TESTS)
|
|
#include "catch/catch.hpp"
|
|
|
|
#define INCLUDE_GPUADDRESS_HELPERS
|
|
|
|
#include "data/hlsl/hlsl_cbuffers.h"
|
|
|
|
GPUAddress toaddr(uint64_t addr)
|
|
{
|
|
GPUAddress ret;
|
|
RDCCOMPILE_ASSERT(sizeof(ret) == sizeof(addr), "GPU address isn't 64-bit");
|
|
memcpy(&ret, &addr, sizeof(ret));
|
|
return ret;
|
|
}
|
|
|
|
uint64_t fromaddr(GPUAddress addr)
|
|
{
|
|
uint64_t ret;
|
|
RDCCOMPILE_ASSERT(sizeof(ret) == sizeof(addr), "GPU address isn't 64-bit");
|
|
memcpy(&ret, &addr, sizeof(ret));
|
|
return ret;
|
|
}
|
|
|
|
TEST_CASE("HLSL uint64 helpers", "[d3d]")
|
|
{
|
|
rdcarray<uint64_t> testValues = {
|
|
0,
|
|
1,
|
|
2,
|
|
3,
|
|
4,
|
|
5,
|
|
6,
|
|
7,
|
|
8,
|
|
9,
|
|
10,
|
|
11,
|
|
100,
|
|
128,
|
|
1000,
|
|
|
|
0xfffffffa,
|
|
0xfffffffb,
|
|
0xfffffffc,
|
|
0xfffffffd,
|
|
0xfffffffe,
|
|
0xffffffff,
|
|
|
|
0x100000000ULL,
|
|
0x100000001ULL,
|
|
0x100000002ULL,
|
|
0x100000003ULL,
|
|
0x100000004ULL,
|
|
0x100000005ULL,
|
|
0x100000006ULL,
|
|
|
|
0x1000000000001000ULL,
|
|
0x100000000fffffffULL,
|
|
0x1000000010000000ULL,
|
|
0x1000000010000001ULL,
|
|
0x1000000010000002ULL,
|
|
0x1000000010000002ULL,
|
|
|
|
0x4000000000001000ULL,
|
|
0x400000000fffffffULL,
|
|
0x4000000010000000ULL,
|
|
0x4000000010000001ULL,
|
|
0x4000000010000002ULL,
|
|
0x4000000010000002ULL,
|
|
// don't test anything that could overflow if summed together for simplicity
|
|
};
|
|
|
|
for(uint64_t first : testValues)
|
|
{
|
|
for(uint64_t second : testValues)
|
|
{
|
|
GPUAddress a, b;
|
|
a = toaddr(first);
|
|
b = toaddr(second);
|
|
|
|
// sanity check
|
|
CHECK(fromaddr(a) == first);
|
|
CHECK(fromaddr(b) == second);
|
|
|
|
CHECK(lessThan(a, b) == (first < second));
|
|
CHECK(lessEqual(a, b) == (first <= second));
|
|
|
|
CHECK(lessThan(b, a) == (second < first));
|
|
CHECK(lessEqual(b, a) == (second <= first));
|
|
|
|
CHECK(fromaddr(add(a, b)) == (first + second));
|
|
CHECK(fromaddr(add(b, a)) == (first + second));
|
|
|
|
if(first >= second)
|
|
CHECK(fromaddr(sub(a, b)) == (first - second));
|
|
else
|
|
CHECK(fromaddr(sub(b, a)) == (second - first));
|
|
}
|
|
}
|
|
};
|
|
|
|
#endif // ENABLED(ENABLE_UNIT_TESTS)
|