summaryrefslogtreecommitdiffstats
path: root/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context.cpp')
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context.cpp4507
1 files changed, 4507 insertions, 0 deletions
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context.cpp
new file mode 100644
index 00000000..45af2f7b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context.cpp
@@ -0,0 +1,4507 @@
+#include <cstring>
+
+#include "d3d11_context.h"
+#include "d3d11_device.h"
+#include "d3d11_query.h"
+#include "d3d11_texture.h"
+#include "d3d11_video.h"
+
+#include "../dxbc/dxbc_util.h"
+
+namespace dxvk {
+
+ D3D11DeviceContext::D3D11DeviceContext(
+ D3D11Device* pParent,
+ const Rc<DxvkDevice>& Device,
+ DxvkCsChunkFlags CsFlags)
+ : D3D11DeviceChild<ID3D11DeviceContext4>(pParent),
+ m_contextExt(this),
+ m_annotation(this),
+ m_multithread(this, false),
+ m_device (Device),
+ m_csFlags (CsFlags),
+ m_csChunk (AllocCsChunk()),
+ m_cmdData (nullptr) {
+
+ }
+
+
+ D3D11DeviceContext::~D3D11DeviceContext() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DeviceContext::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D11DeviceChild)
+ || riid == __uuidof(ID3D11DeviceContext)
+ || riid == __uuidof(ID3D11DeviceContext1)
+ || riid == __uuidof(ID3D11DeviceContext2)
+ || riid == __uuidof(ID3D11DeviceContext3)
+ || riid == __uuidof(ID3D11DeviceContext4)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(ID3D11VkExtContext)
+ || riid == __uuidof(ID3D11VkExtContext1)) {
+ *ppvObject = ref(&m_contextExt);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(ID3DUserDefinedAnnotation)) {
+ *ppvObject = ref(&m_annotation);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(ID3D10Multithread)) {
+ *ppvObject = ref(&m_multithread);
+ return S_OK;
+ }
+
+ Logger::warn("D3D11DeviceContext::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DiscardResource(ID3D11Resource* pResource) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (!pResource)
+ return;
+
+ // We don't support the Discard API for images
+ D3D11_RESOURCE_DIMENSION resType = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+ pResource->GetType(&resType);
+
+ if (resType == D3D11_RESOURCE_DIMENSION_BUFFER) {
+ DiscardBuffer(pResource);
+ } else {
+ auto texture = GetCommonTexture(pResource);
+
+ for (uint32_t i = 0; i < texture->CountSubresources(); i++)
+ DiscardTexture(pResource, i);
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DiscardView(ID3D11View* pResourceView) {
+ DiscardView1(pResourceView, nullptr, 0);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DiscardView1(
+ ID3D11View* pResourceView,
+ const D3D11_RECT* pRects,
+ UINT NumRects) {
+ D3D10DeviceLock lock = LockContext();
+
+ // We don't support discarding individual rectangles
+ if (!pResourceView || (NumRects && pRects))
+ return;
+
+ // ID3D11View has no methods to query the exact type of
+ // the view, so we'll have to check each possible class
+ auto dsv = dynamic_cast<D3D11DepthStencilView*>(pResourceView);
+ auto rtv = dynamic_cast<D3D11RenderTargetView*>(pResourceView);
+ auto uav = dynamic_cast<D3D11UnorderedAccessView*>(pResourceView);
+
+ Rc<DxvkImageView> view;
+ if (dsv) view = dsv->GetImageView();
+ if (rtv) view = rtv->GetImageView();
+ if (uav) view = uav->GetImageView();
+
+ if (view == nullptr)
+ return;
+
+ // Get information about underlying resource
+ Com<ID3D11Resource> resource;
+ pResourceView->GetResource(&resource);
+
+ uint32_t mipCount = GetCommonTexture(resource.ptr())->Desc()->MipLevels;
+
+ // Discard mip levels one by one
+ VkImageSubresourceRange sr = view->subresources();
+
+ for (uint32_t layer = 0; layer < sr.layerCount; layer++) {
+ for (uint32_t mip = 0; mip < sr.levelCount; mip++) {
+ DiscardTexture(resource.ptr(), D3D11CalcSubresource(
+ sr.baseMipLevel + mip, sr.baseArrayLayer + layer, mipCount));
+ }
+ }
+
+ // Since we don't handle SRVs here, we can assume that the
+ // view covers all aspects of the underlying resource.
+ EmitCs([cView = view] (DxvkContext* ctx) {
+ ctx->discardImageView(cView, cView->formatInfo()->aspectMask);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::ClearState() {
+ D3D10DeviceLock lock = LockContext();
+
+ // Default shaders
+ m_state.vs.shader = nullptr;
+ m_state.hs.shader = nullptr;
+ m_state.ds.shader = nullptr;
+ m_state.gs.shader = nullptr;
+ m_state.ps.shader = nullptr;
+ m_state.cs.shader = nullptr;
+
+ // Default constant buffers
+ for (uint32_t i = 0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++) {
+ m_state.vs.constantBuffers[i] = { nullptr, 0, 0 };
+ m_state.hs.constantBuffers[i] = { nullptr, 0, 0 };
+ m_state.ds.constantBuffers[i] = { nullptr, 0, 0 };
+ m_state.gs.constantBuffers[i] = { nullptr, 0, 0 };
+ m_state.ps.constantBuffers[i] = { nullptr, 0, 0 };
+ m_state.cs.constantBuffers[i] = { nullptr, 0, 0 };
+ }
+
+ // Default samplers
+ for (uint32_t i = 0; i < D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; i++) {
+ m_state.vs.samplers[i] = nullptr;
+ m_state.hs.samplers[i] = nullptr;
+ m_state.ds.samplers[i] = nullptr;
+ m_state.gs.samplers[i] = nullptr;
+ m_state.ps.samplers[i] = nullptr;
+ m_state.cs.samplers[i] = nullptr;
+ }
+
+ // Default shader resources
+ for (uint32_t i = 0; i < D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; i++) {
+ m_state.vs.shaderResources.views[i] = nullptr;
+ m_state.hs.shaderResources.views[i] = nullptr;
+ m_state.ds.shaderResources.views[i] = nullptr;
+ m_state.gs.shaderResources.views[i] = nullptr;
+ m_state.ps.shaderResources.views[i] = nullptr;
+ m_state.cs.shaderResources.views[i] = nullptr;
+ }
+
+ m_state.vs.shaderResources.hazardous.clear();
+ m_state.hs.shaderResources.hazardous.clear();
+ m_state.ds.shaderResources.hazardous.clear();
+ m_state.gs.shaderResources.hazardous.clear();
+ m_state.ps.shaderResources.hazardous.clear();
+ m_state.cs.shaderResources.hazardous.clear();
+
+ // Default UAVs
+ for (uint32_t i = 0; i < D3D11_1_UAV_SLOT_COUNT; i++) {
+ m_state.ps.unorderedAccessViews[i] = nullptr;
+ m_state.cs.unorderedAccessViews[i] = nullptr;
+ }
+
+ m_state.cs.uavMask.clear();
+
+ // Default ID state
+ m_state.id.argBuffer = nullptr;
+
+ // Default IA state
+ m_state.ia.inputLayout = nullptr;
+ m_state.ia.primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED;
+
+ for (uint32_t i = 0; i < D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT; i++) {
+ m_state.ia.vertexBuffers[i].buffer = nullptr;
+ m_state.ia.vertexBuffers[i].offset = 0;
+ m_state.ia.vertexBuffers[i].stride = 0;
+ }
+
+ m_state.ia.indexBuffer.buffer = nullptr;
+ m_state.ia.indexBuffer.offset = 0;
+ m_state.ia.indexBuffer.format = DXGI_FORMAT_UNKNOWN;
+
+ // Default OM State
+ for (uint32_t i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
+ m_state.om.renderTargetViews[i] = nullptr;
+ m_state.om.depthStencilView = nullptr;
+
+ m_state.om.cbState = nullptr;
+ m_state.om.dsState = nullptr;
+
+ for (uint32_t i = 0; i < 4; i++)
+ m_state.om.blendFactor[i] = 1.0f;
+
+ m_state.om.sampleMask = D3D11_DEFAULT_SAMPLE_MASK;
+ m_state.om.stencilRef = D3D11_DEFAULT_STENCIL_REFERENCE;
+
+ m_state.om.maxRtv = 0;
+ m_state.om.maxUav = 0;
+
+ // Default RS state
+ m_state.rs.state = nullptr;
+ m_state.rs.numViewports = 0;
+ m_state.rs.numScissors = 0;
+
+ for (uint32_t i = 0; i < D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; i++) {
+ m_state.rs.viewports[i] = D3D11_VIEWPORT { };
+ m_state.rs.scissors [i] = D3D11_RECT { };
+ }
+
+ // Default SO state
+ for (uint32_t i = 0; i < D3D11_SO_BUFFER_SLOT_COUNT; i++) {
+ m_state.so.targets[i].buffer = nullptr;
+ m_state.so.targets[i].offset = 0;
+ }
+
+ // Default predication
+ m_state.pr.predicateObject = nullptr;
+ m_state.pr.predicateValue = FALSE;
+
+ // Make sure to apply all state
+ ResetState();
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::SetPredication(
+ ID3D11Predicate* pPredicate,
+ BOOL PredicateValue) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto predicate = D3D11Query::FromPredicate(pPredicate);
+ m_state.pr.predicateObject = predicate;
+ m_state.pr.predicateValue = PredicateValue;
+
+ static bool s_errorShown = false;
+
+ if (pPredicate && !std::exchange(s_errorShown, true))
+ Logger::err("D3D11DeviceContext::SetPredication: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GetPredication(
+ ID3D11Predicate** ppPredicate,
+ BOOL* pPredicateValue) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppPredicate)
+ *ppPredicate = D3D11Query::AsPredicate(m_state.pr.predicateObject.ref());
+
+ if (pPredicateValue)
+ *pPredicateValue = m_state.pr.predicateValue;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CopySubresourceRegion(
+ ID3D11Resource* pDstResource,
+ UINT DstSubresource,
+ UINT DstX,
+ UINT DstY,
+ UINT DstZ,
+ ID3D11Resource* pSrcResource,
+ UINT SrcSubresource,
+ const D3D11_BOX* pSrcBox) {
+ CopySubresourceRegion1(
+ pDstResource, DstSubresource, DstX, DstY, DstZ,
+ pSrcResource, SrcSubresource, pSrcBox, 0);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CopySubresourceRegion1(
+ ID3D11Resource* pDstResource,
+ UINT DstSubresource,
+ UINT DstX,
+ UINT DstY,
+ UINT DstZ,
+ ID3D11Resource* pSrcResource,
+ UINT SrcSubresource,
+ const D3D11_BOX* pSrcBox,
+ UINT CopyFlags) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (!pDstResource || !pSrcResource)
+ return;
+
+ if (pSrcBox
+ && (pSrcBox->left >= pSrcBox->right
+ || pSrcBox->top >= pSrcBox->bottom
+ || pSrcBox->front >= pSrcBox->back))
+ return;
+
+ D3D11_RESOURCE_DIMENSION dstResourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+ D3D11_RESOURCE_DIMENSION srcResourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+
+ pDstResource->GetType(&dstResourceDim);
+ pSrcResource->GetType(&srcResourceDim);
+
+ if (dstResourceDim == D3D11_RESOURCE_DIMENSION_BUFFER && srcResourceDim == D3D11_RESOURCE_DIMENSION_BUFFER) {
+ auto dstBuffer = static_cast<D3D11Buffer*>(pDstResource);
+ auto srcBuffer = static_cast<D3D11Buffer*>(pSrcResource);
+
+ VkDeviceSize dstOffset = DstX;
+ VkDeviceSize srcOffset = 0;
+ VkDeviceSize byteCount = -1;
+
+ if (pSrcBox) {
+ srcOffset = pSrcBox->left;
+ byteCount = pSrcBox->right - pSrcBox->left;
+ }
+
+ CopyBuffer(dstBuffer, dstOffset, srcBuffer, srcOffset, byteCount);
+ } else if (dstResourceDim != D3D11_RESOURCE_DIMENSION_BUFFER && srcResourceDim != D3D11_RESOURCE_DIMENSION_BUFFER) {
+ auto dstTexture = GetCommonTexture(pDstResource);
+ auto srcTexture = GetCommonTexture(pSrcResource);
+
+ if (DstSubresource >= dstTexture->CountSubresources()
+ || SrcSubresource >= srcTexture->CountSubresources())
+ return;
+
+ auto dstFormatInfo = imageFormatInfo(dstTexture->GetPackedFormat());
+ auto srcFormatInfo = imageFormatInfo(srcTexture->GetPackedFormat());
+
+ auto dstLayers = vk::makeSubresourceLayers(dstTexture->GetSubresourceFromIndex(dstFormatInfo->aspectMask, DstSubresource));
+ auto srcLayers = vk::makeSubresourceLayers(srcTexture->GetSubresourceFromIndex(srcFormatInfo->aspectMask, SrcSubresource));
+
+ VkOffset3D srcOffset = { 0, 0, 0 };
+ VkOffset3D dstOffset = { int32_t(DstX), int32_t(DstY), int32_t(DstZ) };
+
+ VkExtent3D srcExtent = srcTexture->MipLevelExtent(srcLayers.mipLevel);
+
+ if (pSrcBox != nullptr) {
+ srcOffset.x = pSrcBox->left;
+ srcOffset.y = pSrcBox->top;
+ srcOffset.z = pSrcBox->front;
+
+ srcExtent.width = pSrcBox->right - pSrcBox->left;
+ srcExtent.height = pSrcBox->bottom - pSrcBox->top;
+ srcExtent.depth = pSrcBox->back - pSrcBox->front;
+ }
+
+ CopyImage(
+ dstTexture, &dstLayers, dstOffset,
+ srcTexture, &srcLayers, srcOffset,
+ srcExtent);
+ } else {
+ Logger::err(str::format(
+ "D3D11: CopySubresourceRegion1: Incompatible resources",
+ "\n Dst resource type: ", dstResourceDim,
+ "\n Src resource type: ", srcResourceDim));
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CopyResource(
+ ID3D11Resource* pDstResource,
+ ID3D11Resource* pSrcResource) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (!pDstResource || !pSrcResource || (pDstResource == pSrcResource))
+ return;
+
+ D3D11_RESOURCE_DIMENSION dstResourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+ D3D11_RESOURCE_DIMENSION srcResourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+
+ pDstResource->GetType(&dstResourceDim);
+ pSrcResource->GetType(&srcResourceDim);
+
+ if (dstResourceDim != srcResourceDim) {
+ Logger::err(str::format(
+ "D3D11: CopyResource: Incompatible resources",
+ "\n Dst resource type: ", dstResourceDim,
+ "\n Src resource type: ", srcResourceDim));
+ return;
+ }
+
+ if (dstResourceDim == D3D11_RESOURCE_DIMENSION_BUFFER) {
+ auto dstBuffer = static_cast<D3D11Buffer*>(pDstResource);
+ auto srcBuffer = static_cast<D3D11Buffer*>(pSrcResource);
+
+ if (dstBuffer->Desc()->ByteWidth != srcBuffer->Desc()->ByteWidth)
+ return;
+
+ CopyBuffer(dstBuffer, 0, srcBuffer, 0, -1);
+ } else {
+ auto dstTexture = GetCommonTexture(pDstResource);
+ auto srcTexture = GetCommonTexture(pSrcResource);
+
+ auto dstDesc = dstTexture->Desc();
+ auto srcDesc = srcTexture->Desc();
+
+ // The subresource count must match as well
+ if (dstDesc->ArraySize != srcDesc->ArraySize
+ || dstDesc->MipLevels != srcDesc->MipLevels) {
+ Logger::err("D3D11: CopyResource: Incompatible images");
+ return;
+ }
+
+ auto dstFormatInfo = imageFormatInfo(dstTexture->GetPackedFormat());
+ auto srcFormatInfo = imageFormatInfo(srcTexture->GetPackedFormat());
+
+ for (uint32_t i = 0; i < dstDesc->MipLevels; i++) {
+ VkImageSubresourceLayers dstLayers = { dstFormatInfo->aspectMask, i, 0, dstDesc->ArraySize };
+ VkImageSubresourceLayers srcLayers = { srcFormatInfo->aspectMask, i, 0, srcDesc->ArraySize };
+
+ CopyImage(
+ dstTexture, &dstLayers, VkOffset3D(),
+ srcTexture, &srcLayers, VkOffset3D(),
+ srcTexture->MipLevelExtent(i));
+ }
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CopyStructureCount(
+ ID3D11Buffer* pDstBuffer,
+ UINT DstAlignedByteOffset,
+ ID3D11UnorderedAccessView* pSrcView) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto buf = static_cast<D3D11Buffer*>(pDstBuffer);
+ auto uav = static_cast<D3D11UnorderedAccessView*>(pSrcView);
+
+ if (!buf || !uav)
+ return;
+
+ auto counterSlice = uav->GetCounterSlice();
+ if (!counterSlice.defined())
+ return;
+
+ EmitCs([
+ cDstSlice = buf->GetBufferSlice(DstAlignedByteOffset),
+ cSrcSlice = std::move(counterSlice)
+ ] (DxvkContext* ctx) {
+ ctx->copyBuffer(
+ cDstSlice.buffer(),
+ cDstSlice.offset(),
+ cSrcSlice.buffer(),
+ cSrcSlice.offset(),
+ sizeof(uint32_t));
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CopyTiles(
+ ID3D11Resource* pTiledResource,
+ const D3D11_TILED_RESOURCE_COORDINATE* pTileRegionStartCoordinate,
+ const D3D11_TILE_REGION_SIZE* pTileRegionSize,
+ ID3D11Buffer* pBuffer,
+ UINT64 BufferStartOffsetInBytes,
+ UINT Flags) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::err("D3D11DeviceContext::CopyTiles: Not implemented");
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DeviceContext::CopyTileMappings(
+ ID3D11Resource* pDestTiledResource,
+ const D3D11_TILED_RESOURCE_COORDINATE* pDestRegionStartCoordinate,
+ ID3D11Resource* pSourceTiledResource,
+ const D3D11_TILED_RESOURCE_COORDINATE* pSourceRegionStartCoordinate,
+ const D3D11_TILE_REGION_SIZE* pTileRegionSize,
+ UINT Flags) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::err("D3D11DeviceContext::CopyTileMappings: Not implemented");
+
+ return DXGI_ERROR_INVALID_CALL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DeviceContext::ResizeTilePool(
+ ID3D11Buffer* pTilePool,
+ UINT64 NewSizeInBytes) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::err("D3D11DeviceContext::ResizeTilePool: Not implemented");
+
+ return DXGI_ERROR_INVALID_CALL;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::TiledResourceBarrier(
+ ID3D11DeviceChild* pTiledResourceOrViewAccessBeforeBarrier,
+ ID3D11DeviceChild* pTiledResourceOrViewAccessAfterBarrier) {
+
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::ClearRenderTargetView(
+ ID3D11RenderTargetView* pRenderTargetView,
+ const FLOAT ColorRGBA[4]) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto rtv = static_cast<D3D11RenderTargetView*>(pRenderTargetView);
+
+ if (!rtv)
+ return;
+
+ auto view = rtv->GetImageView();
+ auto color = ConvertColorValue(ColorRGBA, view->formatInfo());
+
+ EmitCs([
+ cClearValue = color,
+ cImageView = std::move(view)
+ ] (DxvkContext* ctx) {
+ ctx->clearRenderTarget(
+ cImageView,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ cClearValue);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::ClearUnorderedAccessViewUint(
+ ID3D11UnorderedAccessView* pUnorderedAccessView,
+ const UINT Values[4]) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto uav = static_cast<D3D11UnorderedAccessView*>(pUnorderedAccessView);
+
+ if (!uav)
+ return;
+
+ // Gather UAV format info. We'll use this to determine
+ // whether we need to create a temporary view or not.
+ D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc;
+ uav->GetDesc(&uavDesc);
+
+ VkFormat uavFormat = m_parent->LookupFormat(uavDesc.Format, DXGI_VK_FORMAT_MODE_ANY).Format;
+ VkFormat rawFormat = m_parent->LookupFormat(uavDesc.Format, DXGI_VK_FORMAT_MODE_RAW).Format;
+
+ if (uavFormat != rawFormat && rawFormat == VK_FORMAT_UNDEFINED) {
+ Logger::err(str::format("D3D11: ClearUnorderedAccessViewUint: No raw format found for ", uavFormat));
+ return;
+ }
+
+ // Set up clear color struct
+ VkClearValue clearValue;
+ clearValue.color.uint32[0] = Values[0];
+ clearValue.color.uint32[1] = Values[1];
+ clearValue.color.uint32[2] = Values[2];
+ clearValue.color.uint32[3] = Values[3];
+
+ // This is the only packed format that has UAV support
+ if (uavFormat == VK_FORMAT_B10G11R11_UFLOAT_PACK32) {
+ clearValue.color.uint32[0] = ((Values[0] & 0x7FF) << 0)
+ | ((Values[1] & 0x7FF) << 11)
+ | ((Values[2] & 0x3FF) << 22);
+ }
+
+ if (uav->GetResourceType() == D3D11_RESOURCE_DIMENSION_BUFFER) {
+ // In case of raw and structured buffers as well as typed
+ // buffers that can be used for atomic operations, we can
+ // use the fast Vulkan buffer clear function.
+ Rc<DxvkBufferView> bufferView = uav->GetBufferView();
+
+ if (bufferView->info().format == VK_FORMAT_R32_UINT
+ || bufferView->info().format == VK_FORMAT_R32_SINT
+ || bufferView->info().format == VK_FORMAT_R32_SFLOAT) {
+ EmitCs([
+ cClearValue = Values[0],
+ cDstSlice = bufferView->slice()
+ ] (DxvkContext* ctx) {
+ ctx->clearBuffer(
+ cDstSlice.buffer(),
+ cDstSlice.offset(),
+ cDstSlice.length(),
+ cClearValue);
+ });
+ } else {
+ // Create a view with an integer format if necessary
+ if (uavFormat != rawFormat) {
+ DxvkBufferViewCreateInfo info = bufferView->info();
+ info.format = rawFormat;
+
+ bufferView = m_device->createBufferView(
+ bufferView->buffer(), info);
+ }
+
+ EmitCs([
+ cClearValue = clearValue,
+ cDstView = bufferView
+ ] (DxvkContext* ctx) {
+ ctx->clearBufferView(
+ cDstView, 0,
+ cDstView->elementCount(),
+ cClearValue.color);
+ });
+ }
+ } else {
+ // Create a view with an integer format if necessary
+ Rc<DxvkImageView> imageView = uav->GetImageView();
+
+ if (uavFormat != rawFormat) {
+ DxvkImageViewCreateInfo info = imageView->info();
+ info.format = rawFormat;
+
+ imageView = m_device->createImageView(
+ imageView->image(), info);
+ }
+
+ EmitCs([
+ cClearValue = clearValue,
+ cDstView = imageView
+ ] (DxvkContext* ctx) {
+ ctx->clearImageView(cDstView,
+ VkOffset3D { 0, 0, 0 },
+ cDstView->mipLevelExtent(0),
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ cClearValue);
+ });
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::ClearUnorderedAccessViewFloat(
+ ID3D11UnorderedAccessView* pUnorderedAccessView,
+ const FLOAT Values[4]) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto uav = static_cast<D3D11UnorderedAccessView*>(pUnorderedAccessView);
+
+ if (!uav)
+ return;
+
+ auto imgView = uav->GetImageView();
+ auto bufView = uav->GetBufferView();
+
+ const DxvkFormatInfo* info = nullptr;
+ if (imgView != nullptr) info = imgView->formatInfo();
+ if (bufView != nullptr) info = bufView->formatInfo();
+
+ if (!info || info->flags.any(DxvkFormatFlag::SampledSInt, DxvkFormatFlag::SampledUInt))
+ return;
+
+ VkClearValue clearValue;
+ clearValue.color.float32[0] = Values[0];
+ clearValue.color.float32[1] = Values[1];
+ clearValue.color.float32[2] = Values[2];
+ clearValue.color.float32[3] = Values[3];
+
+ if (uav->GetResourceType() == D3D11_RESOURCE_DIMENSION_BUFFER) {
+ EmitCs([
+ cClearValue = clearValue,
+ cDstView = std::move(bufView)
+ ] (DxvkContext* ctx) {
+ ctx->clearBufferView(
+ cDstView, 0,
+ cDstView->elementCount(),
+ cClearValue.color);
+ });
+ } else {
+ EmitCs([
+ cClearValue = clearValue,
+ cDstView = std::move(imgView)
+ ] (DxvkContext* ctx) {
+ ctx->clearImageView(cDstView,
+ VkOffset3D { 0, 0, 0 },
+ cDstView->mipLevelExtent(0),
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ cClearValue);
+ });
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::ClearDepthStencilView(
+ ID3D11DepthStencilView* pDepthStencilView,
+ UINT ClearFlags,
+ FLOAT Depth,
+ UINT8 Stencil) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto dsv = static_cast<D3D11DepthStencilView*>(pDepthStencilView);
+
+ if (!dsv)
+ return;
+
+ // Figure out which aspects to clear based on
+ // the image view properties and clear flags.
+ VkImageAspectFlags aspectMask = 0;
+
+ if (ClearFlags & D3D11_CLEAR_DEPTH)
+ aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
+
+ if (ClearFlags & D3D11_CLEAR_STENCIL)
+ aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
+
+ aspectMask &= dsv->GetWritableAspectMask();
+
+ if (!aspectMask)
+ return;
+
+ VkClearValue clearValue;
+ clearValue.depthStencil.depth = Depth;
+ clearValue.depthStencil.stencil = Stencil;
+
+ EmitCs([
+ cClearValue = clearValue,
+ cAspectMask = aspectMask,
+ cImageView = dsv->GetImageView()
+ ] (DxvkContext* ctx) {
+ ctx->clearRenderTarget(
+ cImageView,
+ cAspectMask,
+ cClearValue);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::ClearView(
+ ID3D11View* pView,
+ const FLOAT Color[4],
+ const D3D11_RECT* pRect,
+ UINT NumRects) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (NumRects && !pRect)
+ return;
+
+ // ID3D11View has no methods to query the exact type of
+ // the view, so we'll have to check each possible class
+ auto dsv = dynamic_cast<D3D11DepthStencilView*>(pView);
+ auto rtv = dynamic_cast<D3D11RenderTargetView*>(pView);
+ auto uav = dynamic_cast<D3D11UnorderedAccessView*>(pView);
+ auto vov = dynamic_cast<D3D11VideoProcessorOutputView*>(pView);
+
+ // Retrieve underlying resource view
+ Rc<DxvkBufferView> bufView;
+ Rc<DxvkImageView> imgView;
+
+ if (dsv != nullptr)
+ imgView = dsv->GetImageView();
+
+ if (rtv != nullptr)
+ imgView = rtv->GetImageView();
+
+ if (uav != nullptr) {
+ bufView = uav->GetBufferView();
+ imgView = uav->GetImageView();
+ }
+
+ if (vov != nullptr)
+ imgView = vov->GetView();
+
+ // 3D views are unsupported
+ if (imgView != nullptr
+ && imgView->info().type == VK_IMAGE_VIEW_TYPE_3D)
+ return;
+
+ // Query the view format. We'll have to convert
+ // the clear color based on the format's data type.
+ VkFormat format = VK_FORMAT_UNDEFINED;
+
+ if (bufView != nullptr)
+ format = bufView->info().format;
+
+ if (imgView != nullptr)
+ format = imgView->info().format;
+
+ if (format == VK_FORMAT_UNDEFINED)
+ return;
+
+ // We'll need the format info to determine the buffer
+ // element size, and we also need it for depth images.
+ const DxvkFormatInfo* formatInfo = imageFormatInfo(format);
+
+ // Convert the clear color format. ClearView takes
+ // the clear value for integer formats as a set of
+ // integral floats, so we'll have to convert.
+ VkClearValue clearValue = ConvertColorValue(Color, formatInfo);
+ VkImageAspectFlags clearAspect = formatInfo->aspectMask & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT);
+
+ // Clear all the rectangles that are specified
+ for (uint32_t i = 0; i < NumRects || i < 1; i++) {
+ if (pRect) {
+ if (pRect[i].left >= pRect[i].right
+ || pRect[i].top >= pRect[i].bottom)
+ continue;
+ }
+
+ if (bufView != nullptr) {
+ VkDeviceSize offset = 0;
+ VkDeviceSize length = bufView->info().rangeLength / formatInfo->elementSize;
+
+ if (pRect) {
+ offset = pRect[i].left;
+ length = pRect[i].right - pRect[i].left;
+ }
+
+ EmitCs([
+ cBufferView = bufView,
+ cRangeOffset = offset,
+ cRangeLength = length,
+ cClearValue = clearValue
+ ] (DxvkContext* ctx) {
+ ctx->clearBufferView(
+ cBufferView,
+ cRangeOffset,
+ cRangeLength,
+ cClearValue.color);
+ });
+ }
+
+ if (imgView != nullptr) {
+ VkOffset3D offset = { 0, 0, 0 };
+ VkExtent3D extent = imgView->mipLevelExtent(0);
+
+ if (pRect) {
+ offset = { pRect[i].left, pRect[i].top, 0 };
+ extent = {
+ uint32_t(pRect[i].right - pRect[i].left),
+ uint32_t(pRect[i].bottom - pRect[i].top), 1 };
+ }
+
+ EmitCs([
+ cImageView = imgView,
+ cAreaOffset = offset,
+ cAreaExtent = extent,
+ cClearAspect = clearAspect,
+ cClearValue = clearValue
+ ] (DxvkContext* ctx) {
+ const VkImageUsageFlags rtUsage =
+ VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
+ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+
+ bool isFullSize = cImageView->mipLevelExtent(0) == cAreaExtent;
+
+ if ((cImageView->info().usage & rtUsage) && isFullSize) {
+ ctx->clearRenderTarget(
+ cImageView,
+ cClearAspect,
+ cClearValue);
+ } else {
+ ctx->clearImageView(
+ cImageView,
+ cAreaOffset,
+ cAreaExtent,
+ cClearAspect,
+ cClearValue);
+ }
+ });
+ }
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GenerateMips(ID3D11ShaderResourceView* pShaderResourceView) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto view = static_cast<D3D11ShaderResourceView*>(pShaderResourceView);
+
+ if (!view || view->GetResourceType() == D3D11_RESOURCE_DIMENSION_BUFFER)
+ return;
+
+ D3D11_COMMON_RESOURCE_DESC resourceDesc = view->GetResourceDesc();
+
+ if (!(resourceDesc.MiscFlags & D3D11_RESOURCE_MISC_GENERATE_MIPS))
+ return;
+
+ EmitCs([cDstImageView = view->GetImageView()]
+ (DxvkContext* ctx) {
+ ctx->generateMipmaps(cDstImageView, VK_FILTER_LINEAR);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::UpdateSubresource(
+ ID3D11Resource* pDstResource,
+ UINT DstSubresource,
+ const D3D11_BOX* pDstBox,
+ const void* pSrcData,
+ UINT SrcRowPitch,
+ UINT SrcDepthPitch) {
+ UpdateSubresource1(pDstResource,
+ DstSubresource, pDstBox, pSrcData,
+ SrcRowPitch, SrcDepthPitch, 0);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::UpdateSubresource1(
+ ID3D11Resource* pDstResource,
+ UINT DstSubresource,
+ const D3D11_BOX* pDstBox,
+ const void* pSrcData,
+ UINT SrcRowPitch,
+ UINT SrcDepthPitch,
+ UINT CopyFlags) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (!pDstResource)
+ return;
+
+ // Filter out invalid copy flags
+ CopyFlags &= D3D11_COPY_NO_OVERWRITE | D3D11_COPY_DISCARD;
+
+ // We need a different code path for buffers
+ D3D11_RESOURCE_DIMENSION resourceType;
+ pDstResource->GetType(&resourceType);
+
+ if (resourceType == D3D11_RESOURCE_DIMENSION_BUFFER) {
+ const auto bufferResource = static_cast<D3D11Buffer*>(pDstResource);
+ const auto bufferSlice = bufferResource->GetBufferSlice();
+
+ VkDeviceSize offset = bufferSlice.offset();
+ VkDeviceSize size = bufferSlice.length();
+
+ if (pDstBox != nullptr) {
+ offset = pDstBox->left;
+ size = pDstBox->right - pDstBox->left;
+ }
+
+ if (!size || offset + size > bufferSlice.length())
+ return;
+
+ bool useMap = (bufferSlice.buffer()->memFlags() & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
+ && (size == bufferSlice.length() || CopyFlags);
+
+ if (useMap) {
+ D3D11_MAP mapType = (CopyFlags & D3D11_COPY_NO_OVERWRITE)
+ ? D3D11_MAP_WRITE_NO_OVERWRITE
+ : D3D11_MAP_WRITE_DISCARD;
+
+ D3D11_MAPPED_SUBRESOURCE mappedSr;
+ if (likely(useMap = SUCCEEDED(Map(pDstResource, 0, mapType, 0, &mappedSr)))) {
+ std::memcpy(reinterpret_cast<char*>(mappedSr.pData) + offset, pSrcData, size);
+ Unmap(pDstResource, 0);
+ }
+ }
+
+ if (!useMap) {
+ DxvkDataSlice dataSlice = AllocUpdateBufferSlice(size);
+ std::memcpy(dataSlice.ptr(), pSrcData, size);
+
+ EmitCs([
+ cDataBuffer = std::move(dataSlice),
+ cBufferSlice = bufferSlice.subSlice(offset, size)
+ ] (DxvkContext* ctx) {
+ ctx->updateBuffer(
+ cBufferSlice.buffer(),
+ cBufferSlice.offset(),
+ cBufferSlice.length(),
+ cDataBuffer.ptr());
+ });
+ }
+ } else {
+ D3D11CommonTexture* dstTexture = GetCommonTexture(pDstResource);
+
+ if (DstSubresource >= dstTexture->CountSubresources())
+ return;
+
+ VkFormat packedFormat = dstTexture->GetPackedFormat();
+
+ auto formatInfo = imageFormatInfo(packedFormat);
+ auto subresource = dstTexture->GetSubresourceFromIndex(
+ formatInfo->aspectMask, DstSubresource);
+
+ VkExtent3D mipExtent = dstTexture->MipLevelExtent(subresource.mipLevel);
+
+ VkOffset3D offset = { 0, 0, 0 };
+ VkExtent3D extent = mipExtent;
+
+ if (pDstBox != nullptr) {
+ if (pDstBox->left >= pDstBox->right
+ || pDstBox->top >= pDstBox->bottom
+ || pDstBox->front >= pDstBox->back)
+ return; // no-op, but legal
+
+ offset.x = pDstBox->left;
+ offset.y = pDstBox->top;
+ offset.z = pDstBox->front;
+
+ extent.width = pDstBox->right - pDstBox->left;
+ extent.height = pDstBox->bottom - pDstBox->top;
+ extent.depth = pDstBox->back - pDstBox->front;
+ }
+
+ if (!util::isBlockAligned(offset, extent, formatInfo->blockSize, mipExtent)) {
+ Logger::err("D3D11: UpdateSubresource1: Unaligned region");
+ return;
+ }
+
+ auto stagingSlice = AllocStagingBuffer(util::computeImageDataSize(packedFormat, extent));
+
+ util::packImageData(stagingSlice.mapPtr(0),
+ pSrcData, SrcRowPitch, SrcDepthPitch, 0, 0,
+ dstTexture->GetVkImageType(), extent, 1,
+ formatInfo, formatInfo->aspectMask);
+
+ UpdateImage(dstTexture, &subresource,
+ offset, extent, std::move(stagingSlice));
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DeviceContext::UpdateTileMappings(
+ ID3D11Resource* pTiledResource,
+ UINT NumTiledResourceRegions,
+ const D3D11_TILED_RESOURCE_COORDINATE* pTiledResourceRegionStartCoordinates,
+ const D3D11_TILE_REGION_SIZE* pTiledResourceRegionSizes,
+ ID3D11Buffer* pTilePool,
+ UINT NumRanges,
+ const UINT* pRangeFlags,
+ const UINT* pTilePoolStartOffsets,
+ const UINT* pRangeTileCounts,
+ UINT Flags) {
+ bool s_errorShown = false;
+
+ if (std::exchange(s_errorShown, true))
+ Logger::err("D3D11DeviceContext::UpdateTileMappings: Not implemented");
+
+ return DXGI_ERROR_INVALID_CALL;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::UpdateTiles(
+ ID3D11Resource* pDestTiledResource,
+ const D3D11_TILED_RESOURCE_COORDINATE* pDestTileRegionStartCoordinate,
+ const D3D11_TILE_REGION_SIZE* pDestTileRegionSize,
+ const void* pSourceTileData,
+ UINT Flags) {
+ bool s_errorShown = false;
+
+ if (std::exchange(s_errorShown, true))
+ Logger::err("D3D11DeviceContext::UpdateTiles: Not implemented");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::SetResourceMinLOD(
+ ID3D11Resource* pResource,
+ FLOAT MinLOD) {
+ bool s_errorShown = false;
+
+ if (std::exchange(s_errorShown, true))
+ Logger::err("D3D11DeviceContext::SetResourceMinLOD: Not implemented");
+ }
+
+
+ FLOAT STDMETHODCALLTYPE D3D11DeviceContext::GetResourceMinLOD(ID3D11Resource* pResource) {
+ bool s_errorShown = false;
+
+ if (std::exchange(s_errorShown, true))
+ Logger::err("D3D11DeviceContext::GetResourceMinLOD: Not implemented");
+
+ return 0.0f;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::ResolveSubresource(
+ ID3D11Resource* pDstResource,
+ UINT DstSubresource,
+ ID3D11Resource* pSrcResource,
+ UINT SrcSubresource,
+ DXGI_FORMAT Format) {
+ D3D10DeviceLock lock = LockContext();
+
+ bool isSameSubresource = pDstResource == pSrcResource
+ && DstSubresource == SrcSubresource;
+
+ if (!pDstResource || !pSrcResource || isSameSubresource)
+ return;
+
+ D3D11_RESOURCE_DIMENSION dstResourceType;
+ D3D11_RESOURCE_DIMENSION srcResourceType;
+
+ pDstResource->GetType(&dstResourceType);
+ pSrcResource->GetType(&srcResourceType);
+
+ if (dstResourceType != D3D11_RESOURCE_DIMENSION_TEXTURE2D
+ || srcResourceType != D3D11_RESOURCE_DIMENSION_TEXTURE2D) {
+ Logger::err(str::format(
+ "D3D11: ResolveSubresource: Incompatible resources",
+ "\n Dst resource type: ", dstResourceType,
+ "\n Src resource type: ", srcResourceType));
+ return;
+ }
+
+ auto dstTexture = static_cast<D3D11Texture2D*>(pDstResource);
+ auto srcTexture = static_cast<D3D11Texture2D*>(pSrcResource);
+
+ D3D11_TEXTURE2D_DESC dstDesc;
+ D3D11_TEXTURE2D_DESC srcDesc;
+
+ dstTexture->GetDesc(&dstDesc);
+ srcTexture->GetDesc(&srcDesc);
+
+ if (dstDesc.SampleDesc.Count != 1) {
+ Logger::err(str::format(
+ "D3D11: ResolveSubresource: Invalid sample counts",
+ "\n Dst sample count: ", dstDesc.SampleDesc.Count,
+ "\n Src sample count: ", srcDesc.SampleDesc.Count));
+ return;
+ }
+
+ const D3D11CommonTexture* dstTextureInfo = GetCommonTexture(pDstResource);
+ const D3D11CommonTexture* srcTextureInfo = GetCommonTexture(pSrcResource);
+
+ const DXGI_VK_FORMAT_INFO dstFormatInfo = m_parent->LookupFormat(dstDesc.Format, DXGI_VK_FORMAT_MODE_ANY);
+ const DXGI_VK_FORMAT_INFO srcFormatInfo = m_parent->LookupFormat(srcDesc.Format, DXGI_VK_FORMAT_MODE_ANY);
+
+ auto dstVulkanFormatInfo = imageFormatInfo(dstFormatInfo.Format);
+ auto srcVulkanFormatInfo = imageFormatInfo(srcFormatInfo.Format);
+
+ if (DstSubresource >= dstTextureInfo->CountSubresources()
+ || SrcSubresource >= srcTextureInfo->CountSubresources())
+ return;
+
+ const VkImageSubresource dstSubresource =
+ dstTextureInfo->GetSubresourceFromIndex(
+ dstVulkanFormatInfo->aspectMask, DstSubresource);
+
+ const VkImageSubresource srcSubresource =
+ srcTextureInfo->GetSubresourceFromIndex(
+ srcVulkanFormatInfo->aspectMask, SrcSubresource);
+
+ const VkImageSubresourceLayers dstSubresourceLayers = {
+ dstSubresource.aspectMask,
+ dstSubresource.mipLevel,
+ dstSubresource.arrayLayer, 1 };
+
+ const VkImageSubresourceLayers srcSubresourceLayers = {
+ srcSubresource.aspectMask,
+ srcSubresource.mipLevel,
+ srcSubresource.arrayLayer, 1 };
+
+ if (srcDesc.SampleDesc.Count == 1 || m_parent->GetOptions()->disableMsaa) {
+ EmitCs([
+ cDstImage = dstTextureInfo->GetImage(),
+ cSrcImage = srcTextureInfo->GetImage(),
+ cDstLayers = dstSubresourceLayers,
+ cSrcLayers = srcSubresourceLayers
+ ] (DxvkContext* ctx) {
+ ctx->copyImage(
+ cDstImage, cDstLayers, VkOffset3D { 0, 0, 0 },
+ cSrcImage, cSrcLayers, VkOffset3D { 0, 0, 0 },
+ cDstImage->mipLevelExtent(cDstLayers.mipLevel));
+ });
+ } else {
+ const VkFormat format = m_parent->LookupFormat(
+ Format, DXGI_VK_FORMAT_MODE_ANY).Format;
+
+ EmitCs([
+ cDstImage = dstTextureInfo->GetImage(),
+ cSrcImage = srcTextureInfo->GetImage(),
+ cDstSubres = dstSubresourceLayers,
+ cSrcSubres = srcSubresourceLayers,
+ cFormat = format
+ ] (DxvkContext* ctx) {
+ VkImageResolve region;
+ region.srcSubresource = cSrcSubres;
+ region.srcOffset = VkOffset3D { 0, 0, 0 };
+ region.dstSubresource = cDstSubres;
+ region.dstOffset = VkOffset3D { 0, 0, 0 };
+ region.extent = cDstImage->mipLevelExtent(cDstSubres.mipLevel);
+
+ ctx->resolveImage(cDstImage, cSrcImage, region, cFormat);
+ });
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DrawAuto() {
+ D3D10DeviceLock lock = LockContext();
+
+ D3D11Buffer* buffer = m_state.ia.vertexBuffers[0].buffer.ptr();
+
+ if (buffer == nullptr)
+ return;
+
+ DxvkBufferSlice vtxBuf = buffer->GetBufferSlice();
+ DxvkBufferSlice ctrBuf = buffer->GetSOCounter();
+
+ if (!ctrBuf.defined())
+ return;
+
+ EmitCs([=] (DxvkContext* ctx) {
+ ctx->drawIndirectXfb(ctrBuf,
+ vtxBuf.buffer()->getXfbVertexStride(),
+ vtxBuf.offset());
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::Draw(
+ UINT VertexCount,
+ UINT StartVertexLocation) {
+ D3D10DeviceLock lock = LockContext();
+
+ EmitCs([=] (DxvkContext* ctx) {
+ ctx->draw(
+ VertexCount, 1,
+ StartVertexLocation, 0);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DrawIndexed(
+ UINT IndexCount,
+ UINT StartIndexLocation,
+ INT BaseVertexLocation) {
+ D3D10DeviceLock lock = LockContext();
+
+ EmitCs([=] (DxvkContext* ctx) {
+ ctx->drawIndexed(
+ IndexCount, 1,
+ StartIndexLocation,
+ BaseVertexLocation, 0);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DrawInstanced(
+ UINT VertexCountPerInstance,
+ UINT InstanceCount,
+ UINT StartVertexLocation,
+ UINT StartInstanceLocation) {
+ D3D10DeviceLock lock = LockContext();
+
+ EmitCs([=] (DxvkContext* ctx) {
+ ctx->draw(
+ VertexCountPerInstance,
+ InstanceCount,
+ StartVertexLocation,
+ StartInstanceLocation);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DrawIndexedInstanced(
+ UINT IndexCountPerInstance,
+ UINT InstanceCount,
+ UINT StartIndexLocation,
+ INT BaseVertexLocation,
+ UINT StartInstanceLocation) {
+ D3D10DeviceLock lock = LockContext();
+
+ EmitCs([=] (DxvkContext* ctx) {
+ ctx->drawIndexed(
+ IndexCountPerInstance,
+ InstanceCount,
+ StartIndexLocation,
+ BaseVertexLocation,
+ StartInstanceLocation);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DrawIndexedInstancedIndirect(
+ ID3D11Buffer* pBufferForArgs,
+ UINT AlignedByteOffsetForArgs) {
+ D3D10DeviceLock lock = LockContext();
+ SetDrawBuffers(pBufferForArgs, nullptr);
+
+ if (!ValidateDrawBufferSize(pBufferForArgs, AlignedByteOffsetForArgs, sizeof(VkDrawIndexedIndirectCommand)))
+ return;
+
+ // If possible, batch up multiple indirect draw calls of
+ // the same type into one single multiDrawIndirect call
+ auto cmdData = static_cast<D3D11CmdDrawIndirectData*>(m_cmdData);
+ auto stride = 0u;
+
+ if (cmdData && cmdData->type == D3D11CmdType::DrawIndirectIndexed)
+ stride = GetIndirectCommandStride(cmdData, AlignedByteOffsetForArgs, sizeof(VkDrawIndexedIndirectCommand));
+
+ if (stride) {
+ cmdData->count += 1;
+ cmdData->stride = stride;
+ } else {
+ cmdData = EmitCsCmd<D3D11CmdDrawIndirectData>(
+ [] (DxvkContext* ctx, const D3D11CmdDrawIndirectData* data) {
+ ctx->drawIndexedIndirect(data->offset, data->count, data->stride);
+ });
+
+ cmdData->type = D3D11CmdType::DrawIndirectIndexed;
+ cmdData->offset = AlignedByteOffsetForArgs;
+ cmdData->count = 1;
+ cmdData->stride = 0;
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DrawInstancedIndirect(
+ ID3D11Buffer* pBufferForArgs,
+ UINT AlignedByteOffsetForArgs) {
+ D3D10DeviceLock lock = LockContext();
+ SetDrawBuffers(pBufferForArgs, nullptr);
+
+ if (!ValidateDrawBufferSize(pBufferForArgs, AlignedByteOffsetForArgs, sizeof(VkDrawIndirectCommand)))
+ return;
+
+ // If possible, batch up multiple indirect draw calls of
+ // the same type into one single multiDrawIndirect call
+ auto cmdData = static_cast<D3D11CmdDrawIndirectData*>(m_cmdData);
+ auto stride = 0u;
+
+ if (cmdData && cmdData->type == D3D11CmdType::DrawIndirect)
+ stride = GetIndirectCommandStride(cmdData, AlignedByteOffsetForArgs, sizeof(VkDrawIndirectCommand));
+
+ if (stride) {
+ cmdData->count += 1;
+ cmdData->stride = stride;
+ } else {
+ cmdData = EmitCsCmd<D3D11CmdDrawIndirectData>(
+ [] (DxvkContext* ctx, const D3D11CmdDrawIndirectData* data) {
+ ctx->drawIndirect(data->offset, data->count, data->stride);
+ });
+
+ cmdData->type = D3D11CmdType::DrawIndirect;
+ cmdData->offset = AlignedByteOffsetForArgs;
+ cmdData->count = 1;
+ cmdData->stride = 0;
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::Dispatch(
+ UINT ThreadGroupCountX,
+ UINT ThreadGroupCountY,
+ UINT ThreadGroupCountZ) {
+ D3D10DeviceLock lock = LockContext();
+
+ EmitCs([=] (DxvkContext* ctx) {
+ ctx->dispatch(
+ ThreadGroupCountX,
+ ThreadGroupCountY,
+ ThreadGroupCountZ);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DispatchIndirect(
+ ID3D11Buffer* pBufferForArgs,
+ UINT AlignedByteOffsetForArgs) {
+ D3D10DeviceLock lock = LockContext();
+ SetDrawBuffers(pBufferForArgs, nullptr);
+
+ if (!ValidateDrawBufferSize(pBufferForArgs, AlignedByteOffsetForArgs, sizeof(VkDispatchIndirectCommand)))
+ return;
+
+ EmitCs([cOffset = AlignedByteOffsetForArgs]
+ (DxvkContext* ctx) {
+ ctx->dispatchIndirect(cOffset);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::IASetInputLayout(ID3D11InputLayout* pInputLayout) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto inputLayout = static_cast<D3D11InputLayout*>(pInputLayout);
+
+ if (m_state.ia.inputLayout != inputLayout) {
+ bool equal = false;
+
+ // Some games (e.g. Grim Dawn) create lots and lots of
+ // identical input layouts, so we'll only apply the state
+ // if the input layouts has actually changed between calls.
+ if (m_state.ia.inputLayout != nullptr && inputLayout != nullptr)
+ equal = m_state.ia.inputLayout->Compare(inputLayout);
+
+ m_state.ia.inputLayout = inputLayout;
+
+ if (!equal)
+ ApplyInputLayout();
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY Topology) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (m_state.ia.primitiveTopology != Topology) {
+ m_state.ia.primitiveTopology = Topology;
+ ApplyPrimitiveTopology();
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::IASetVertexBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppVertexBuffers,
+ const UINT* pStrides,
+ const UINT* pOffsets) {
+ D3D10DeviceLock lock = LockContext();
+
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ auto newBuffer = static_cast<D3D11Buffer*>(ppVertexBuffers[i]);
+ bool needsUpdate = m_state.ia.vertexBuffers[StartSlot + i].buffer != newBuffer;
+
+ if (needsUpdate)
+ m_state.ia.vertexBuffers[StartSlot + i].buffer = newBuffer;
+
+ needsUpdate |= m_state.ia.vertexBuffers[StartSlot + i].offset != pOffsets[i]
+ || m_state.ia.vertexBuffers[StartSlot + i].stride != pStrides[i];
+
+ if (needsUpdate) {
+ m_state.ia.vertexBuffers[StartSlot + i].offset = pOffsets[i];
+ m_state.ia.vertexBuffers[StartSlot + i].stride = pStrides[i];
+
+ BindVertexBuffer(StartSlot + i, newBuffer, pOffsets[i], pStrides[i]);
+ }
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::IASetIndexBuffer(
+ ID3D11Buffer* pIndexBuffer,
+ DXGI_FORMAT Format,
+ UINT Offset) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto newBuffer = static_cast<D3D11Buffer*>(pIndexBuffer);
+ bool needsUpdate = m_state.ia.indexBuffer.buffer != newBuffer;
+
+ if (needsUpdate)
+ m_state.ia.indexBuffer.buffer = newBuffer;
+
+ needsUpdate |= m_state.ia.indexBuffer.offset != Offset
+ || m_state.ia.indexBuffer.format != Format;
+
+ if (needsUpdate) {
+ m_state.ia.indexBuffer.offset = Offset;
+ m_state.ia.indexBuffer.format = Format;
+
+ BindIndexBuffer(newBuffer, Offset, Format);
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::IAGetInputLayout(ID3D11InputLayout** ppInputLayout) {
+ D3D10DeviceLock lock = LockContext();
+
+ *ppInputLayout = m_state.ia.inputLayout.ref();
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::IAGetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY* pTopology) {
+ D3D10DeviceLock lock = LockContext();
+
+ *pTopology = m_state.ia.primitiveTopology;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::IAGetVertexBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppVertexBuffers,
+ UINT* pStrides,
+ UINT* pOffsets) {
+ D3D10DeviceLock lock = LockContext();
+
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ const bool inRange = StartSlot + i < m_state.ia.vertexBuffers.size();
+
+ if (ppVertexBuffers != nullptr) {
+ ppVertexBuffers[i] = inRange
+ ? m_state.ia.vertexBuffers[StartSlot + i].buffer.ref()
+ : nullptr;
+ }
+
+ if (pStrides != nullptr) {
+ pStrides[i] = inRange
+ ? m_state.ia.vertexBuffers[StartSlot + i].stride
+ : 0u;
+ }
+
+ if (pOffsets != nullptr) {
+ pOffsets[i] = inRange
+ ? m_state.ia.vertexBuffers[StartSlot + i].offset
+ : 0u;
+ }
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::IAGetIndexBuffer(
+ ID3D11Buffer** ppIndexBuffer,
+ DXGI_FORMAT* pFormat,
+ UINT* pOffset) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppIndexBuffer != nullptr)
+ *ppIndexBuffer = m_state.ia.indexBuffer.buffer.ref();
+
+ if (pFormat != nullptr)
+ *pFormat = m_state.ia.indexBuffer.format;
+
+ if (pOffset != nullptr)
+ *pOffset = m_state.ia.indexBuffer.offset;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::VSSetShader(
+ ID3D11VertexShader* pVertexShader,
+ ID3D11ClassInstance* const* ppClassInstances,
+ UINT NumClassInstances) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto shader = static_cast<D3D11VertexShader*>(pVertexShader);
+
+ if (NumClassInstances != 0)
+ Logger::err("D3D11: Class instances not supported");
+
+ if (m_state.vs.shader != shader) {
+ m_state.vs.shader = shader;
+
+ BindShader<DxbcProgramType::VertexShader>(GetCommonShader(shader));
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::VSSetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetConstantBuffers<DxbcProgramType::VertexShader>(
+ m_state.vs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::VSSetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers,
+ const UINT* pFirstConstant,
+ const UINT* pNumConstants) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetConstantBuffers1<DxbcProgramType::VertexShader>(
+ m_state.vs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ pFirstConstant,
+ pNumConstants);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::VSSetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView* const* ppShaderResourceViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetShaderResources<DxbcProgramType::VertexShader>(
+ m_state.vs.shaderResources,
+ StartSlot, NumViews,
+ ppShaderResourceViews);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::VSSetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState* const* ppSamplers) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetSamplers<DxbcProgramType::VertexShader>(
+ m_state.vs.samplers,
+ StartSlot, NumSamplers,
+ ppSamplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::VSGetShader(
+ ID3D11VertexShader** ppVertexShader,
+ ID3D11ClassInstance** ppClassInstances,
+ UINT* pNumClassInstances) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppVertexShader != nullptr)
+ *ppVertexShader = m_state.vs.shader.ref();
+
+ if (pNumClassInstances != nullptr)
+ *pNumClassInstances = 0;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::VSGetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetConstantBuffers(
+ m_state.vs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ nullptr, nullptr);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::VSGetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers,
+ UINT* pFirstConstant,
+ UINT* pNumConstants) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetConstantBuffers(
+ m_state.vs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ pFirstConstant,
+ pNumConstants);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::VSGetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView** ppShaderResourceViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetShaderResources(m_state.vs.shaderResources,
+ StartSlot, NumViews, ppShaderResourceViews);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::VSGetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState** ppSamplers) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetSamplers(m_state.vs.samplers,
+ StartSlot, NumSamplers, ppSamplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::HSSetShader(
+ ID3D11HullShader* pHullShader,
+ ID3D11ClassInstance* const* ppClassInstances,
+ UINT NumClassInstances) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto shader = static_cast<D3D11HullShader*>(pHullShader);
+
+ if (NumClassInstances != 0)
+ Logger::err("D3D11: Class instances not supported");
+
+ if (m_state.hs.shader != shader) {
+ m_state.hs.shader = shader;
+
+ BindShader<DxbcProgramType::HullShader>(GetCommonShader(shader));
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::HSSetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView* const* ppShaderResourceViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetShaderResources<DxbcProgramType::HullShader>(
+ m_state.hs.shaderResources,
+ StartSlot, NumViews,
+ ppShaderResourceViews);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::HSSetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetConstantBuffers<DxbcProgramType::HullShader>(
+ m_state.hs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::HSSetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers,
+ const UINT* pFirstConstant,
+ const UINT* pNumConstants) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetConstantBuffers1<DxbcProgramType::HullShader>(
+ m_state.hs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ pFirstConstant,
+ pNumConstants);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::HSSetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState* const* ppSamplers) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetSamplers<DxbcProgramType::HullShader>(
+ m_state.hs.samplers,
+ StartSlot, NumSamplers,
+ ppSamplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::HSGetShader(
+ ID3D11HullShader** ppHullShader,
+ ID3D11ClassInstance** ppClassInstances,
+ UINT* pNumClassInstances) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppHullShader != nullptr)
+ *ppHullShader = m_state.hs.shader.ref();
+
+ if (pNumClassInstances != nullptr)
+ *pNumClassInstances = 0;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::HSGetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetConstantBuffers(
+ m_state.hs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ nullptr, nullptr);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::HSGetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers,
+ UINT* pFirstConstant,
+ UINT* pNumConstants) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetConstantBuffers(
+ m_state.hs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ pFirstConstant,
+ pNumConstants);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::HSGetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView** ppShaderResourceViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetShaderResources(m_state.hs.shaderResources,
+ StartSlot, NumViews, ppShaderResourceViews);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::HSGetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState** ppSamplers) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetSamplers(m_state.hs.samplers,
+ StartSlot, NumSamplers, ppSamplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DSSetShader(
+ ID3D11DomainShader* pDomainShader,
+ ID3D11ClassInstance* const* ppClassInstances,
+ UINT NumClassInstances) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto shader = static_cast<D3D11DomainShader*>(pDomainShader);
+
+ if (NumClassInstances != 0)
+ Logger::err("D3D11: Class instances not supported");
+
+ if (m_state.ds.shader != shader) {
+ m_state.ds.shader = shader;
+
+ BindShader<DxbcProgramType::DomainShader>(GetCommonShader(shader));
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DSSetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView* const* ppShaderResourceViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetShaderResources<DxbcProgramType::DomainShader>(
+ m_state.ds.shaderResources,
+ StartSlot, NumViews,
+ ppShaderResourceViews);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DSSetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetConstantBuffers<DxbcProgramType::DomainShader>(
+ m_state.ds.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DSSetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers,
+ const UINT* pFirstConstant,
+ const UINT* pNumConstants) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetConstantBuffers1<DxbcProgramType::DomainShader>(
+ m_state.ds.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ pFirstConstant,
+ pNumConstants);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DSSetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState* const* ppSamplers) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetSamplers<DxbcProgramType::DomainShader>(
+ m_state.ds.samplers,
+ StartSlot, NumSamplers,
+ ppSamplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DSGetShader(
+ ID3D11DomainShader** ppDomainShader,
+ ID3D11ClassInstance** ppClassInstances,
+ UINT* pNumClassInstances) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppDomainShader != nullptr)
+ *ppDomainShader = m_state.ds.shader.ref();
+
+ if (pNumClassInstances != nullptr)
+ *pNumClassInstances = 0;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DSGetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetConstantBuffers(
+ m_state.ds.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ nullptr, nullptr);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DSGetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers,
+ UINT* pFirstConstant,
+ UINT* pNumConstants) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetConstantBuffers(
+ m_state.ds.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ pFirstConstant,
+ pNumConstants);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DSGetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView** ppShaderResourceViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetShaderResources(m_state.ds.shaderResources,
+ StartSlot, NumViews, ppShaderResourceViews);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DSGetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState** ppSamplers) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetSamplers(m_state.ds.samplers,
+ StartSlot, NumSamplers, ppSamplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GSSetShader(
+ ID3D11GeometryShader* pShader,
+ ID3D11ClassInstance* const* ppClassInstances,
+ UINT NumClassInstances) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto shader = static_cast<D3D11GeometryShader*>(pShader);
+
+ if (NumClassInstances != 0)
+ Logger::err("D3D11: Class instances not supported");
+
+ if (m_state.gs.shader != shader) {
+ m_state.gs.shader = shader;
+
+ BindShader<DxbcProgramType::GeometryShader>(GetCommonShader(shader));
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GSSetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetConstantBuffers<DxbcProgramType::GeometryShader>(
+ m_state.gs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GSSetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers,
+ const UINT* pFirstConstant,
+ const UINT* pNumConstants) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetConstantBuffers1<DxbcProgramType::GeometryShader>(
+ m_state.gs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ pFirstConstant,
+ pNumConstants);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GSSetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView* const* ppShaderResourceViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetShaderResources<DxbcProgramType::GeometryShader>(
+ m_state.gs.shaderResources,
+ StartSlot, NumViews,
+ ppShaderResourceViews);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GSSetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState* const* ppSamplers) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetSamplers<DxbcProgramType::GeometryShader>(
+ m_state.gs.samplers,
+ StartSlot, NumSamplers,
+ ppSamplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GSGetShader(
+ ID3D11GeometryShader** ppGeometryShader,
+ ID3D11ClassInstance** ppClassInstances,
+ UINT* pNumClassInstances) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppGeometryShader != nullptr)
+ *ppGeometryShader = m_state.gs.shader.ref();
+
+ if (pNumClassInstances != nullptr)
+ *pNumClassInstances = 0;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GSGetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetConstantBuffers(
+ m_state.gs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ nullptr, nullptr);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GSGetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers,
+ UINT* pFirstConstant,
+ UINT* pNumConstants) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetConstantBuffers(
+ m_state.gs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ pFirstConstant,
+ pNumConstants);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GSGetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView** ppShaderResourceViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetShaderResources(m_state.gs.shaderResources,
+ StartSlot, NumViews, ppShaderResourceViews);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GSGetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState** ppSamplers) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetSamplers(m_state.gs.samplers,
+ StartSlot, NumSamplers, ppSamplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::PSSetShader(
+ ID3D11PixelShader* pPixelShader,
+ ID3D11ClassInstance* const* ppClassInstances,
+ UINT NumClassInstances) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto shader = static_cast<D3D11PixelShader*>(pPixelShader);
+
+ if (NumClassInstances != 0)
+ Logger::err("D3D11: Class instances not supported");
+
+ if (m_state.ps.shader != shader) {
+ m_state.ps.shader = shader;
+
+ BindShader<DxbcProgramType::PixelShader>(GetCommonShader(shader));
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::PSSetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetConstantBuffers<DxbcProgramType::PixelShader>(
+ m_state.ps.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::PSSetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers,
+ const UINT* pFirstConstant,
+ const UINT* pNumConstants) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetConstantBuffers1<DxbcProgramType::PixelShader>(
+ m_state.ps.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ pFirstConstant,
+ pNumConstants);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::PSSetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView* const* ppShaderResourceViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetShaderResources<DxbcProgramType::PixelShader>(
+ m_state.ps.shaderResources,
+ StartSlot, NumViews,
+ ppShaderResourceViews);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::PSSetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState* const* ppSamplers) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetSamplers<DxbcProgramType::PixelShader>(
+ m_state.ps.samplers,
+ StartSlot, NumSamplers,
+ ppSamplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::PSGetShader(
+ ID3D11PixelShader** ppPixelShader,
+ ID3D11ClassInstance** ppClassInstances,
+ UINT* pNumClassInstances) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppPixelShader != nullptr)
+ *ppPixelShader = m_state.ps.shader.ref();
+
+ if (pNumClassInstances != nullptr)
+ *pNumClassInstances = 0;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::PSGetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetConstantBuffers(
+ m_state.ps.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ nullptr, nullptr);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::PSGetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers,
+ UINT* pFirstConstant,
+ UINT* pNumConstants) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetConstantBuffers(
+ m_state.ps.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ pFirstConstant,
+ pNumConstants);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::PSGetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView** ppShaderResourceViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetShaderResources(m_state.ps.shaderResources,
+ StartSlot, NumViews, ppShaderResourceViews);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::PSGetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState** ppSamplers) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetSamplers(m_state.ps.samplers,
+ StartSlot, NumSamplers, ppSamplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CSSetShader(
+ ID3D11ComputeShader* pComputeShader,
+ ID3D11ClassInstance* const* ppClassInstances,
+ UINT NumClassInstances) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto shader = static_cast<D3D11ComputeShader*>(pComputeShader);
+
+ if (NumClassInstances != 0)
+ Logger::err("D3D11: Class instances not supported");
+
+ if (m_state.cs.shader != shader) {
+ m_state.cs.shader = shader;
+
+ BindShader<DxbcProgramType::ComputeShader>(GetCommonShader(shader));
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CSSetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetConstantBuffers<DxbcProgramType::ComputeShader>(
+ m_state.cs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CSSetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers,
+ const UINT* pFirstConstant,
+ const UINT* pNumConstants) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetConstantBuffers1<DxbcProgramType::ComputeShader>(
+ m_state.cs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ pFirstConstant,
+ pNumConstants);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CSSetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView* const* ppShaderResourceViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetShaderResources<DxbcProgramType::ComputeShader>(
+ m_state.cs.shaderResources,
+ StartSlot, NumViews,
+ ppShaderResourceViews);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CSSetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState* const* ppSamplers) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetSamplers<DxbcProgramType::ComputeShader>(
+ m_state.cs.samplers,
+ StartSlot, NumSamplers,
+ ppSamplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CSSetUnorderedAccessViews(
+ UINT StartSlot,
+ UINT NumUAVs,
+ ID3D11UnorderedAccessView* const* ppUnorderedAccessViews,
+ const UINT* pUAVInitialCounts) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (TestRtvUavHazards(0, nullptr, NumUAVs, ppUnorderedAccessViews))
+ return;
+
+ // Unbind previously bound conflicting UAVs
+ uint32_t uavSlotId = computeUavBinding (DxbcProgramType::ComputeShader, 0);
+ uint32_t ctrSlotId = computeUavCounterBinding(DxbcProgramType::ComputeShader, 0);
+
+ int32_t uavId = m_state.cs.uavMask.findNext(0);
+
+ while (uavId >= 0) {
+ if (uint32_t(uavId) < StartSlot || uint32_t(uavId) >= StartSlot + NumUAVs) {
+ for (uint32_t i = 0; i < NumUAVs; i++) {
+ auto uav = static_cast<D3D11UnorderedAccessView*>(ppUnorderedAccessViews[i]);
+
+ if (CheckViewOverlap(uav, m_state.cs.unorderedAccessViews[uavId].ptr())) {
+ m_state.cs.unorderedAccessViews[uavId] = nullptr;
+ m_state.cs.uavMask.clr(uavId);
+
+ BindUnorderedAccessView(
+ uavSlotId + uavId, nullptr,
+ ctrSlotId + uavId, ~0u);
+ }
+ }
+
+ uavId = m_state.cs.uavMask.findNext(uavId + 1);
+ } else {
+ uavId = m_state.cs.uavMask.findNext(StartSlot + NumUAVs);
+ }
+ }
+
+ // Actually bind the given UAVs
+ for (uint32_t i = 0; i < NumUAVs; i++) {
+ auto uav = static_cast<D3D11UnorderedAccessView*>(ppUnorderedAccessViews[i]);
+ auto ctr = pUAVInitialCounts ? pUAVInitialCounts[i] : ~0u;
+
+ if (m_state.cs.unorderedAccessViews[StartSlot + i] != uav || ctr != ~0u) {
+ m_state.cs.unorderedAccessViews[StartSlot + i] = uav;
+ m_state.cs.uavMask.set(StartSlot + i, uav != nullptr);
+
+ BindUnorderedAccessView(
+ uavSlotId + StartSlot + i, uav,
+ ctrSlotId + StartSlot + i, ctr);
+
+ ResolveCsSrvHazards(uav);
+ }
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CSGetShader(
+ ID3D11ComputeShader** ppComputeShader,
+ ID3D11ClassInstance** ppClassInstances,
+ UINT* pNumClassInstances) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppComputeShader != nullptr)
+ *ppComputeShader = m_state.cs.shader.ref();
+
+ if (pNumClassInstances != nullptr)
+ *pNumClassInstances = 0;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CSGetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetConstantBuffers(
+ m_state.cs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ nullptr, nullptr);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CSGetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers,
+ UINT* pFirstConstant,
+ UINT* pNumConstants) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetConstantBuffers(
+ m_state.cs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ pFirstConstant,
+ pNumConstants);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CSGetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView** ppShaderResourceViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetShaderResources(m_state.cs.shaderResources,
+ StartSlot, NumViews, ppShaderResourceViews);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CSGetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState** ppSamplers) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetSamplers(m_state.cs.samplers,
+ StartSlot, NumSamplers, ppSamplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CSGetUnorderedAccessViews(
+ UINT StartSlot,
+ UINT NumUAVs,
+ ID3D11UnorderedAccessView** ppUnorderedAccessViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ for (uint32_t i = 0; i < NumUAVs; i++) {
+ ppUnorderedAccessViews[i] = StartSlot + i < m_state.cs.unorderedAccessViews.size()
+ ? m_state.cs.unorderedAccessViews[StartSlot + i].ref()
+ : nullptr;
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::OMSetRenderTargets(
+ UINT NumViews,
+ ID3D11RenderTargetView* const* ppRenderTargetViews,
+ ID3D11DepthStencilView* pDepthStencilView) {
+ OMSetRenderTargetsAndUnorderedAccessViews(
+ NumViews, ppRenderTargetViews, pDepthStencilView,
+ NumViews, 0, nullptr, nullptr);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::OMSetRenderTargetsAndUnorderedAccessViews(
+ UINT NumRTVs,
+ ID3D11RenderTargetView* const* ppRenderTargetViews,
+ ID3D11DepthStencilView* pDepthStencilView,
+ UINT UAVStartSlot,
+ UINT NumUAVs,
+ ID3D11UnorderedAccessView* const* ppUnorderedAccessViews,
+ const UINT* pUAVInitialCounts) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (TestRtvUavHazards(NumRTVs, ppRenderTargetViews, NumUAVs, ppUnorderedAccessViews))
+ return;
+
+ bool needsUpdate = false;
+
+ if (likely(NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL)) {
+ // Native D3D11 does not change the render targets if
+ // the parameters passed to this method are invalid.
+ if (!ValidateRenderTargets(NumRTVs, ppRenderTargetViews, pDepthStencilView))
+ return;
+
+ for (uint32_t i = 0; i < m_state.om.renderTargetViews.size(); i++) {
+ auto rtv = i < NumRTVs
+ ? static_cast<D3D11RenderTargetView*>(ppRenderTargetViews[i])
+ : nullptr;
+
+ if (m_state.om.renderTargetViews[i] != rtv) {
+ m_state.om.renderTargetViews[i] = rtv;
+ needsUpdate = true;
+ ResolveOmSrvHazards(rtv);
+
+ if (NumUAVs == D3D11_KEEP_UNORDERED_ACCESS_VIEWS)
+ ResolveOmUavHazards(rtv);
+ }
+ }
+
+ auto dsv = static_cast<D3D11DepthStencilView*>(pDepthStencilView);
+
+ if (m_state.om.depthStencilView != dsv) {
+ m_state.om.depthStencilView = dsv;
+ needsUpdate = true;
+ ResolveOmSrvHazards(dsv);
+ }
+
+ m_state.om.maxRtv = NumRTVs;
+ }
+
+ if (unlikely(NumUAVs || m_state.om.maxUav)) {
+ uint32_t uavSlotId = computeUavBinding (DxbcProgramType::PixelShader, 0);
+ uint32_t ctrSlotId = computeUavCounterBinding(DxbcProgramType::PixelShader, 0);
+
+ if (likely(NumUAVs != D3D11_KEEP_UNORDERED_ACCESS_VIEWS)) {
+ uint32_t newMaxUav = NumUAVs ? UAVStartSlot + NumUAVs : 0;
+ uint32_t oldMaxUav = std::exchange(m_state.om.maxUav, newMaxUav);
+
+ for (uint32_t i = 0; i < std::max(oldMaxUav, newMaxUav); i++) {
+ D3D11UnorderedAccessView* uav = nullptr;
+ uint32_t ctr = ~0u;
+
+ if (i >= UAVStartSlot && i < UAVStartSlot + NumUAVs) {
+ uav = static_cast<D3D11UnorderedAccessView*>(ppUnorderedAccessViews[i - UAVStartSlot]);
+ ctr = pUAVInitialCounts ? pUAVInitialCounts[i - UAVStartSlot] : ~0u;
+ }
+
+ if (m_state.ps.unorderedAccessViews[i] != uav || ctr != ~0u) {
+ m_state.ps.unorderedAccessViews[i] = uav;
+
+ BindUnorderedAccessView(
+ uavSlotId + i, uav,
+ ctrSlotId + i, ctr);
+
+ ResolveOmSrvHazards(uav);
+
+ if (NumRTVs == D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL)
+ needsUpdate |= ResolveOmRtvHazards(uav);
+ }
+ }
+ }
+ }
+
+ if (needsUpdate)
+ BindFramebuffer();
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::OMSetBlendState(
+ ID3D11BlendState* pBlendState,
+ const FLOAT BlendFactor[4],
+ UINT SampleMask) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto blendState = static_cast<D3D11BlendState*>(pBlendState);
+
+ if (m_state.om.cbState != blendState
+ || m_state.om.sampleMask != SampleMask) {
+ m_state.om.cbState = blendState;
+ m_state.om.sampleMask = SampleMask;
+
+ ApplyBlendState();
+ }
+
+ if (BlendFactor != nullptr) {
+ for (uint32_t i = 0; i < 4; i++)
+ m_state.om.blendFactor[i] = BlendFactor[i];
+
+ ApplyBlendFactor();
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::OMSetDepthStencilState(
+ ID3D11DepthStencilState* pDepthStencilState,
+ UINT StencilRef) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto depthStencilState = static_cast<D3D11DepthStencilState*>(pDepthStencilState);
+
+ if (m_state.om.dsState != depthStencilState) {
+ m_state.om.dsState = depthStencilState;
+ ApplyDepthStencilState();
+ }
+
+ if (m_state.om.stencilRef != StencilRef) {
+ m_state.om.stencilRef = StencilRef;
+ ApplyStencilRef();
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::OMGetRenderTargets(
+ UINT NumViews,
+ ID3D11RenderTargetView** ppRenderTargetViews,
+ ID3D11DepthStencilView** ppDepthStencilView) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppRenderTargetViews != nullptr) {
+ for (UINT i = 0; i < NumViews; i++) {
+ ppRenderTargetViews[i] = i < m_state.om.renderTargetViews.size()
+ ? m_state.om.renderTargetViews[i].ref()
+ : nullptr;
+ }
+ }
+
+ if (ppDepthStencilView != nullptr)
+ *ppDepthStencilView = m_state.om.depthStencilView.ref();
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::OMGetRenderTargetsAndUnorderedAccessViews(
+ UINT NumRTVs,
+ ID3D11RenderTargetView** ppRenderTargetViews,
+ ID3D11DepthStencilView** ppDepthStencilView,
+ UINT UAVStartSlot,
+ UINT NumUAVs,
+ ID3D11UnorderedAccessView** ppUnorderedAccessViews) {
+ OMGetRenderTargets(NumRTVs, ppRenderTargetViews, ppDepthStencilView);
+
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppUnorderedAccessViews != nullptr) {
+ for (UINT i = 0; i < NumUAVs; i++) {
+ ppUnorderedAccessViews[i] = UAVStartSlot + i < m_state.ps.unorderedAccessViews.size()
+ ? m_state.ps.unorderedAccessViews[UAVStartSlot + i].ref()
+ : nullptr;
+ }
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::OMGetBlendState(
+ ID3D11BlendState** ppBlendState,
+ FLOAT BlendFactor[4],
+ UINT* pSampleMask) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppBlendState != nullptr)
+ *ppBlendState = ref(m_state.om.cbState);
+
+ if (BlendFactor != nullptr)
+ std::memcpy(BlendFactor, m_state.om.blendFactor, sizeof(FLOAT) * 4);
+
+ if (pSampleMask != nullptr)
+ *pSampleMask = m_state.om.sampleMask;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::OMGetDepthStencilState(
+ ID3D11DepthStencilState** ppDepthStencilState,
+ UINT* pStencilRef) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppDepthStencilState != nullptr)
+ *ppDepthStencilState = ref(m_state.om.dsState);
+
+ if (pStencilRef != nullptr)
+ *pStencilRef = m_state.om.stencilRef;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::RSSetState(ID3D11RasterizerState* pRasterizerState) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto rasterizerState = static_cast<D3D11RasterizerState*>(pRasterizerState);
+
+ bool currScissorEnable = m_state.rs.state != nullptr
+ ? m_state.rs.state->Desc()->ScissorEnable
+ : false;
+
+ bool nextScissorEnable = rasterizerState != nullptr
+ ? rasterizerState->Desc()->ScissorEnable
+ : false;
+
+ if (m_state.rs.state != rasterizerState) {
+ m_state.rs.state = rasterizerState;
+
+ // In D3D11, the rasterizer state defines whether the
+ // scissor test is enabled, so we have to update the
+ // scissor rectangles as well.
+ ApplyRasterizerState();
+
+ if (currScissorEnable != nextScissorEnable)
+ ApplyViewportState();
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::RSSetViewports(
+ UINT NumViewports,
+ const D3D11_VIEWPORT* pViewports) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (unlikely(NumViewports > m_state.rs.viewports.size()))
+ return;
+
+ bool dirty = m_state.rs.numViewports != NumViewports;
+ m_state.rs.numViewports = NumViewports;
+
+ for (uint32_t i = 0; i < NumViewports; i++) {
+ const D3D11_VIEWPORT& vp = m_state.rs.viewports[i];
+
+ dirty |= vp.TopLeftX != pViewports[i].TopLeftX
+ || vp.TopLeftY != pViewports[i].TopLeftY
+ || vp.Width != pViewports[i].Width
+ || vp.Height != pViewports[i].Height
+ || vp.MinDepth != pViewports[i].MinDepth
+ || vp.MaxDepth != pViewports[i].MaxDepth;
+
+ m_state.rs.viewports[i] = pViewports[i];
+ }
+
+ if (dirty)
+ ApplyViewportState();
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::RSSetScissorRects(
+ UINT NumRects,
+ const D3D11_RECT* pRects) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (unlikely(NumRects > m_state.rs.scissors.size()))
+ return;
+
+ bool dirty = m_state.rs.numScissors != NumRects;
+ m_state.rs.numScissors = NumRects;
+
+ for (uint32_t i = 0; i < NumRects; i++) {
+ if (pRects[i].bottom >= pRects[i].top
+ && pRects[i].right >= pRects[i].left) {
+ const D3D11_RECT& sr = m_state.rs.scissors[i];
+
+ dirty |= sr.top != pRects[i].top
+ || sr.left != pRects[i].left
+ || sr.bottom != pRects[i].bottom
+ || sr.right != pRects[i].right;
+
+ m_state.rs.scissors[i] = pRects[i];
+ }
+ }
+
+ if (m_state.rs.state != nullptr && dirty) {
+ D3D11_RASTERIZER_DESC rsDesc;
+ m_state.rs.state->GetDesc(&rsDesc);
+
+ if (rsDesc.ScissorEnable)
+ ApplyViewportState();
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::RSGetState(ID3D11RasterizerState** ppRasterizerState) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppRasterizerState != nullptr)
+ *ppRasterizerState = ref(m_state.rs.state);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::RSGetViewports(
+ UINT* pNumViewports,
+ D3D11_VIEWPORT* pViewports) {
+ D3D10DeviceLock lock = LockContext();
+ uint32_t numWritten = m_state.rs.numViewports;
+
+ if (pViewports) {
+ numWritten = std::min(numWritten, *pNumViewports);
+
+ for (uint32_t i = 0; i < *pNumViewports; i++) {
+ if (i < m_state.rs.numViewports) {
+ pViewports[i] = m_state.rs.viewports[i];
+ } else {
+ pViewports[i].TopLeftX = 0.0f;
+ pViewports[i].TopLeftY = 0.0f;
+ pViewports[i].Width = 0.0f;
+ pViewports[i].Height = 0.0f;
+ pViewports[i].MinDepth = 0.0f;
+ pViewports[i].MaxDepth = 0.0f;
+ }
+ }
+ }
+
+ *pNumViewports = numWritten;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::RSGetScissorRects(
+ UINT* pNumRects,
+ D3D11_RECT* pRects) {
+ D3D10DeviceLock lock = LockContext();
+ uint32_t numWritten = m_state.rs.numScissors;
+
+ if (pRects) {
+ numWritten = std::min(numWritten, *pNumRects);
+
+ for (uint32_t i = 0; i < *pNumRects; i++) {
+ if (i < m_state.rs.numScissors) {
+ pRects[i] = m_state.rs.scissors[i];
+ } else {
+ pRects[i].left = 0;
+ pRects[i].top = 0;
+ pRects[i].right = 0;
+ pRects[i].bottom = 0;
+ }
+ }
+ }
+
+ *pNumRects = m_state.rs.numScissors;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::SOSetTargets(
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppSOTargets,
+ const UINT* pOffsets) {
+ D3D10DeviceLock lock = LockContext();
+
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ D3D11Buffer* buffer = static_cast<D3D11Buffer*>(ppSOTargets[i]);
+ UINT offset = pOffsets != nullptr ? pOffsets[i] : 0;
+
+ m_state.so.targets[i].buffer = buffer;
+ m_state.so.targets[i].offset = offset;
+ }
+
+ for (uint32_t i = NumBuffers; i < D3D11_SO_BUFFER_SLOT_COUNT; i++) {
+ m_state.so.targets[i].buffer = nullptr;
+ m_state.so.targets[i].offset = 0;
+ }
+
+ for (uint32_t i = 0; i < D3D11_SO_BUFFER_SLOT_COUNT; i++) {
+ BindXfbBuffer(i,
+ m_state.so.targets[i].buffer.ptr(),
+ m_state.so.targets[i].offset);
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::SOGetTargets(
+ UINT NumBuffers,
+ ID3D11Buffer** ppSOTargets) {
+ D3D10DeviceLock lock = LockContext();
+
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ ppSOTargets[i] = i < m_state.so.targets.size()
+ ? m_state.so.targets[i].buffer.ref()
+ : nullptr;
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::SOGetTargetsWithOffsets(
+ UINT NumBuffers,
+ ID3D11Buffer** ppSOTargets,
+ UINT* pOffsets) {
+ D3D10DeviceLock lock = LockContext();
+
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ const bool inRange = i < m_state.so.targets.size();
+
+ if (ppSOTargets != nullptr) {
+ ppSOTargets[i] = inRange
+ ? m_state.so.targets[i].buffer.ref()
+ : nullptr;
+ }
+
+ if (pOffsets != nullptr) {
+ pOffsets[i] = inRange
+ ? m_state.so.targets[i].offset
+ : 0u;
+ }
+ }
+ }
+
+
+ BOOL STDMETHODCALLTYPE D3D11DeviceContext::IsAnnotationEnabled() {
+ return m_device->instance()->extensions().extDebugUtils;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::SetMarkerInt(
+ LPCWSTR pLabel,
+ INT Data) {
+ // Not implemented in the backend, ignore
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::BeginEventInt(
+ LPCWSTR pLabel,
+ INT Data) {
+ // Not implemented in the backend, ignore
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::EndEvent() {
+ // Not implemented in the backend, ignore
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GetHardwareProtectionState(
+ BOOL* pHwProtectionEnable) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::err("D3D11DeviceContext::GetHardwareProtectionState: Not implemented");
+
+ if (pHwProtectionEnable)
+ *pHwProtectionEnable = FALSE;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::SetHardwareProtectionState(
+ BOOL HwProtectionEnable) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::err("D3D11DeviceContext::SetHardwareProtectionState: Not implemented");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::TransitionSurfaceLayout(
+ IDXGIVkInteropSurface* pSurface,
+ const VkImageSubresourceRange* pSubresources,
+ VkImageLayout OldLayout,
+ VkImageLayout NewLayout) {
+ D3D10DeviceLock lock = LockContext();
+
+ // Get the underlying D3D11 resource
+ Com<ID3D11Resource> resource;
+
+ pSurface->QueryInterface(__uuidof(ID3D11Resource),
+ reinterpret_cast<void**>(&resource));
+
+ // Get the texture from that resource
+ D3D11CommonTexture* texture = GetCommonTexture(resource.ptr());
+
+ EmitCs([
+ cImage = texture->GetImage(),
+ cSubresources = *pSubresources,
+ cOldLayout = OldLayout,
+ cNewLayout = NewLayout
+ ] (DxvkContext* ctx) {
+ ctx->transformImage(
+ cImage, cSubresources,
+ cOldLayout, cNewLayout);
+ });
+ }
+
+
+ void D3D11DeviceContext::ApplyInputLayout() {
+ auto inputLayout = m_state.ia.inputLayout.prvRef();
+
+ if (likely(inputLayout != nullptr)) {
+ EmitCs([
+ cInputLayout = std::move(inputLayout)
+ ] (DxvkContext* ctx) {
+ cInputLayout->BindToContext(ctx);
+ });
+ } else {
+ EmitCs([] (DxvkContext* ctx) {
+ ctx->setInputLayout(0, nullptr, 0, nullptr);
+ });
+ }
+ }
+
+
+ void D3D11DeviceContext::ApplyPrimitiveTopology() {
+ D3D11_PRIMITIVE_TOPOLOGY topology = m_state.ia.primitiveTopology;
+ DxvkInputAssemblyState iaState = { };
+
+ if (topology <= D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ) {
+ static const std::array<DxvkInputAssemblyState, 14> s_iaStates = {{
+ { VK_PRIMITIVE_TOPOLOGY_MAX_ENUM, VK_FALSE, 0 },
+ { VK_PRIMITIVE_TOPOLOGY_POINT_LIST, VK_FALSE, 0 },
+ { VK_PRIMITIVE_TOPOLOGY_LINE_LIST, VK_FALSE, 0 },
+ { VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, VK_TRUE, 0 },
+ { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_FALSE, 0 },
+ { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, VK_TRUE, 0 },
+ { }, { }, { }, { }, // Random gap that exists for no reason
+ { VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY, VK_FALSE, 0 },
+ { VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY, VK_TRUE, 0 },
+ { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY, VK_FALSE, 0 },
+ { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY, VK_TRUE, 0 },
+ }};
+
+ iaState = s_iaStates[uint32_t(topology)];
+ } else if (topology >= D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST
+ && topology <= D3D11_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST) {
+ // The number of control points per patch can be inferred from the enum value in D3D11
+ uint32_t vertexCount = uint32_t(topology - D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + 1);
+ iaState = { VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, VK_FALSE, vertexCount };
+ }
+
+ EmitCs([iaState] (DxvkContext* ctx) {
+ ctx->setInputAssemblyState(iaState);
+ });
+ }
+
+
+ void D3D11DeviceContext::ApplyBlendState() {
+ if (m_state.om.cbState != nullptr) {
+ EmitCs([
+ cBlendState = m_state.om.cbState,
+ cSampleMask = m_state.om.sampleMask
+ ] (DxvkContext* ctx) {
+ cBlendState->BindToContext(ctx, cSampleMask);
+ });
+ } else {
+ EmitCs([
+ cSampleMask = m_state.om.sampleMask
+ ] (DxvkContext* ctx) {
+ DxvkBlendMode cbState;
+ DxvkLogicOpState loState;
+ DxvkMultisampleState msState;
+ InitDefaultBlendState(&cbState, &loState, &msState, cSampleMask);
+
+ for (uint32_t i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
+ ctx->setBlendMode(i, cbState);
+
+ ctx->setLogicOpState(loState);
+ ctx->setMultisampleState(msState);
+ });
+ }
+ }
+
+
+ void D3D11DeviceContext::ApplyBlendFactor() {
+ EmitCs([
+ cBlendConstants = DxvkBlendConstants {
+ m_state.om.blendFactor[0], m_state.om.blendFactor[1],
+ m_state.om.blendFactor[2], m_state.om.blendFactor[3] }
+ ] (DxvkContext* ctx) {
+ ctx->setBlendConstants(cBlendConstants);
+ });
+ }
+
+
+ void D3D11DeviceContext::ApplyDepthStencilState() {
+ if (m_state.om.dsState != nullptr) {
+ EmitCs([
+ cDepthStencilState = m_state.om.dsState
+ ] (DxvkContext* ctx) {
+ cDepthStencilState->BindToContext(ctx);
+ });
+ } else {
+ EmitCs([] (DxvkContext* ctx) {
+ DxvkDepthStencilState dsState;
+ InitDefaultDepthStencilState(&dsState);
+
+ ctx->setDepthStencilState(dsState);
+ });
+ }
+ }
+
+
+ void D3D11DeviceContext::ApplyStencilRef() {
+ EmitCs([
+ cStencilRef = m_state.om.stencilRef
+ ] (DxvkContext* ctx) {
+ ctx->setStencilReference(cStencilRef);
+ });
+ }
+
+
+ void D3D11DeviceContext::ApplyRasterizerState() {
+ if (m_state.rs.state != nullptr) {
+ EmitCs([
+ cRasterizerState = m_state.rs.state
+ ] (DxvkContext* ctx) {
+ cRasterizerState->BindToContext(ctx);
+ });
+ } else {
+ EmitCs([] (DxvkContext* ctx) {
+ DxvkRasterizerState rsState;
+ InitDefaultRasterizerState(&rsState);
+
+ ctx->setRasterizerState(rsState);
+ });
+ }
+ }
+
+
+ void D3D11DeviceContext::ApplyViewportState() {
+ std::array<VkViewport, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE> viewports;
+ std::array<VkRect2D, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE> scissors;
+
+ // The backend can't handle a viewport count of zero,
+ // so we should at least specify one empty viewport
+ uint32_t viewportCount = m_state.rs.numViewports;
+
+ if (unlikely(!viewportCount)) {
+ viewportCount = 1;
+ viewports[0] = VkViewport();
+ scissors [0] = VkRect2D();
+ }
+
+ // D3D11's coordinate system has its origin in the bottom left,
+ // but the viewport coordinates are aligned to the top-left
+ // corner so we can get away with flipping the viewport.
+ for (uint32_t i = 0; i < m_state.rs.numViewports; i++) {
+ const D3D11_VIEWPORT& vp = m_state.rs.viewports[i];
+
+ viewports[i] = VkViewport {
+ vp.TopLeftX, vp.Height + vp.TopLeftY,
+ vp.Width, -vp.Height,
+ vp.MinDepth, vp.MaxDepth,
+ };
+ }
+
+ // Scissor rectangles. Vulkan does not provide an easy way
+ // to disable the scissor test, so we'll have to set scissor
+ // rects that are at least as large as the framebuffer.
+ bool enableScissorTest = false;
+
+ if (m_state.rs.state != nullptr) {
+ D3D11_RASTERIZER_DESC rsDesc;
+ m_state.rs.state->GetDesc(&rsDesc);
+ enableScissorTest = rsDesc.ScissorEnable;
+ }
+
+ for (uint32_t i = 0; i < m_state.rs.numViewports; i++) {
+ if (!enableScissorTest) {
+ scissors[i] = VkRect2D {
+ VkOffset2D { 0, 0 },
+ VkExtent2D {
+ D3D11_VIEWPORT_BOUNDS_MAX,
+ D3D11_VIEWPORT_BOUNDS_MAX } };
+ } else if (i >= m_state.rs.numScissors) {
+ scissors[i] = VkRect2D {
+ VkOffset2D { 0, 0 },
+ VkExtent2D { 0, 0 } };
+ } else {
+ D3D11_RECT sr = m_state.rs.scissors[i];
+
+ VkOffset2D srPosA;
+ srPosA.x = std::max<int32_t>(0, sr.left);
+ srPosA.y = std::max<int32_t>(0, sr.top);
+
+ VkOffset2D srPosB;
+ srPosB.x = std::max<int32_t>(srPosA.x, sr.right);
+ srPosB.y = std::max<int32_t>(srPosA.y, sr.bottom);
+
+ VkExtent2D srSize;
+ srSize.width = uint32_t(srPosB.x - srPosA.x);
+ srSize.height = uint32_t(srPosB.y - srPosA.y);
+
+ scissors[i] = VkRect2D { srPosA, srSize };
+ }
+ }
+
+ if (likely(viewportCount == 1)) {
+ EmitCs([
+ cViewport = viewports[0],
+ cScissor = scissors[0]
+ ] (DxvkContext* ctx) {
+ ctx->setViewports(1,
+ &cViewport,
+ &cScissor);
+ });
+ } else {
+ EmitCs([
+ cViewportCount = viewportCount,
+ cViewports = viewports,
+ cScissors = scissors
+ ] (DxvkContext* ctx) {
+ ctx->setViewports(
+ cViewportCount,
+ cViewports.data(),
+ cScissors.data());
+ });
+ }
+ }
+
+
+ template<DxbcProgramType ShaderStage>
+ void D3D11DeviceContext::BindShader(
+ const D3D11CommonShader* pShaderModule) {
+ // Bind the shader and the ICB at once
+ EmitCs([
+ cSlice = pShaderModule != nullptr
+ && pShaderModule->GetIcb() != nullptr
+ ? DxvkBufferSlice(pShaderModule->GetIcb())
+ : DxvkBufferSlice(),
+ cShader = pShaderModule != nullptr
+ ? pShaderModule->GetShader()
+ : nullptr
+ ] (DxvkContext* ctx) {
+ VkShaderStageFlagBits stage = GetShaderStage(ShaderStage);
+
+ uint32_t slotId = computeConstantBufferBinding(ShaderStage,
+ D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT);
+
+ ctx->bindShader (stage, cShader);
+ ctx->bindResourceBuffer(slotId, cSlice);
+ });
+ }
+
+
+ void D3D11DeviceContext::BindFramebuffer() {
+ DxvkRenderTargets attachments;
+
+ // D3D11 doesn't have the concept of a framebuffer object,
+ // so we'll just create a new one every time the render
+ // target bindings are updated. Set up the attachments.
+ for (UINT i = 0; i < m_state.om.renderTargetViews.size(); i++) {
+ if (m_state.om.renderTargetViews[i] != nullptr) {
+ attachments.color[i] = {
+ m_state.om.renderTargetViews[i]->GetImageView(),
+ m_state.om.renderTargetViews[i]->GetRenderLayout() };
+ }
+ }
+
+ if (m_state.om.depthStencilView != nullptr) {
+ attachments.depth = {
+ m_state.om.depthStencilView->GetImageView(),
+ m_state.om.depthStencilView->GetRenderLayout() };
+ }
+
+ // Create and bind the framebuffer object to the context
+ EmitCs([
+ cAttachments = std::move(attachments)
+ ] (DxvkContext* ctx) {
+ ctx->bindRenderTargets(cAttachments);
+ });
+ }
+
+
+ void D3D11DeviceContext::BindDrawBuffers(
+ D3D11Buffer* pBufferForArgs,
+ D3D11Buffer* pBufferForCount) {
+ EmitCs([
+ cArgBuffer = pBufferForArgs ? pBufferForArgs->GetBufferSlice() : DxvkBufferSlice(),
+ cCntBuffer = pBufferForCount ? pBufferForCount->GetBufferSlice() : DxvkBufferSlice()
+ ] (DxvkContext* ctx) {
+ ctx->bindDrawBuffers(cArgBuffer, cCntBuffer);
+ });
+ }
+
+
+ void D3D11DeviceContext::BindVertexBuffer(
+ UINT Slot,
+ D3D11Buffer* pBuffer,
+ UINT Offset,
+ UINT Stride) {
+ EmitCs([
+ cSlotId = Slot,
+ cBufferSlice = pBuffer != nullptr ? pBuffer->GetBufferSlice(Offset) : DxvkBufferSlice(),
+ cStride = Stride
+ ] (DxvkContext* ctx) {
+ ctx->bindVertexBuffer(cSlotId, cBufferSlice, cStride);
+ });
+ }
+
+
+ void D3D11DeviceContext::BindIndexBuffer(
+ D3D11Buffer* pBuffer,
+ UINT Offset,
+ DXGI_FORMAT Format) {
+ VkIndexType indexType = Format == DXGI_FORMAT_R16_UINT
+ ? VK_INDEX_TYPE_UINT16
+ : VK_INDEX_TYPE_UINT32;
+
+ EmitCs([
+ cBufferSlice = pBuffer != nullptr ? pBuffer->GetBufferSlice(Offset) : DxvkBufferSlice(),
+ cIndexType = indexType
+ ] (DxvkContext* ctx) {
+ ctx->bindIndexBuffer(cBufferSlice, cIndexType);
+ });
+ }
+
+
+ void D3D11DeviceContext::BindXfbBuffer(
+ UINT Slot,
+ D3D11Buffer* pBuffer,
+ UINT Offset) {
+ DxvkBufferSlice bufferSlice;
+ DxvkBufferSlice counterSlice;
+
+ if (pBuffer != nullptr) {
+ bufferSlice = pBuffer->GetBufferSlice();
+ counterSlice = pBuffer->GetSOCounter();
+ }
+
+ EmitCs([
+ cSlotId = Slot,
+ cOffset = Offset,
+ cBufferSlice = bufferSlice,
+ cCounterSlice = counterSlice
+ ] (DxvkContext* ctx) {
+ if (cCounterSlice.defined() && cOffset != ~0u) {
+ ctx->updateBuffer(
+ cCounterSlice.buffer(),
+ cCounterSlice.offset(),
+ sizeof(cOffset),
+ &cOffset);
+ }
+
+ ctx->bindXfbBuffer(cSlotId, cBufferSlice, cCounterSlice);
+ });
+ }
+
+
+ void D3D11DeviceContext::BindConstantBuffer(
+ UINT Slot,
+ D3D11Buffer* pBuffer,
+ UINT Offset,
+ UINT Length) {
+ EmitCs([
+ cSlotId = Slot,
+ cBufferSlice = Length ? pBuffer->GetBufferSlice(16 * Offset, 16 * Length) : DxvkBufferSlice()
+ ] (DxvkContext* ctx) {
+ ctx->bindResourceBuffer(cSlotId, cBufferSlice);
+ });
+ }
+
+
+ void D3D11DeviceContext::BindSampler(
+ UINT Slot,
+ D3D11SamplerState* pSampler) {
+ EmitCs([
+ cSlotId = Slot,
+ cSampler = pSampler != nullptr ? pSampler->GetDXVKSampler() : nullptr
+ ] (DxvkContext* ctx) {
+ ctx->bindResourceSampler(cSlotId, cSampler);
+ });
+ }
+
+
+ void D3D11DeviceContext::BindShaderResource(
+ UINT Slot,
+ D3D11ShaderResourceView* pResource) {
+ EmitCs([
+ cSlotId = Slot,
+ cImageView = pResource != nullptr ? pResource->GetImageView() : nullptr,
+ cBufferView = pResource != nullptr ? pResource->GetBufferView() : nullptr
+ ] (DxvkContext* ctx) {
+ ctx->bindResourceView(cSlotId, cImageView, cBufferView);
+ });
+ }
+
+
+ void D3D11DeviceContext::BindUnorderedAccessView(
+ UINT UavSlot,
+ D3D11UnorderedAccessView* pUav,
+ UINT CtrSlot,
+ UINT Counter) {
+ EmitCs([
+ cUavSlotId = UavSlot,
+ cCtrSlotId = CtrSlot,
+ cImageView = pUav != nullptr ? pUav->GetImageView() : nullptr,
+ cBufferView = pUav != nullptr ? pUav->GetBufferView() : nullptr,
+ cCounterSlice = pUav != nullptr ? pUav->GetCounterSlice() : DxvkBufferSlice(),
+ cCounterValue = Counter
+ ] (DxvkContext* ctx) {
+ if (cCounterSlice.defined() && cCounterValue != ~0u) {
+ ctx->updateBuffer(
+ cCounterSlice.buffer(),
+ cCounterSlice.offset(),
+ sizeof(uint32_t),
+ &cCounterValue);
+ }
+
+ ctx->bindResourceView (cUavSlotId, cImageView, cBufferView);
+ ctx->bindResourceBuffer (cCtrSlotId, cCounterSlice);
+ });
+ }
+
+
+ void D3D11DeviceContext::CopyBuffer(
+ D3D11Buffer* pDstBuffer,
+ VkDeviceSize DstOffset,
+ D3D11Buffer* pSrcBuffer,
+ VkDeviceSize SrcOffset,
+ VkDeviceSize ByteCount) {
+ // Clamp copy region to prevent out-of-bounds access
+ VkDeviceSize dstLength = pDstBuffer->Desc()->ByteWidth;
+ VkDeviceSize srcLength = pSrcBuffer->Desc()->ByteWidth;
+
+ if (SrcOffset >= srcLength || DstOffset >= dstLength || !ByteCount)
+ return;
+
+ ByteCount = std::min(dstLength - DstOffset, ByteCount);
+ ByteCount = std::min(srcLength - SrcOffset, ByteCount);
+
+ EmitCs([
+ cDstBuffer = pDstBuffer->GetBufferSlice(DstOffset, ByteCount),
+ cSrcBuffer = pSrcBuffer->GetBufferSlice(SrcOffset, ByteCount)
+ ] (DxvkContext* ctx) {
+ if (cDstBuffer.buffer() != cSrcBuffer.buffer()) {
+ ctx->copyBuffer(
+ cDstBuffer.buffer(),
+ cDstBuffer.offset(),
+ cSrcBuffer.buffer(),
+ cSrcBuffer.offset(),
+ cSrcBuffer.length());
+ } else {
+ ctx->copyBufferRegion(
+ cDstBuffer.buffer(),
+ cDstBuffer.offset(),
+ cSrcBuffer.offset(),
+ cSrcBuffer.length());
+ }
+ });
+ }
+
+
+ void D3D11DeviceContext::CopyImage(
+ D3D11CommonTexture* pDstTexture,
+ const VkImageSubresourceLayers* pDstLayers,
+ VkOffset3D DstOffset,
+ D3D11CommonTexture* pSrcTexture,
+ const VkImageSubresourceLayers* pSrcLayers,
+ VkOffset3D SrcOffset,
+ VkExtent3D SrcExtent) {
+ // Image formats must be size-compatible
+ auto dstFormatInfo = imageFormatInfo(pDstTexture->GetPackedFormat());
+ auto srcFormatInfo = imageFormatInfo(pSrcTexture->GetPackedFormat());
+
+ if (dstFormatInfo->elementSize != srcFormatInfo->elementSize) {
+ Logger::err("D3D11: CopyImage: Incompatible texel size");
+ return;
+ }
+
+ // Sample counts must match
+ if (pDstTexture->Desc()->SampleDesc.Count != pSrcTexture->Desc()->SampleDesc.Count) {
+ Logger::err("D3D11: CopyImage: Incompatible sample count");
+ return;
+ }
+
+ // Obviously, the copy region must not be empty
+ VkExtent3D dstMipExtent = pDstTexture->MipLevelExtent(pDstLayers->mipLevel);
+ VkExtent3D srcMipExtent = pSrcTexture->MipLevelExtent(pSrcLayers->mipLevel);
+
+ if (uint32_t(DstOffset.x) >= dstMipExtent.width
+ || uint32_t(DstOffset.y) >= dstMipExtent.height
+ || uint32_t(DstOffset.z) >= dstMipExtent.depth)
+ return;
+
+ if (uint32_t(SrcOffset.x) >= srcMipExtent.width
+ || uint32_t(SrcOffset.y) >= srcMipExtent.height
+ || uint32_t(SrcOffset.z) >= srcMipExtent.depth)
+ return;
+
+ // Don't perform the copy if the offsets aren't block-aligned
+ if (!util::isBlockAligned(SrcOffset, srcFormatInfo->blockSize)
+ || !util::isBlockAligned(DstOffset, dstFormatInfo->blockSize)) {
+ Logger::err(str::format("D3D11: CopyImage: Unaligned block offset"));
+ return;
+ }
+
+ // Clamp the image region in order to avoid out-of-bounds access
+ VkExtent3D blockCount = util::computeBlockCount(SrcExtent, srcFormatInfo->blockSize);
+ VkExtent3D dstBlockCount = util::computeMaxBlockCount(DstOffset, dstMipExtent, dstFormatInfo->blockSize);
+ VkExtent3D srcBlockCount = util::computeMaxBlockCount(SrcOffset, srcMipExtent, srcFormatInfo->blockSize);
+
+ blockCount = util::minExtent3D(blockCount, dstBlockCount);
+ blockCount = util::minExtent3D(blockCount, srcBlockCount);
+
+ SrcExtent = util::computeBlockExtent(blockCount, srcFormatInfo->blockSize);
+ SrcExtent = util::snapExtent3D(SrcOffset, SrcExtent, srcMipExtent);
+
+ if (!SrcExtent.width || !SrcExtent.height || !SrcExtent.depth)
+ return;
+
+ // While copying between 2D and 3D images is allowed in CopySubresourceRegion,
+ // copying more than one slice at a time is not suppoted. Layer counts are 1.
+ if ((pDstTexture->GetVkImageType() == VK_IMAGE_TYPE_3D)
+ != (pSrcTexture->GetVkImageType() == VK_IMAGE_TYPE_3D))
+ SrcExtent.depth = 1;
+
+ // Certain types of copies require us to pass the destination extent to
+ // the backend. This may be different when copying between compressed
+ // and uncompressed image formats.
+ VkExtent3D dstExtent = util::computeBlockExtent(blockCount, dstFormatInfo->blockSize);
+ dstExtent = util::snapExtent3D(DstOffset, dstExtent, dstMipExtent);
+
+ // It is possible for any of the given images to be a staging image with
+ // no actual image, so we need to account for all possibilities here.
+ bool dstIsImage = pDstTexture->GetMapMode() != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING;
+ bool srcIsImage = pSrcTexture->GetMapMode() != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING;
+
+ if (dstIsImage && srcIsImage) {
+ EmitCs([
+ cDstImage = pDstTexture->GetImage(),
+ cSrcImage = pSrcTexture->GetImage(),
+ cDstLayers = *pDstLayers,
+ cSrcLayers = *pSrcLayers,
+ cDstOffset = DstOffset,
+ cSrcOffset = SrcOffset,
+ cExtent = SrcExtent
+ ] (DxvkContext* ctx) {
+ // CopyResource can only copy between different images, and
+ // CopySubresourceRegion can only copy data from one single
+ // subresource at a time, so this check is safe.
+ if (cDstImage != cSrcImage || cDstLayers != cSrcLayers) {
+ ctx->copyImage(
+ cDstImage, cDstLayers, cDstOffset,
+ cSrcImage, cSrcLayers, cSrcOffset,
+ cExtent);
+ } else {
+ ctx->copyImageRegion(
+ cDstImage, cDstLayers, cDstOffset,
+ cSrcOffset, cExtent);
+ }
+ });
+ } else {
+ // Since each subresource uses a dedicated buffer, we are going
+ // to need one call per subresource for staging resource copies
+ for (uint32_t i = 0; i < pDstLayers->layerCount; i++) {
+ uint32_t dstSubresource = D3D11CalcSubresource(pDstLayers->mipLevel, pDstLayers->baseArrayLayer + i, pDstTexture->Desc()->MipLevels);
+ uint32_t srcSubresource = D3D11CalcSubresource(pSrcLayers->mipLevel, pSrcLayers->baseArrayLayer + i, pSrcTexture->Desc()->MipLevels);
+
+ // For multi-plane image data stored in a buffer, the backend
+ // assumes that the second plane immediately follows the first
+ // plane in memory, which is only true if we copy the full image.
+ uint32_t planeCount = 1;
+
+ if (dstFormatInfo->flags.test(DxvkFormatFlag::MultiPlane)) {
+ bool needsSeparateCopies = !dstIsImage && !srcIsImage;
+
+ if (!dstIsImage)
+ needsSeparateCopies |= pDstTexture->MipLevelExtent(pDstLayers->mipLevel) != SrcExtent;
+ if (!srcIsImage)
+ needsSeparateCopies |= pSrcTexture->MipLevelExtent(pSrcLayers->mipLevel) != SrcExtent;
+
+ if (needsSeparateCopies)
+ planeCount = vk::getPlaneCount(srcFormatInfo->aspectMask);
+ }
+
+ for (uint32_t j = 0; j < planeCount; j++) {
+ VkImageAspectFlags dstAspectMask = dstFormatInfo->aspectMask;
+ VkImageAspectFlags srcAspectMask = srcFormatInfo->aspectMask;
+
+ if (planeCount > 1) {
+ dstAspectMask = vk::getPlaneAspect(j);
+ srcAspectMask = dstAspectMask;
+ }
+
+ if (dstIsImage) {
+ VkImageSubresourceLayers dstLayer = { dstAspectMask,
+ pDstLayers->mipLevel, pDstLayers->baseArrayLayer + i, 1 };
+
+ EmitCs([
+ cDstImage = pDstTexture->GetImage(),
+ cDstLayers = dstLayer,
+ cDstOffset = DstOffset,
+ cDstExtent = dstExtent,
+ cSrcBuffer = pSrcTexture->GetMappedBuffer(srcSubresource),
+ cSrcLayout = pSrcTexture->GetSubresourceLayout(srcAspectMask, srcSubresource),
+ cSrcOffset = pSrcTexture->ComputeMappedOffset(srcSubresource, j, SrcOffset),
+ cSrcCoord = SrcOffset,
+ cSrcExtent = srcMipExtent,
+ cSrcFormat = pSrcTexture->GetPackedFormat()
+ ] (DxvkContext* ctx) {
+ if (cDstLayers.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
+ ctx->copyBufferToImage(cDstImage, cDstLayers, cDstOffset, cDstExtent,
+ cSrcBuffer, cSrcOffset, cSrcLayout.RowPitch, cSrcLayout.DepthPitch);
+ } else {
+ ctx->copyPackedBufferToDepthStencilImage(cDstImage, cDstLayers,
+ VkOffset2D { cDstOffset.x, cDstOffset.y },
+ VkExtent2D { cDstExtent.width, cDstExtent.height },
+ cSrcBuffer, cSrcLayout.Offset,
+ VkOffset2D { cSrcCoord.x, cSrcCoord.y },
+ VkExtent2D { cSrcExtent.width, cSrcExtent.height },
+ cSrcFormat);
+ }
+ });
+ } else if (srcIsImage) {
+ VkImageSubresourceLayers srcLayer = { srcAspectMask,
+ pSrcLayers->mipLevel, pSrcLayers->baseArrayLayer + i, 1 };
+
+ EmitCs([
+ cSrcImage = pSrcTexture->GetImage(),
+ cSrcLayers = srcLayer,
+ cSrcOffset = SrcOffset,
+ cSrcExtent = SrcExtent,
+ cDstBuffer = pDstTexture->GetMappedBuffer(dstSubresource),
+ cDstLayout = pDstTexture->GetSubresourceLayout(dstAspectMask, dstSubresource),
+ cDstOffset = pDstTexture->ComputeMappedOffset(dstSubresource, j, DstOffset),
+ cDstCoord = DstOffset,
+ cDstExtent = dstMipExtent,
+ cDstFormat = pDstTexture->GetPackedFormat()
+ ] (DxvkContext* ctx) {
+ if (cSrcLayers.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
+ ctx->copyImageToBuffer(cDstBuffer, cDstOffset, cDstLayout.RowPitch,
+ cDstLayout.DepthPitch, cSrcImage, cSrcLayers, cSrcOffset, cSrcExtent);
+ } else {
+ ctx->copyDepthStencilImageToPackedBuffer(cDstBuffer, cDstLayout.Offset,
+ VkOffset2D { cDstCoord.x, cDstCoord.y },
+ VkExtent2D { cDstExtent.width, cDstExtent.height },
+ cSrcImage, cSrcLayers,
+ VkOffset2D { cSrcOffset.x, cSrcOffset.y },
+ VkExtent2D { cSrcExtent.width, cSrcExtent.height },
+ cDstFormat);
+ }
+ });
+ } else {
+ // The backend is not aware of image metadata in this case,
+ // so we need to handle image planes and block sizes here
+ VkDeviceSize elementSize = dstFormatInfo->elementSize;
+ VkExtent3D dstBlockSize = dstFormatInfo->blockSize;
+ VkExtent3D srcBlockSize = srcFormatInfo->blockSize;
+ VkExtent3D planeBlockSize = { 1u, 1u, 1u };
+
+ if (planeCount > 1) {
+ auto plane = &dstFormatInfo->planes[j];
+ dstBlockSize.width *= plane->blockSize.width;
+ dstBlockSize.height *= plane->blockSize.height;
+ srcBlockSize.width *= plane->blockSize.width;
+ srcBlockSize.height *= plane->blockSize.height;
+
+ planeBlockSize.width = plane->blockSize.width;
+ planeBlockSize.height = plane->blockSize.height;
+ elementSize = plane->elementSize;
+ }
+
+ EmitCs([
+ cPixelSize = elementSize,
+ cSrcBuffer = pSrcTexture->GetMappedBuffer(srcSubresource),
+ cSrcStart = pSrcTexture->GetSubresourceLayout(srcAspectMask, srcSubresource).Offset,
+ cSrcOffset = util::computeBlockOffset(SrcOffset, srcBlockSize),
+ cSrcSize = util::computeBlockCount(srcMipExtent, srcBlockSize),
+ cDstBuffer = pDstTexture->GetMappedBuffer(dstSubresource),
+ cDstStart = pDstTexture->GetSubresourceLayout(dstAspectMask, dstSubresource).Offset,
+ cDstOffset = util::computeBlockOffset(DstOffset, dstBlockSize),
+ cDstSize = util::computeBlockCount(dstMipExtent, dstBlockSize),
+ cExtent = util::computeBlockCount(blockCount, planeBlockSize)
+ ] (DxvkContext* ctx) {
+ ctx->copyPackedBufferImage(
+ cDstBuffer, cDstStart, cDstOffset, cDstSize,
+ cSrcBuffer, cSrcStart, cSrcOffset, cSrcSize,
+ cExtent, cPixelSize);
+ });
+ }
+ }
+ }
+ }
+ }
+
+
+ void D3D11DeviceContext::DiscardBuffer(
+ ID3D11Resource* pResource) {
+ auto buffer = static_cast<D3D11Buffer*>(pResource);
+
+ if (buffer->GetMapMode() != D3D11_COMMON_BUFFER_MAP_MODE_NONE) {
+ D3D11_MAPPED_SUBRESOURCE sr;
+
+ Map(pResource, 0, D3D11_MAP_WRITE_DISCARD, 0, &sr);
+ Unmap(pResource, 0);
+ }
+ }
+
+
+ void D3D11DeviceContext::DiscardTexture(
+ ID3D11Resource* pResource,
+ UINT Subresource) {
+ auto texture = GetCommonTexture(pResource);
+
+ if (texture->GetMapMode() != D3D11_COMMON_TEXTURE_MAP_MODE_NONE) {
+ D3D11_MAPPED_SUBRESOURCE sr;
+
+ Map(pResource, Subresource, D3D11_MAP_WRITE_DISCARD, 0, &sr);
+ Unmap(pResource, Subresource);
+ }
+ }
+
+
+ void D3D11DeviceContext::UpdateImage(
+ D3D11CommonTexture* pDstTexture,
+ const VkImageSubresource* pDstSubresource,
+ VkOffset3D DstOffset,
+ VkExtent3D DstExtent,
+ DxvkBufferSlice StagingBuffer) {
+ bool dstIsImage = pDstTexture->GetMapMode() != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING;
+
+ if (dstIsImage) {
+ EmitCs([
+ cDstImage = pDstTexture->GetImage(),
+ cDstLayers = vk::makeSubresourceLayers(*pDstSubresource),
+ cDstOffset = DstOffset,
+ cDstExtent = DstExtent,
+ cStagingSlice = std::move(StagingBuffer),
+ cPackedFormat = pDstTexture->GetPackedFormat()
+ ] (DxvkContext* ctx) {
+ if (cDstLayers.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
+ ctx->copyBufferToImage(cDstImage,
+ cDstLayers, cDstOffset, cDstExtent,
+ cStagingSlice.buffer(),
+ cStagingSlice.offset(), 0, 0);
+ } else {
+ ctx->copyPackedBufferToDepthStencilImage(cDstImage, cDstLayers,
+ VkOffset2D { cDstOffset.x, cDstOffset.y },
+ VkExtent2D { cDstExtent.width, cDstExtent.height },
+ cStagingSlice.buffer(),
+ cStagingSlice.offset(),
+ VkOffset2D { 0, 0 },
+ VkExtent2D { cDstExtent.width, cDstExtent.height },
+ cPackedFormat);
+ }
+ });
+ } else {
+ // If the destination image is backed only by a buffer, we need to use
+ // the packed buffer copy function which does not know about planes and
+ // format metadata, so deal with it manually here.
+ VkExtent3D dstMipExtent = pDstTexture->MipLevelExtent(pDstSubresource->mipLevel);
+
+ uint32_t dstSubresource = D3D11CalcSubresource(pDstSubresource->mipLevel,
+ pDstSubresource->arrayLayer, pDstTexture->Desc()->MipLevels);
+
+ auto dstFormat = pDstTexture->GetPackedFormat();
+ auto dstFormatInfo = imageFormatInfo(dstFormat);
+
+ uint32_t planeCount = 1;
+
+ if (dstFormatInfo->flags.test(DxvkFormatFlag::MultiPlane))
+ planeCount = vk::getPlaneCount(dstFormatInfo->aspectMask);
+
+ // The source data isn't stored in an image so we'll also need to
+ // track the offset for that while iterating over the planes.
+ VkDeviceSize srcPlaneOffset = 0;
+
+ for (uint32_t i = 0; i < planeCount; i++) {
+ VkImageAspectFlags dstAspectMask = dstFormatInfo->aspectMask;
+ VkDeviceSize elementSize = dstFormatInfo->elementSize;
+ VkExtent3D blockSize = dstFormatInfo->blockSize;
+
+ if (dstFormatInfo->flags.test(DxvkFormatFlag::MultiPlane)) {
+ dstAspectMask = vk::getPlaneAspect(i);
+
+ auto plane = &dstFormatInfo->planes[i];
+ blockSize.width *= plane->blockSize.width;
+ blockSize.height *= plane->blockSize.height;
+ elementSize = plane->elementSize;
+ }
+
+ VkExtent3D blockCount = util::computeBlockCount(DstExtent, blockSize);
+
+ EmitCs([
+ cDstBuffer = pDstTexture->GetMappedBuffer(dstSubresource),
+ cDstStart = pDstTexture->GetSubresourceLayout(dstAspectMask, dstSubresource).Offset,
+ cDstOffset = util::computeBlockOffset(DstOffset, blockSize),
+ cDstSize = util::computeBlockCount(dstMipExtent, blockSize),
+ cDstExtent = blockCount,
+ cSrcBuffer = StagingBuffer.buffer(),
+ cSrcStart = StagingBuffer.offset() + srcPlaneOffset,
+ cPixelSize = elementSize
+ ] (DxvkContext* ctx) {
+ ctx->copyPackedBufferImage(
+ cDstBuffer, cDstStart, cDstOffset, cDstSize,
+ cSrcBuffer, cSrcStart, VkOffset3D(), cDstExtent,
+ cDstExtent, cPixelSize);
+ });
+
+ srcPlaneOffset += util::flattenImageExtent(blockCount) * elementSize;
+ }
+ }
+ }
+
+
+ void D3D11DeviceContext::SetDrawBuffers(
+ ID3D11Buffer* pBufferForArgs,
+ ID3D11Buffer* pBufferForCount) {
+ auto argBuffer = static_cast<D3D11Buffer*>(pBufferForArgs);
+ auto cntBuffer = static_cast<D3D11Buffer*>(pBufferForCount);
+
+ if (m_state.id.argBuffer != argBuffer
+ || m_state.id.cntBuffer != cntBuffer) {
+ m_state.id.argBuffer = argBuffer;
+ m_state.id.cntBuffer = cntBuffer;
+
+ BindDrawBuffers(argBuffer, cntBuffer);
+ }
+ }
+
+
+ template<DxbcProgramType ShaderStage>
+ void D3D11DeviceContext::SetConstantBuffers(
+ D3D11ConstantBufferBindings& Bindings,
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers) {
+ uint32_t slotId = computeConstantBufferBinding(ShaderStage, StartSlot);
+
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ auto newBuffer = static_cast<D3D11Buffer*>(ppConstantBuffers[i]);
+
+ UINT constantCount = 0;
+
+ if (likely(newBuffer != nullptr))
+ constantCount = std::min(newBuffer->Desc()->ByteWidth / 16, UINT(D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT));
+
+ if (Bindings[StartSlot + i].buffer != newBuffer
+ || Bindings[StartSlot + i].constantCount != constantCount) {
+ Bindings[StartSlot + i].buffer = newBuffer;
+ Bindings[StartSlot + i].constantOffset = 0;
+ Bindings[StartSlot + i].constantCount = constantCount;
+ Bindings[StartSlot + i].constantBound = constantCount;
+
+ BindConstantBuffer(slotId + i, newBuffer, 0, constantCount);
+ }
+ }
+ }
+
+
+ template<DxbcProgramType ShaderStage>
+ void D3D11DeviceContext::SetConstantBuffers1(
+ D3D11ConstantBufferBindings& Bindings,
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers,
+ const UINT* pFirstConstant,
+ const UINT* pNumConstants) {
+ uint32_t slotId = computeConstantBufferBinding(ShaderStage, StartSlot);
+
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ auto newBuffer = static_cast<D3D11Buffer*>(ppConstantBuffers[i]);
+
+ UINT constantOffset;
+ UINT constantCount;
+ UINT constantBound;
+
+ if (likely(newBuffer != nullptr)) {
+ UINT bufferConstantsCount = newBuffer->Desc()->ByteWidth / 16;
+ constantBound = std::min(bufferConstantsCount, UINT(D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT));
+
+ if (likely(pFirstConstant && pNumConstants)) {
+ constantOffset = pFirstConstant[i];
+ constantCount = pNumConstants [i];
+
+ if (unlikely(constantCount > D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT))
+ continue;
+
+ constantBound = (constantOffset + constantCount > bufferConstantsCount)
+ ? bufferConstantsCount - std::min(constantOffset, bufferConstantsCount)
+ : constantCount;
+ } else {
+ constantOffset = 0;
+ constantCount = constantBound;
+ }
+ } else {
+ constantOffset = 0;
+ constantCount = 0;
+ constantBound = 0;
+ }
+
+ bool needsUpdate = Bindings[StartSlot + i].buffer != newBuffer;
+
+ if (needsUpdate)
+ Bindings[StartSlot + i].buffer = newBuffer;
+
+ needsUpdate |= Bindings[StartSlot + i].constantOffset != constantOffset
+ || Bindings[StartSlot + i].constantCount != constantCount;
+
+ if (needsUpdate) {
+ Bindings[StartSlot + i].constantOffset = constantOffset;
+ Bindings[StartSlot + i].constantCount = constantCount;
+ Bindings[StartSlot + i].constantBound = constantBound;
+
+ BindConstantBuffer(slotId + i, newBuffer, constantOffset, constantBound);
+ }
+ }
+ }
+
+
+ template<DxbcProgramType ShaderStage>
+ void D3D11DeviceContext::SetSamplers(
+ D3D11SamplerBindings& Bindings,
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState* const* ppSamplers) {
+ uint32_t slotId = computeSamplerBinding(ShaderStage, StartSlot);
+
+ for (uint32_t i = 0; i < NumSamplers; i++) {
+ auto sampler = static_cast<D3D11SamplerState*>(ppSamplers[i]);
+
+ if (Bindings[StartSlot + i] != sampler) {
+ Bindings[StartSlot + i] = sampler;
+ BindSampler(slotId + i, sampler);
+ }
+ }
+ }
+
+
+ template<DxbcProgramType ShaderStage>
+ void D3D11DeviceContext::SetShaderResources(
+ D3D11ShaderResourceBindings& Bindings,
+ UINT StartSlot,
+ UINT NumResources,
+ ID3D11ShaderResourceView* const* ppResources) {
+ uint32_t slotId = computeSrvBinding(ShaderStage, StartSlot);
+
+ for (uint32_t i = 0; i < NumResources; i++) {
+ auto resView = static_cast<D3D11ShaderResourceView*>(ppResources[i]);
+
+ if (Bindings.views[StartSlot + i] != resView) {
+ if (unlikely(resView && resView->TestHazards())) {
+ if (TestSrvHazards<ShaderStage>(resView))
+ resView = nullptr;
+
+ // Only set if necessary, but don't reset it on every
+ // bind as this would be more expensive than a few
+ // redundant checks in OMSetRenderTargets and friends.
+ Bindings.hazardous.set(StartSlot + i, resView);
+ }
+
+ Bindings.views[StartSlot + i] = resView;
+ BindShaderResource(slotId + i, resView);
+ }
+ }
+ }
+
+
+ void D3D11DeviceContext::GetConstantBuffers(
+ const D3D11ConstantBufferBindings& Bindings,
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers,
+ UINT* pFirstConstant,
+ UINT* pNumConstants) {
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ const bool inRange = StartSlot + i < Bindings.size();
+
+ if (ppConstantBuffers != nullptr) {
+ ppConstantBuffers[i] = inRange
+ ? Bindings[StartSlot + i].buffer.ref()
+ : nullptr;
+ }
+
+ if (pFirstConstant != nullptr) {
+ pFirstConstant[i] = inRange
+ ? Bindings[StartSlot + i].constantOffset
+ : 0u;
+ }
+
+ if (pNumConstants != nullptr) {
+ pNumConstants[i] = inRange
+ ? Bindings[StartSlot + i].constantCount
+ : 0u;
+ }
+ }
+ }
+
+
+ void D3D11DeviceContext::GetShaderResources(
+ const D3D11ShaderResourceBindings& Bindings,
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView** ppShaderResourceViews) {
+ for (uint32_t i = 0; i < NumViews; i++) {
+ ppShaderResourceViews[i] = StartSlot + i < Bindings.views.size()
+ ? Bindings.views[StartSlot + i].ref()
+ : nullptr;
+ }
+ }
+
+
+ void D3D11DeviceContext::GetSamplers(
+ const D3D11SamplerBindings& Bindings,
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState** ppSamplers) {
+ for (uint32_t i = 0; i < NumSamplers; i++) {
+ ppSamplers[i] = StartSlot + i < Bindings.size()
+ ? ref(Bindings[StartSlot + i])
+ : nullptr;
+ }
+ }
+
+
+ void D3D11DeviceContext::ResetState() {
+ EmitCs([] (DxvkContext* ctx) {
+ // Reset render targets
+ ctx->bindRenderTargets(DxvkRenderTargets());
+
+ // Reset vertex input state
+ ctx->setInputLayout(0, nullptr, 0, nullptr);
+
+ // Reset render states
+ DxvkInputAssemblyState iaState;
+ InitDefaultPrimitiveTopology(&iaState);
+
+ DxvkDepthStencilState dsState;
+ InitDefaultDepthStencilState(&dsState);
+
+ DxvkRasterizerState rsState;
+ InitDefaultRasterizerState(&rsState);
+
+ DxvkBlendMode cbState;
+ DxvkLogicOpState loState;
+ DxvkMultisampleState msState;
+ InitDefaultBlendState(&cbState, &loState, &msState, D3D11_DEFAULT_SAMPLE_MASK);
+
+ ctx->setInputAssemblyState(iaState);
+ ctx->setDepthStencilState(dsState);
+ ctx->setRasterizerState(rsState);
+ ctx->setLogicOpState(loState);
+ ctx->setMultisampleState(msState);
+
+ for (uint32_t i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
+ ctx->setBlendMode(i, cbState);
+
+ // Reset dynamic states
+ ctx->setBlendConstants(DxvkBlendConstants { 1.0f, 1.0f, 1.0f, 1.0f });
+ ctx->setStencilReference(D3D11_DEFAULT_STENCIL_REFERENCE);
+
+ // Reset viewports
+ auto viewport = VkViewport();
+ auto scissor = VkRect2D();
+
+ ctx->setViewports(1, &viewport, &scissor);
+
+ // Unbind indirect draw buffer
+ ctx->bindDrawBuffers(DxvkBufferSlice(), DxvkBufferSlice());
+
+ // Unbind index and vertex buffers
+ ctx->bindIndexBuffer(DxvkBufferSlice(), VK_INDEX_TYPE_UINT32);
+
+ for (uint32_t i = 0; i < D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT; i++)
+ ctx->bindVertexBuffer(i, DxvkBufferSlice(), 0);
+
+ // Unbind transform feedback buffers
+ for (uint32_t i = 0; i < D3D11_SO_BUFFER_SLOT_COUNT; i++)
+ ctx->bindXfbBuffer(i, DxvkBufferSlice(), DxvkBufferSlice());
+
+ // Unbind per-shader stage resources
+ for (uint32_t i = 0; i < 6; i++) {
+ auto programType = DxbcProgramType(i);
+ ctx->bindShader(GetShaderStage(programType), nullptr);
+
+ // Unbind constant buffers, including the shader's ICB
+ auto cbSlotId = computeConstantBufferBinding(programType, 0);
+
+ for (uint32_t j = 0; j <= D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; j++)
+ ctx->bindResourceBuffer(cbSlotId + j, DxvkBufferSlice());
+
+ // Unbind shader resource views
+ auto srvSlotId = computeSrvBinding(programType, 0);
+
+ for (uint32_t j = 0; j < D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; j++)
+ ctx->bindResourceView(srvSlotId + j, nullptr, nullptr);
+
+ // Unbind texture samplers
+ auto samplerSlotId = computeSamplerBinding(programType, 0);
+
+ for (uint32_t j = 0; j < D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; j++)
+ ctx->bindResourceSampler(samplerSlotId + j, nullptr);
+
+ // Unbind UAVs for supported stages
+ if (programType == DxbcProgramType::PixelShader
+ || programType == DxbcProgramType::ComputeShader) {
+ auto uavSlotId = computeUavBinding(programType, 0);
+ auto ctrSlotId = computeUavCounterBinding(programType, 0);
+
+ for (uint32_t j = 0; j < D3D11_1_UAV_SLOT_COUNT; j++) {
+ ctx->bindResourceView (uavSlotId, nullptr, nullptr);
+ ctx->bindResourceBuffer (ctrSlotId, DxvkBufferSlice());
+ }
+ }
+ }
+ });
+ }
+
+
+ void D3D11DeviceContext::RestoreState() {
+ BindFramebuffer();
+
+ BindShader<DxbcProgramType::VertexShader> (GetCommonShader(m_state.vs.shader.ptr()));
+ BindShader<DxbcProgramType::HullShader> (GetCommonShader(m_state.hs.shader.ptr()));
+ BindShader<DxbcProgramType::DomainShader> (GetCommonShader(m_state.ds.shader.ptr()));
+ BindShader<DxbcProgramType::GeometryShader> (GetCommonShader(m_state.gs.shader.ptr()));
+ BindShader<DxbcProgramType::PixelShader> (GetCommonShader(m_state.ps.shader.ptr()));
+ BindShader<DxbcProgramType::ComputeShader> (GetCommonShader(m_state.cs.shader.ptr()));
+
+ ApplyInputLayout();
+ ApplyPrimitiveTopology();
+ ApplyBlendState();
+ ApplyBlendFactor();
+ ApplyDepthStencilState();
+ ApplyStencilRef();
+ ApplyRasterizerState();
+ ApplyViewportState();
+
+ BindDrawBuffers(
+ m_state.id.argBuffer.ptr(),
+ m_state.id.cntBuffer.ptr());
+
+ BindIndexBuffer(
+ m_state.ia.indexBuffer.buffer.ptr(),
+ m_state.ia.indexBuffer.offset,
+ m_state.ia.indexBuffer.format);
+
+ for (uint32_t i = 0; i < m_state.ia.vertexBuffers.size(); i++) {
+ BindVertexBuffer(i,
+ m_state.ia.vertexBuffers[i].buffer.ptr(),
+ m_state.ia.vertexBuffers[i].offset,
+ m_state.ia.vertexBuffers[i].stride);
+ }
+
+ for (uint32_t i = 0; i < m_state.so.targets.size(); i++)
+ BindXfbBuffer(i, m_state.so.targets[i].buffer.ptr(), ~0u);
+
+ RestoreConstantBuffers<DxbcProgramType::VertexShader> (m_state.vs.constantBuffers);
+ RestoreConstantBuffers<DxbcProgramType::HullShader> (m_state.hs.constantBuffers);
+ RestoreConstantBuffers<DxbcProgramType::DomainShader> (m_state.ds.constantBuffers);
+ RestoreConstantBuffers<DxbcProgramType::GeometryShader> (m_state.gs.constantBuffers);
+ RestoreConstantBuffers<DxbcProgramType::PixelShader> (m_state.ps.constantBuffers);
+ RestoreConstantBuffers<DxbcProgramType::ComputeShader> (m_state.cs.constantBuffers);
+
+ RestoreSamplers<DxbcProgramType::VertexShader> (m_state.vs.samplers);
+ RestoreSamplers<DxbcProgramType::HullShader> (m_state.hs.samplers);
+ RestoreSamplers<DxbcProgramType::DomainShader> (m_state.ds.samplers);
+ RestoreSamplers<DxbcProgramType::GeometryShader>(m_state.gs.samplers);
+ RestoreSamplers<DxbcProgramType::PixelShader> (m_state.ps.samplers);
+ RestoreSamplers<DxbcProgramType::ComputeShader> (m_state.cs.samplers);
+
+ RestoreShaderResources<DxbcProgramType::VertexShader> (m_state.vs.shaderResources);
+ RestoreShaderResources<DxbcProgramType::HullShader> (m_state.hs.shaderResources);
+ RestoreShaderResources<DxbcProgramType::DomainShader> (m_state.ds.shaderResources);
+ RestoreShaderResources<DxbcProgramType::GeometryShader> (m_state.gs.shaderResources);
+ RestoreShaderResources<DxbcProgramType::PixelShader> (m_state.ps.shaderResources);
+ RestoreShaderResources<DxbcProgramType::ComputeShader> (m_state.cs.shaderResources);
+
+ RestoreUnorderedAccessViews<DxbcProgramType::PixelShader> (m_state.ps.unorderedAccessViews);
+ RestoreUnorderedAccessViews<DxbcProgramType::ComputeShader> (m_state.cs.unorderedAccessViews);
+ }
+
+
+ template<DxbcProgramType Stage>
+ void D3D11DeviceContext::RestoreConstantBuffers(
+ D3D11ConstantBufferBindings& Bindings) {
+ uint32_t slotId = computeConstantBufferBinding(Stage, 0);
+
+ for (uint32_t i = 0; i < Bindings.size(); i++) {
+ BindConstantBuffer(slotId + i, Bindings[i].buffer.ptr(),
+ Bindings[i].constantOffset, Bindings[i].constantBound);
+ }
+ }
+
+
+ template<DxbcProgramType Stage>
+ void D3D11DeviceContext::RestoreSamplers(
+ D3D11SamplerBindings& Bindings) {
+ uint32_t slotId = computeSamplerBinding(Stage, 0);
+
+ for (uint32_t i = 0; i < Bindings.size(); i++)
+ BindSampler(slotId + i, Bindings[i]);
+ }
+
+
+ template<DxbcProgramType Stage>
+ void D3D11DeviceContext::RestoreShaderResources(
+ D3D11ShaderResourceBindings& Bindings) {
+ uint32_t slotId = computeSrvBinding(Stage, 0);
+
+ for (uint32_t i = 0; i < Bindings.views.size(); i++)
+ BindShaderResource(slotId + i, Bindings.views[i].ptr());
+ }
+
+
+ template<DxbcProgramType Stage>
+ void D3D11DeviceContext::RestoreUnorderedAccessViews(
+ D3D11UnorderedAccessBindings& Bindings) {
+ uint32_t uavSlotId = computeUavBinding (Stage, 0);
+ uint32_t ctrSlotId = computeUavCounterBinding(Stage, 0);
+
+ for (uint32_t i = 0; i < Bindings.size(); i++) {
+ BindUnorderedAccessView(
+ uavSlotId + i,
+ Bindings[i].ptr(),
+ ctrSlotId + i, ~0u);
+ }
+ }
+
+
+ bool D3D11DeviceContext::TestRtvUavHazards(
+ UINT NumRTVs,
+ ID3D11RenderTargetView* const* ppRTVs,
+ UINT NumUAVs,
+ ID3D11UnorderedAccessView* const* ppUAVs) {
+ if (NumRTVs == D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL) NumRTVs = 0;
+ if (NumUAVs == D3D11_KEEP_UNORDERED_ACCESS_VIEWS) NumUAVs = 0;
+
+ for (uint32_t i = 0; i < NumRTVs; i++) {
+ auto rtv = static_cast<D3D11RenderTargetView*>(ppRTVs[i]);
+
+ if (!rtv)
+ continue;
+
+ for (uint32_t j = 0; j < i; j++) {
+ if (CheckViewOverlap(rtv, static_cast<D3D11RenderTargetView*>(ppRTVs[j])))
+ return true;
+ }
+
+ if (rtv->HasBindFlag(D3D11_BIND_UNORDERED_ACCESS)) {
+ for (uint32_t j = 0; j < NumUAVs; j++) {
+ if (CheckViewOverlap(rtv, static_cast<D3D11UnorderedAccessView*>(ppUAVs[j])))
+ return true;
+ }
+ }
+ }
+
+ for (uint32_t i = 0; i < NumUAVs; i++) {
+ auto uav = static_cast<D3D11UnorderedAccessView*>(ppUAVs[i]);
+
+ if (!uav)
+ continue;
+
+ for (uint32_t j = 0; j < i; j++) {
+ if (CheckViewOverlap(uav, static_cast<D3D11UnorderedAccessView*>(ppUAVs[j])))
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ template<DxbcProgramType ShaderStage>
+ bool D3D11DeviceContext::TestSrvHazards(
+ D3D11ShaderResourceView* pView) {
+ bool hazard = false;
+
+ if (ShaderStage == DxbcProgramType::ComputeShader) {
+ int32_t uav = m_state.cs.uavMask.findNext(0);
+
+ while (uav >= 0 && !hazard) {
+ hazard = CheckViewOverlap(pView, m_state.cs.unorderedAccessViews[uav].ptr());
+ uav = m_state.cs.uavMask.findNext(uav + 1);
+ }
+ } else {
+ hazard = CheckViewOverlap(pView, m_state.om.depthStencilView.ptr());
+
+ for (uint32_t i = 0; !hazard && i < m_state.om.maxRtv; i++)
+ hazard = CheckViewOverlap(pView, m_state.om.renderTargetViews[i].ptr());
+
+ for (uint32_t i = 0; !hazard && i < m_state.om.maxUav; i++)
+ hazard = CheckViewOverlap(pView, m_state.ps.unorderedAccessViews[i].ptr());
+ }
+
+ return hazard;
+ }
+
+
+ template<DxbcProgramType ShaderStage, typename T>
+ void D3D11DeviceContext::ResolveSrvHazards(
+ T* pView,
+ D3D11ShaderResourceBindings& Bindings) {
+ uint32_t slotId = computeSrvBinding(ShaderStage, 0);
+ int32_t srvId = Bindings.hazardous.findNext(0);
+
+ while (srvId >= 0) {
+ auto srv = Bindings.views[srvId].ptr();
+
+ if (likely(srv && srv->TestHazards())) {
+ bool hazard = CheckViewOverlap(pView, srv);
+
+ if (unlikely(hazard)) {
+ Bindings.views[srvId] = nullptr;
+ Bindings.hazardous.clr(srvId);
+
+ BindShaderResource(slotId + srvId, nullptr);
+ }
+ } else {
+ // Avoid further redundant iterations
+ Bindings.hazardous.clr(srvId);
+ }
+
+ srvId = Bindings.hazardous.findNext(srvId + 1);
+ }
+ }
+
+
+ template<typename T>
+ void D3D11DeviceContext::ResolveCsSrvHazards(
+ T* pView) {
+ if (!pView) return;
+ ResolveSrvHazards<DxbcProgramType::ComputeShader> (pView, m_state.cs.shaderResources);
+ }
+
+
+ template<typename T>
+ void D3D11DeviceContext::ResolveOmSrvHazards(
+ T* pView) {
+ if (!pView) return;
+ ResolveSrvHazards<DxbcProgramType::VertexShader> (pView, m_state.vs.shaderResources);
+ ResolveSrvHazards<DxbcProgramType::HullShader> (pView, m_state.hs.shaderResources);
+ ResolveSrvHazards<DxbcProgramType::DomainShader> (pView, m_state.ds.shaderResources);
+ ResolveSrvHazards<DxbcProgramType::GeometryShader> (pView, m_state.gs.shaderResources);
+ ResolveSrvHazards<DxbcProgramType::PixelShader> (pView, m_state.ps.shaderResources);
+ }
+
+
+ bool D3D11DeviceContext::ResolveOmRtvHazards(
+ D3D11UnorderedAccessView* pView) {
+ if (!pView || !pView->HasBindFlag(D3D11_BIND_RENDER_TARGET))
+ return false;
+
+ bool hazard = false;
+
+ if (CheckViewOverlap(pView, m_state.om.depthStencilView.ptr())) {
+ m_state.om.depthStencilView = nullptr;
+ hazard = true;
+ }
+
+ for (uint32_t i = 0; i < m_state.om.maxRtv; i++) {
+ if (CheckViewOverlap(pView, m_state.om.renderTargetViews[i].ptr())) {
+ m_state.om.renderTargetViews[i] = nullptr;
+ hazard = true;
+ }
+ }
+
+ return hazard;
+ }
+
+
+ void D3D11DeviceContext::ResolveOmUavHazards(
+ D3D11RenderTargetView* pView) {
+ if (!pView || !pView->HasBindFlag(D3D11_BIND_UNORDERED_ACCESS))
+ return;
+
+ uint32_t uavSlotId = computeUavBinding (DxbcProgramType::PixelShader, 0);
+ uint32_t ctrSlotId = computeUavCounterBinding(DxbcProgramType::PixelShader, 0);
+
+ for (uint32_t i = 0; i < m_state.om.maxUav; i++) {
+ if (CheckViewOverlap(pView, m_state.ps.unorderedAccessViews[i].ptr())) {
+ m_state.ps.unorderedAccessViews[i] = nullptr;
+
+ BindUnorderedAccessView(
+ uavSlotId + i, nullptr,
+ ctrSlotId + i, ~0u);
+ }
+ }
+ }
+
+
+ bool D3D11DeviceContext::ValidateRenderTargets(
+ UINT NumViews,
+ ID3D11RenderTargetView* const* ppRenderTargetViews,
+ ID3D11DepthStencilView* pDepthStencilView) {
+ Rc<DxvkImageView> refView;
+
+ if (pDepthStencilView != nullptr) {
+ refView = static_cast<D3D11DepthStencilView*>(
+ pDepthStencilView)->GetImageView();
+ }
+
+ for (uint32_t i = 0; i < NumViews; i++) {
+ if (ppRenderTargetViews[i] != nullptr) {
+ auto curView = static_cast<D3D11RenderTargetView*>(
+ ppRenderTargetViews[i])->GetImageView();
+
+ if (refView != nullptr) {
+ // Render target views must all have the same
+ // size, sample count, layer count, and type
+ if (curView->info().type != refView->info().type
+ || curView->info().numLayers != refView->info().numLayers)
+ return false;
+
+ if (curView->imageInfo().sampleCount
+ != refView->imageInfo().sampleCount)
+ return false;
+ } else {
+ // Set reference view. All remaining views
+ // must be compatible to the reference view.
+ refView = curView;
+ }
+ }
+ }
+
+ return true;
+ }
+
+
+ VkClearValue D3D11DeviceContext::ConvertColorValue(
+ const FLOAT Color[4],
+ const DxvkFormatInfo* pFormatInfo) {
+ VkClearValue result;
+
+ if (pFormatInfo->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
+ for (uint32_t i = 0; i < 4; i++) {
+ if (pFormatInfo->flags.test(DxvkFormatFlag::SampledUInt))
+ result.color.uint32[i] = uint32_t(std::max(0.0f, Color[i]));
+ else if (pFormatInfo->flags.test(DxvkFormatFlag::SampledSInt))
+ result.color.int32[i] = int32_t(Color[i]);
+ else
+ result.color.float32[i] = Color[i];
+ }
+ } else {
+ result.depthStencil.depth = Color[0];
+ result.depthStencil.stencil = 0;
+ }
+
+ return result;
+ }
+
+
+ DxvkDataSlice D3D11DeviceContext::AllocUpdateBufferSlice(size_t Size) {
+ constexpr size_t UpdateBufferSize = 16 * 1024 * 1024;
+
+ if (Size >= UpdateBufferSize) {
+ Rc<DxvkDataBuffer> buffer = new DxvkDataBuffer(Size);
+ return buffer->alloc(Size);
+ } else {
+ if (m_updateBuffer == nullptr)
+ m_updateBuffer = new DxvkDataBuffer(UpdateBufferSize);
+
+ DxvkDataSlice slice = m_updateBuffer->alloc(Size);
+
+ if (slice.ptr() == nullptr) {
+ m_updateBuffer = new DxvkDataBuffer(UpdateBufferSize);
+ slice = m_updateBuffer->alloc(Size);
+ }
+
+ return slice;
+ }
+ }
+
+
+ DxvkBufferSlice D3D11DeviceContext::AllocStagingBuffer(
+ VkDeviceSize Size) {
+ DxvkBufferCreateInfo info;
+ info.size = Size;
+ info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT
+ | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
+ | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
+ info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT
+ | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
+ | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ info.access = VK_ACCESS_TRANSFER_READ_BIT
+ | VK_ACCESS_SHADER_READ_BIT;
+
+ return DxvkBufferSlice(m_device->createBuffer(info,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT));
+ }
+
+
+ DxvkCsChunkRef D3D11DeviceContext::AllocCsChunk() {
+ return m_parent->AllocCsChunk(m_csFlags);
+ }
+
+
+ void D3D11DeviceContext::InitDefaultPrimitiveTopology(
+ DxvkInputAssemblyState* pIaState) {
+ pIaState->primitiveTopology = VK_PRIMITIVE_TOPOLOGY_MAX_ENUM;
+ pIaState->primitiveRestart = VK_FALSE;
+ pIaState->patchVertexCount = 0;
+ }
+
+
+ void D3D11DeviceContext::InitDefaultRasterizerState(
+ DxvkRasterizerState* pRsState) {
+ pRsState->polygonMode = VK_POLYGON_MODE_FILL;
+ pRsState->cullMode = VK_CULL_MODE_BACK_BIT;
+ pRsState->frontFace = VK_FRONT_FACE_CLOCKWISE;
+ pRsState->depthClipEnable = VK_TRUE;
+ pRsState->depthBiasEnable = VK_FALSE;
+ pRsState->conservativeMode = VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT;
+ pRsState->sampleCount = 0;
+ }
+
+
+ void D3D11DeviceContext::InitDefaultDepthStencilState(
+ DxvkDepthStencilState* pDsState) {
+ VkStencilOpState stencilOp;
+ stencilOp.failOp = VK_STENCIL_OP_KEEP;
+ stencilOp.passOp = VK_STENCIL_OP_KEEP;
+ stencilOp.depthFailOp = VK_STENCIL_OP_KEEP;
+ stencilOp.compareOp = VK_COMPARE_OP_ALWAYS;
+ stencilOp.compareMask = D3D11_DEFAULT_STENCIL_READ_MASK;
+ stencilOp.writeMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
+ stencilOp.reference = 0;
+
+ pDsState->enableDepthTest = VK_TRUE;
+ pDsState->enableDepthWrite = VK_TRUE;
+ pDsState->enableStencilTest = VK_FALSE;
+ pDsState->depthCompareOp = VK_COMPARE_OP_LESS;
+ pDsState->stencilOpFront = stencilOp;
+ pDsState->stencilOpBack = stencilOp;
+ }
+
+
+ void D3D11DeviceContext::InitDefaultBlendState(
+ DxvkBlendMode* pCbState,
+ DxvkLogicOpState* pLoState,
+ DxvkMultisampleState* pMsState,
+ UINT SampleMask) {
+ pCbState->enableBlending = VK_FALSE;
+ pCbState->colorSrcFactor = VK_BLEND_FACTOR_ONE;
+ pCbState->colorDstFactor = VK_BLEND_FACTOR_ZERO;
+ pCbState->colorBlendOp = VK_BLEND_OP_ADD;
+ pCbState->alphaSrcFactor = VK_BLEND_FACTOR_ONE;
+ pCbState->alphaDstFactor = VK_BLEND_FACTOR_ZERO;
+ pCbState->alphaBlendOp = VK_BLEND_OP_ADD;
+ pCbState->writeMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
+ | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
+
+ pLoState->enableLogicOp = VK_FALSE;
+ pLoState->logicOp = VK_LOGIC_OP_NO_OP;
+
+ pMsState->sampleMask = SampleMask;
+ pMsState->enableAlphaToCoverage = VK_FALSE;
+ }
+
+}