1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-02-10 07:54:38 +01:00
dxvk/src/d3d11/d3d11_context_def.cpp

415 lines
13 KiB
C++
Raw Normal View History

#include "d3d11_context_def.h"
#include "d3d11_device.h"
namespace dxvk {
D3D11DeferredContext::D3D11DeferredContext(
D3D11Device* pParent,
const Rc<DxvkDevice>& Device,
UINT ContextFlags)
: D3D11DeviceContext(pParent, Device, GetCsChunkFlags(pParent)),
m_contextFlags(ContextFlags),
m_commandList (CreateCommandList()) {
ClearState();
}
D3D11_DEVICE_CONTEXT_TYPE STDMETHODCALLTYPE D3D11DeferredContext::GetType() {
return D3D11_DEVICE_CONTEXT_DEFERRED;
}
UINT STDMETHODCALLTYPE D3D11DeferredContext::GetContextFlags() {
return m_contextFlags;
}
HRESULT STDMETHODCALLTYPE D3D11DeferredContext::GetData(
ID3D11Asynchronous* pAsync,
void* pData,
UINT DataSize,
UINT GetDataFlags) {
static bool s_errorShown = false;
if (!std::exchange(s_errorShown, true))
Logger::warn("D3D11: GetData called on a deferred context");
return DXGI_ERROR_INVALID_CALL;
}
void STDMETHODCALLTYPE D3D11DeferredContext::Begin(
ID3D11Asynchronous* pAsync) {
D3D10DeviceLock lock = LockContext();
if (unlikely(!pAsync))
return;
Com<D3D11Query, false> query(static_cast<D3D11Query*>(pAsync));
if (unlikely(!query->IsScoped()))
return;
auto entry = std::find(
m_queriesBegun.begin(),
m_queriesBegun.end(), query);
if (unlikely(entry != m_queriesBegun.end()))
return;
EmitCs([cQuery = query]
(DxvkContext* ctx) {
cQuery->Begin(ctx);
});
m_queriesBegun.push_back(std::move(query));
}
void STDMETHODCALLTYPE D3D11DeferredContext::End(
ID3D11Asynchronous* pAsync) {
D3D10DeviceLock lock = LockContext();
if (unlikely(!pAsync))
return;
Com<D3D11Query, false> query(static_cast<D3D11Query*>(pAsync));
if (query->IsScoped()) {
auto entry = std::find(
m_queriesBegun.begin(),
m_queriesBegun.end(), query);
if (likely(entry != m_queriesBegun.end())) {
m_queriesBegun.erase(entry);
} else {
EmitCs([cQuery = query]
(DxvkContext* ctx) {
cQuery->Begin(ctx);
});
}
}
m_commandList->AddQuery(query.ptr());
EmitCs([cQuery = std::move(query)]
(DxvkContext* ctx) {
cQuery->End(ctx);
});
}
void STDMETHODCALLTYPE D3D11DeferredContext::Flush() {
static bool s_errorShown = false;
if (!std::exchange(s_errorShown, true))
Logger::warn("D3D11: Flush called on a deferred context");
}
2019-09-16 13:12:13 +02:00
void STDMETHODCALLTYPE D3D11DeferredContext::Flush1(
D3D11_CONTEXT_TYPE ContextType,
HANDLE hEvent) {
static bool s_errorShown = false;
if (!std::exchange(s_errorShown, true))
Logger::warn("D3D11: Flush1 called on a deferred context");
2019-09-16 13:12:13 +02:00
}
2019-09-16 13:17:00 +02:00
HRESULT STDMETHODCALLTYPE D3D11DeferredContext::Signal(
ID3D11Fence* pFence,
UINT64 Value) {
static bool s_errorShown = false;
if (!std::exchange(s_errorShown, true))
Logger::warn("D3D11: Signal called on a deferred context");
2019-09-16 13:17:00 +02:00
return DXGI_ERROR_INVALID_CALL;
}
HRESULT STDMETHODCALLTYPE D3D11DeferredContext::Wait(
ID3D11Fence* pFence,
UINT64 Value) {
static bool s_errorShown = false;
if (!std::exchange(s_errorShown, true))
Logger::warn("D3D11: Wait called on a deferred context");
2019-09-16 13:17:00 +02:00
return DXGI_ERROR_INVALID_CALL;
}
void STDMETHODCALLTYPE D3D11DeferredContext::ExecuteCommandList(
ID3D11CommandList* pCommandList,
BOOL RestoreContextState) {
D3D10DeviceLock lock = LockContext();
FlushCsChunk();
static_cast<D3D11CommandList*>(pCommandList)->EmitToCommandList(m_commandList.ptr());
if (RestoreContextState)
RestoreState();
else
ClearState();
}
HRESULT STDMETHODCALLTYPE D3D11DeferredContext::FinishCommandList(
BOOL RestoreDeferredContextState,
ID3D11CommandList **ppCommandList) {
D3D10DeviceLock lock = LockContext();
FinalizeQueries();
FlushCsChunk();
if (ppCommandList != nullptr)
*ppCommandList = m_commandList.ref();
m_commandList = CreateCommandList();
2018-03-10 14:41:06 +01:00
if (RestoreDeferredContextState)
RestoreState();
2018-03-10 14:41:06 +01:00
else
ClearState();
m_mappedResources.clear();
return S_OK;
}
HRESULT STDMETHODCALLTYPE D3D11DeferredContext::Map(
ID3D11Resource* pResource,
UINT Subresource,
D3D11_MAP MapType,
UINT MapFlags,
D3D11_MAPPED_SUBRESOURCE* pMappedResource) {
D3D10DeviceLock lock = LockContext();
if (unlikely(!pResource || !pMappedResource))
return E_INVALIDARG;
D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
pResource->GetType(&resourceDim);
if (MapType == D3D11_MAP_WRITE_DISCARD) {
D3D11DeferredContextMapEntry entry;
HRESULT status = resourceDim == D3D11_RESOURCE_DIMENSION_BUFFER
? MapBuffer(pResource, MapType, MapFlags, &entry)
: MapImage (pResource, Subresource, MapType, MapFlags, &entry);
if (unlikely(FAILED(status))) {
*pMappedResource = D3D11_MAPPED_SUBRESOURCE();
return status;
}
// Adding a new map entry actually overrides the
// old one in practice because the lookup function
// scans the array in reverse order
m_mappedResources.push_back(std::move(entry));
// Fill mapped resource structure
pMappedResource->pData = entry.MapPointer;
pMappedResource->RowPitch = entry.RowPitch;
pMappedResource->DepthPitch = entry.DepthPitch;
return S_OK;
} else if (MapType == D3D11_MAP_WRITE_NO_OVERWRITE) {
// The resource must be mapped with D3D11_MAP_WRITE_DISCARD
// before it can be mapped with D3D11_MAP_WRITE_NO_OVERWRITE.
auto entry = FindMapEntry(pResource, Subresource);
if (unlikely(entry == m_mappedResources.rend())) {
*pMappedResource = D3D11_MAPPED_SUBRESOURCE();
return E_INVALIDARG;
}
// Return same memory region as earlier
entry->MapType = D3D11_MAP_WRITE_NO_OVERWRITE;
pMappedResource->pData = entry->MapPointer;
pMappedResource->RowPitch = entry->RowPitch;
pMappedResource->DepthPitch = entry->DepthPitch;
return S_OK;
} else {
// Not allowed on deferred contexts
*pMappedResource = D3D11_MAPPED_SUBRESOURCE();
return E_INVALIDARG;
}
}
void STDMETHODCALLTYPE D3D11DeferredContext::Unmap(
ID3D11Resource* pResource,
UINT Subresource) {
// No-op, updates are committed in Map
}
void STDMETHODCALLTYPE D3D11DeferredContext::SwapDeviceContextState(
ID3DDeviceContextState* pState,
ID3DDeviceContextState** ppPreviousState) {
static bool s_errorShown = false;
if (!std::exchange(s_errorShown, true))
Logger::warn("D3D11: SwapDeviceContextState called on a deferred context");
}
HRESULT D3D11DeferredContext::MapBuffer(
ID3D11Resource* pResource,
D3D11_MAP MapType,
UINT MapFlags,
D3D11DeferredContextMapEntry* pMapEntry) {
D3D11Buffer* pBuffer = static_cast<D3D11Buffer*>(pResource);
if (unlikely(pBuffer->GetMapMode() == D3D11_COMMON_BUFFER_MAP_MODE_NONE)) {
Logger::err("D3D11: Cannot map a device-local buffer");
return E_INVALIDARG;
}
pMapEntry->pResource = pResource;
pMapEntry->Subresource = 0;
pMapEntry->MapType = D3D11_MAP_WRITE_DISCARD;
pMapEntry->RowPitch = pBuffer->Desc()->ByteWidth;
pMapEntry->DepthPitch = pBuffer->Desc()->ByteWidth;
if (likely(m_csFlags.test(DxvkCsChunkFlag::SingleUse))) {
// For resources that cannot be written by the GPU,
// we may write to the buffer resource directly and
// just swap in the buffer slice as needed.
auto bufferSlice = pBuffer->AllocSlice();
pMapEntry->MapPointer = bufferSlice.mapPtr;
EmitCs([
cDstBuffer = pBuffer->GetBuffer(),
cPhysSlice = bufferSlice
] (DxvkContext* ctx) {
ctx->invalidateBuffer(cDstBuffer, cPhysSlice);
});
} else {
// For GPU-writable resources, we need a data slice
// to perform the update operation at execution time.
auto dataSlice = AllocUpdateBufferSlice(pBuffer->Desc()->ByteWidth);
pMapEntry->MapPointer = dataSlice.ptr();
EmitCs([
cDstBuffer = pBuffer->GetBuffer(),
cDataSlice = dataSlice
] (DxvkContext* ctx) {
DxvkBufferSliceHandle slice = cDstBuffer->allocSlice();
std::memcpy(slice.mapPtr, cDataSlice.ptr(), cDataSlice.length());
ctx->invalidateBuffer(cDstBuffer, slice);
});
}
return S_OK;
}
HRESULT D3D11DeferredContext::MapImage(
ID3D11Resource* pResource,
UINT Subresource,
D3D11_MAP MapType,
UINT MapFlags,
D3D11DeferredContextMapEntry* pMapEntry) {
const D3D11CommonTexture* pTexture = GetCommonTexture(pResource);
const Rc<DxvkImage> image = pTexture->GetImage();
if (unlikely(pTexture->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_NONE)) {
Logger::err("D3D11: Cannot map a device-local image");
return E_INVALIDARG;
}
if (unlikely(Subresource >= pTexture->CountSubresources()))
return E_INVALIDARG;
VkFormat packedFormat = m_parent->LookupPackedFormat(
pTexture->Desc()->Format, pTexture->GetFormatMode()).Format;
auto formatInfo = imageFormatInfo(packedFormat);
auto subresource = pTexture->GetSubresourceFromIndex(
formatInfo->aspectMask, Subresource);
VkExtent3D levelExtent = image->mipLevelExtent(subresource.mipLevel);
auto layout = pTexture->GetSubresourceLayout(formatInfo->aspectMask, Subresource);
auto dataSlice = AllocStagingBuffer(util::computeImageDataSize(packedFormat, levelExtent));
pMapEntry->pResource = pResource;
pMapEntry->Subresource = Subresource;
pMapEntry->MapType = D3D11_MAP_WRITE_DISCARD;
pMapEntry->RowPitch = layout.RowPitch;
pMapEntry->DepthPitch = layout.DepthPitch;
pMapEntry->MapPointer = dataSlice.mapPtr(0);
EmitCs([
cDstImage = pTexture->GetImage(),
cSubresource = pTexture->GetSubresourceFromIndex(formatInfo->aspectMask, Subresource),
cStagingSlice = std::move(dataSlice),
cPackedFormat = GetPackedDepthStencilFormat(pTexture->Desc()->Format)
] (DxvkContext* ctx) {
VkImageSubresourceLayers dstLayers;
dstLayers.aspectMask = cSubresource.aspectMask;
dstLayers.mipLevel = cSubresource.mipLevel;
dstLayers.baseArrayLayer = cSubresource.arrayLayer;
dstLayers.layerCount = 1;
VkOffset3D dstOffset = { 0, 0, 0 };
VkExtent3D dstExtent = cDstImage->mipLevelExtent(dstLayers.mipLevel);
if (cPackedFormat == VK_FORMAT_UNDEFINED) {
ctx->copyBufferToImage(cDstImage,
dstLayers, dstOffset, dstExtent,
cStagingSlice.buffer(),
cStagingSlice.offset(), 0, 0);
} else {
ctx->copyPackedBufferToDepthStencilImage(
cDstImage, dstLayers,
VkOffset2D { dstOffset.x, dstOffset.y },
VkExtent2D { dstExtent.width, dstExtent.height },
cStagingSlice.buffer(),
cStagingSlice.offset(),
VkOffset2D { dstOffset.x, dstOffset.y },
VkExtent2D { dstExtent.width, dstExtent.height },
cPackedFormat);
}
});
return S_OK;
}
void D3D11DeferredContext::FinalizeQueries() {
for (auto& query : m_queriesBegun) {
m_commandList->AddQuery(query.ptr());
EmitCs([cQuery = std::move(query)]
(DxvkContext* ctx) {
cQuery->End(ctx);
});
}
m_queriesBegun.clear();
}
Com<D3D11CommandList> D3D11DeferredContext::CreateCommandList() {
return new D3D11CommandList(m_parent, m_contextFlags);
}
void D3D11DeferredContext::EmitCsChunk(DxvkCsChunkRef&& chunk) {
m_commandList->AddChunk(std::move(chunk));
}
DxvkCsChunkFlags D3D11DeferredContext::GetCsChunkFlags(
D3D11Device* pDevice) {
return pDevice->GetOptions()->dcSingleUseMode
? DxvkCsChunkFlags(DxvkCsChunkFlag::SingleUse)
: DxvkCsChunkFlags();
}
}