mirror of
https://github.com/doitsujin/dxvk.git
synced 2024-12-14 00:48:44 +01:00
432708c15f
The DXGI format info only stores the aspect mask for views created with that format, but we're dealing with a raw resource here so we have to query the aspect mask from the Vulkan format in question. Fixes validation errors with typeless resolve if the formats of the two involved images are identical.
3021 lines
106 KiB
C++
3021 lines
106 KiB
C++
#include <cstring>
|
|
|
|
#include "d3d11_context.h"
|
|
#include "d3d11_device.h"
|
|
#include "d3d11_query.h"
|
|
#include "d3d11_texture.h"
|
|
|
|
#include "../dxbc/dxbc_util.h"
|
|
|
|
namespace dxvk {
|
|
|
|
D3D11DeviceContext::D3D11DeviceContext(
|
|
D3D11Device* pParent,
|
|
const Rc<DxvkDevice>& Device)
|
|
: m_parent (pParent),
|
|
m_annotation(this),
|
|
m_device (Device),
|
|
m_csChunk (new DxvkCsChunk()) {
|
|
// Create default state objects. We won't ever return them
|
|
// to the application, but we'll use them to apply state.
|
|
Com<ID3D11BlendState> defaultBlendState;
|
|
Com<ID3D11DepthStencilState> defaultDepthStencilState;
|
|
Com<ID3D11RasterizerState> defaultRasterizerState;
|
|
|
|
if (FAILED(m_parent->CreateBlendState (nullptr, &defaultBlendState))
|
|
|| FAILED(m_parent->CreateDepthStencilState(nullptr, &defaultDepthStencilState))
|
|
|| FAILED(m_parent->CreateRasterizerState (nullptr, &defaultRasterizerState)))
|
|
throw DxvkError("D3D11DeviceContext: Failed to create default state objects");
|
|
|
|
// Apply default state to the context. This is required
|
|
// in order to initialize the DXVK contex properly.
|
|
m_defaultBlendState = static_cast<D3D11BlendState*> (defaultBlendState.ptr());
|
|
m_defaultDepthStencilState = static_cast<D3D11DepthStencilState*>(defaultDepthStencilState.ptr());
|
|
m_defaultRasterizerState = static_cast<D3D11RasterizerState*> (defaultRasterizerState.ptr());
|
|
}
|
|
|
|
|
|
D3D11DeviceContext::~D3D11DeviceContext() {
|
|
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE D3D11DeviceContext::QueryInterface(REFIID riid, void** ppvObject) {
|
|
*ppvObject = nullptr;
|
|
|
|
if (riid == __uuidof(IUnknown)
|
|
|| riid == __uuidof(ID3D11DeviceChild)
|
|
|| riid == __uuidof(ID3D11DeviceContext)
|
|
|| riid == __uuidof(ID3D11DeviceContext1)) {
|
|
*ppvObject = ref(this);
|
|
return S_OK;
|
|
}
|
|
|
|
if (riid == __uuidof(ID3DUserDefinedAnnotation)) {
|
|
*ppvObject = ref(&m_annotation);
|
|
return S_OK;
|
|
}
|
|
|
|
Logger::warn("D3D11DeviceContext::QueryInterface: Unknown interface query");
|
|
Logger::warn(str::format(riid));
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::DiscardResource(ID3D11Resource * pResource) {
|
|
Logger::err("D3D11DeviceContext::DiscardResource: Not implemented");
|
|
}
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::DiscardView(ID3D11View * pResourceView) {
|
|
Logger::err("D3D11DeviceContext::DiscardView: Not implemented");
|
|
}
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::DiscardView1(
|
|
ID3D11View* pResourceView,
|
|
const D3D11_RECT* pRects,
|
|
UINT NumRects) {
|
|
Logger::err("D3D11DeviceContext::DiscardView1: Not implemented");
|
|
}
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::SwapDeviceContextState(
|
|
ID3DDeviceContextState* pState,
|
|
ID3DDeviceContextState** ppPreviousState) {
|
|
Logger::err("D3D11DeviceContext::SwapDeviceContextState: Not implemented");
|
|
}
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::GetDevice(ID3D11Device **ppDevice) {
|
|
*ppDevice = ref(m_parent);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::ClearState() {
|
|
// 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[i] = nullptr;
|
|
m_state.hs.shaderResources[i] = nullptr;
|
|
m_state.ds.shaderResources[i] = nullptr;
|
|
m_state.gs.shaderResources[i] = nullptr;
|
|
m_state.ps.shaderResources[i] = nullptr;
|
|
m_state.cs.shaderResources[i] = nullptr;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
// 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] = 0.0f;
|
|
|
|
m_state.om.sampleMask = D3D11_DEFAULT_SAMPLE_MASK;
|
|
m_state.om.stencilRef = D3D11_DEFAULT_STENCIL_REFERENCE;
|
|
|
|
// 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_STREAM_COUNT; i++)
|
|
m_state.so.targets[i] = nullptr;
|
|
|
|
// Default predication
|
|
m_state.pr.predicateObject = nullptr;
|
|
m_state.pr.predicateValue = FALSE;
|
|
|
|
// Make sure to apply all state
|
|
RestoreState();
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::Begin(ID3D11Asynchronous *pAsync) {
|
|
if (pAsync == nullptr)
|
|
return;
|
|
|
|
Com<ID3D11Query> query;
|
|
|
|
if (SUCCEEDED(pAsync->QueryInterface(__uuidof(ID3D11Query), reinterpret_cast<void**>(&query)))) {
|
|
Com<D3D11Query> queryPtr = static_cast<D3D11Query*>(query.ptr());
|
|
|
|
if (queryPtr->HasBeginEnabled()) {
|
|
const uint32_t revision = queryPtr->Reset();
|
|
|
|
EmitCs([revision, queryPtr] (DxvkContext* ctx) {
|
|
queryPtr->Begin(ctx, revision);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::End(ID3D11Asynchronous *pAsync) {
|
|
if (pAsync == nullptr)
|
|
return;
|
|
|
|
Com<ID3D11Query> query;
|
|
|
|
if (SUCCEEDED(pAsync->QueryInterface(__uuidof(ID3D11Query), reinterpret_cast<void**>(&query)))) {
|
|
Com<D3D11Query> queryPtr = static_cast<D3D11Query*>(query.ptr());
|
|
|
|
if (queryPtr->HasBeginEnabled()) {
|
|
EmitCs([queryPtr] (DxvkContext* ctx) {
|
|
queryPtr->End(ctx);
|
|
});
|
|
} else {
|
|
const uint32_t revision = queryPtr->Reset();
|
|
|
|
EmitCs([revision, queryPtr] (DxvkContext* ctx) {
|
|
queryPtr->Signal(ctx, revision);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::SetPredication(
|
|
ID3D11Predicate* pPredicate,
|
|
BOOL PredicateValue) {
|
|
static bool s_errorShown = false;
|
|
|
|
if (!std::exchange(s_errorShown, true))
|
|
Logger::err("D3D11DeviceContext::SetPredication: Stub");
|
|
|
|
m_state.pr.predicateObject = static_cast<D3D11Query*>(pPredicate);
|
|
m_state.pr.predicateValue = PredicateValue;
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::GetPredication(
|
|
ID3D11Predicate** ppPredicate,
|
|
BOOL* pPredicateValue) {
|
|
if (ppPredicate != nullptr)
|
|
*ppPredicate = m_state.pr.predicateObject.ref();
|
|
|
|
if (pPredicateValue != nullptr)
|
|
*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) {
|
|
D3D11_RESOURCE_DIMENSION dstResourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
|
|
D3D11_RESOURCE_DIMENSION srcResourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
|
|
|
|
pDstResource->GetType(&dstResourceDim);
|
|
pSrcResource->GetType(&srcResourceDim);
|
|
|
|
// Copying 2D image slices to 3D images and vice versa is legal
|
|
const bool copy2Dto3D = dstResourceDim == D3D11_RESOURCE_DIMENSION_TEXTURE3D
|
|
&& srcResourceDim == D3D11_RESOURCE_DIMENSION_TEXTURE2D;
|
|
const bool copy3Dto2D = dstResourceDim == D3D11_RESOURCE_DIMENSION_TEXTURE2D
|
|
&& srcResourceDim == D3D11_RESOURCE_DIMENSION_TEXTURE3D;
|
|
|
|
if (dstResourceDim != srcResourceDim && !copy2Dto3D && !copy3Dto2D) {
|
|
Logger::err(str::format(
|
|
"D3D11: CopySubresourceRegion: 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)->GetBufferSlice();
|
|
auto srcBuffer = static_cast<D3D11Buffer*>(pSrcResource)->GetBufferSlice();
|
|
|
|
VkDeviceSize dstOffset = DstX;
|
|
VkDeviceSize srcOffset = 0;
|
|
VkDeviceSize regLength = srcBuffer.length();
|
|
|
|
if (dstOffset >= dstBuffer.length())
|
|
return;
|
|
|
|
if (pSrcBox != nullptr) {
|
|
if (pSrcBox->left >= pSrcBox->right)
|
|
return; // no-op, but legal
|
|
|
|
srcOffset = pSrcBox->left;
|
|
regLength = pSrcBox->right - pSrcBox->left;
|
|
|
|
if (srcOffset >= srcBuffer.length())
|
|
return;
|
|
}
|
|
|
|
// Clamp copy region to prevent out-of-bounds access
|
|
regLength = std::min(regLength, srcBuffer.length() - srcOffset);
|
|
regLength = std::min(regLength, dstBuffer.length() - dstOffset);
|
|
|
|
EmitCs([
|
|
cDstSlice = dstBuffer.subSlice(dstOffset, regLength),
|
|
cSrcSlice = srcBuffer.subSlice(srcOffset, regLength)
|
|
] (DxvkContext* ctx) {
|
|
ctx->copyBuffer(
|
|
cDstSlice.buffer(),
|
|
cDstSlice.offset(),
|
|
cSrcSlice.buffer(),
|
|
cSrcSlice.offset(),
|
|
cSrcSlice.length());
|
|
});
|
|
} else {
|
|
const D3D11CommonTexture* dstTextureInfo = GetCommonTexture(pDstResource);
|
|
const D3D11CommonTexture* srcTextureInfo = GetCommonTexture(pSrcResource);
|
|
|
|
const Rc<DxvkImage> dstImage = dstTextureInfo->GetImage();
|
|
const Rc<DxvkImage> srcImage = srcTextureInfo->GetImage();
|
|
|
|
const DxvkFormatInfo* dstFormatInfo = imageFormatInfo(dstImage->info().format);
|
|
const DxvkFormatInfo* srcFormatInfo = imageFormatInfo(srcImage->info().format);
|
|
|
|
const VkImageSubresource dstSubresource = dstTextureInfo->GetSubresourceFromIndex(dstFormatInfo->aspectMask, DstSubresource);
|
|
const VkImageSubresource srcSubresource = srcTextureInfo->GetSubresourceFromIndex(srcFormatInfo->aspectMask, SrcSubresource);
|
|
|
|
// Copies are only supported on size-compatible formats
|
|
if (dstFormatInfo->elementSize != srcFormatInfo->elementSize) {
|
|
Logger::err(str::format(
|
|
"D3D11: CopySubresourceRegion: Incompatible texel size"
|
|
"\n Dst texel size: ", dstFormatInfo->elementSize,
|
|
"\n Src texel size: ", srcFormatInfo->elementSize));
|
|
return;
|
|
}
|
|
|
|
// Copies are only supported if the sample count matches
|
|
if (dstImage->info().sampleCount != srcImage->info().sampleCount) {
|
|
Logger::err(str::format(
|
|
"D3D11: CopySubresourceRegion: Incompatible sample count",
|
|
"\n Dst sample count: ", dstImage->info().sampleCount,
|
|
"\n Src sample count: ", srcImage->info().sampleCount));
|
|
return;
|
|
}
|
|
|
|
VkOffset3D srcOffset = { 0, 0, 0 };
|
|
VkOffset3D dstOffset = { int32_t(DstX), int32_t(DstY), int32_t(DstZ) };
|
|
|
|
VkExtent3D srcExtent = srcImage->mipLevelExtent(srcSubresource.mipLevel);
|
|
VkExtent3D dstExtent = dstImage->mipLevelExtent(dstSubresource.mipLevel);
|
|
VkExtent3D regExtent = srcExtent;
|
|
|
|
if (uint32_t(dstOffset.x) >= dstExtent.width
|
|
|| uint32_t(dstOffset.y) >= dstExtent.height
|
|
|| uint32_t(dstOffset.z) >= dstExtent.depth)
|
|
return;
|
|
|
|
if (pSrcBox != nullptr) {
|
|
if (pSrcBox->left >= pSrcBox->right
|
|
|| pSrcBox->top >= pSrcBox->bottom
|
|
|| pSrcBox->front >= pSrcBox->back)
|
|
return; // no-op, but legal
|
|
|
|
srcOffset.x = pSrcBox->left;
|
|
srcOffset.y = pSrcBox->top;
|
|
srcOffset.z = pSrcBox->front;
|
|
|
|
regExtent.width = pSrcBox->right - pSrcBox->left;
|
|
regExtent.height = pSrcBox->bottom - pSrcBox->top;
|
|
regExtent.depth = pSrcBox->back - pSrcBox->front;
|
|
|
|
if (uint32_t(srcOffset.x) >= srcExtent.width
|
|
|| uint32_t(srcOffset.y) >= srcExtent.height
|
|
|| uint32_t(srcOffset.z) >= srcExtent.depth)
|
|
return;
|
|
}
|
|
|
|
VkImageSubresourceLayers dstLayers = {
|
|
dstSubresource.aspectMask,
|
|
dstSubresource.mipLevel,
|
|
dstSubresource.arrayLayer, 1 };
|
|
|
|
VkImageSubresourceLayers srcLayers = {
|
|
srcSubresource.aspectMask,
|
|
srcSubresource.mipLevel,
|
|
srcSubresource.arrayLayer, 1 };
|
|
|
|
// Copying multiple slices does not
|
|
// seem to be supported in D3D11
|
|
if (copy2Dto3D || copy3Dto2D) {
|
|
regExtent.depth = 1;
|
|
dstLayers.layerCount = 1;
|
|
srcLayers.layerCount = 1;
|
|
}
|
|
|
|
// Don't perform the copy if the offsets aren't aligned
|
|
if (!util::isBlockAligned(srcOffset, srcFormatInfo->blockSize)
|
|
|| !util::isBlockAligned(dstOffset, dstFormatInfo->blockSize)) {
|
|
Logger::err(str::format(
|
|
"D3D11: CopySubresourceRegion: Unaligned block offset",
|
|
"\n Src offset: (", srcOffset.x, ",", srcOffset.y, ",", srcOffset.z, ")",
|
|
"\n Src block size: (", srcFormatInfo->blockSize.width, "x", srcFormatInfo->blockSize.height, "x", srcFormatInfo->blockSize.depth, ")",
|
|
"\n Dst offset: (", dstOffset.x, ",", dstOffset.y, ",", dstOffset.z, ")",
|
|
"\n Dst block size: (", dstFormatInfo->blockSize.width, "x", dstFormatInfo->blockSize.height, "x", dstFormatInfo->blockSize.depth, ")"));
|
|
return;
|
|
}
|
|
|
|
// Clamp the image region in order to avoid out-of-bounds access
|
|
VkExtent3D regBlockCount = util::computeBlockCount(regExtent, srcFormatInfo->blockSize);
|
|
VkExtent3D dstBlockCount = util::computeMaxBlockCount(dstOffset, dstExtent, dstFormatInfo->blockSize);
|
|
VkExtent3D srcBlockCount = util::computeMaxBlockCount(srcOffset, srcExtent, srcFormatInfo->blockSize);
|
|
|
|
regBlockCount = util::minExtent3D(regBlockCount, dstBlockCount);
|
|
regBlockCount = util::minExtent3D(regBlockCount, srcBlockCount);
|
|
|
|
regExtent = util::minExtent3D(regExtent, util::computeBlockExtent(regBlockCount, srcFormatInfo->blockSize));
|
|
|
|
// Don't perform the copy if the image extent is not aligned and
|
|
// if it does not touch the image border for unaligned dimensons
|
|
if (!util::isBlockAligned(srcOffset, regExtent, srcFormatInfo->blockSize, srcExtent)) {
|
|
Logger::err(str::format(
|
|
"D3D11: CopySubresourceRegion: Unaligned block size",
|
|
"\n Src offset: (", srcOffset.x, ",", srcOffset.y, ",", srcOffset.z, ")",
|
|
"\n Src extent: (", srcExtent.width, "x", srcExtent.height, "x", srcExtent.depth, ")",
|
|
"\n Src block size: (", srcFormatInfo->blockSize.width, "x", srcFormatInfo->blockSize.height, "x", srcFormatInfo->blockSize.depth, ")",
|
|
"\n Dst offset: (", dstOffset.x, ",", dstOffset.y, ",", dstOffset.z, ")",
|
|
"\n Dst extent: (", dstExtent.width, "x", dstExtent.height, "x", dstExtent.depth, ")",
|
|
"\n Dst block size: (", dstFormatInfo->blockSize.width, "x", dstFormatInfo->blockSize.height, "x", dstFormatInfo->blockSize.depth, ")",
|
|
"\n Region extent: (", regExtent.width, "x", regExtent.height, "x", regExtent.depth, ")"));
|
|
return;
|
|
}
|
|
|
|
EmitCs([
|
|
cDstImage = dstImage,
|
|
cSrcImage = srcImage,
|
|
cDstLayers = dstLayers,
|
|
cSrcLayers = srcLayers,
|
|
cDstOffset = dstOffset,
|
|
cSrcOffset = srcOffset,
|
|
cExtent = regExtent
|
|
] (DxvkContext* ctx) {
|
|
ctx->copyImage(
|
|
cDstImage, cDstLayers, cDstOffset,
|
|
cSrcImage, cSrcLayers, cSrcOffset,
|
|
cExtent);
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::CopySubresourceRegion1(
|
|
ID3D11Resource* pDstResource,
|
|
UINT DstSubresource,
|
|
UINT DstX,
|
|
UINT DstY,
|
|
UINT DstZ,
|
|
ID3D11Resource* pSrcResource,
|
|
UINT SrcSubresource,
|
|
const D3D11_BOX* pSrcBox,
|
|
UINT CopyFlags) {
|
|
CopySubresourceRegion(pDstResource, DstSubresource, DstX, DstY, DstZ, pSrcResource, SrcSubresource, pSrcBox);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::CopyResource(
|
|
ID3D11Resource* pDstResource,
|
|
ID3D11Resource* pSrcResource) {
|
|
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)->GetBufferSlice();
|
|
auto srcBuffer = static_cast<D3D11Buffer*>(pSrcResource)->GetBufferSlice();
|
|
|
|
if (dstBuffer.length() != srcBuffer.length()) {
|
|
Logger::err(str::format(
|
|
"D3D11: CopyResource: Mismatched buffer size",
|
|
"\n Dst buffer size: ", dstBuffer.length(),
|
|
"\n Src buffer size: ", srcBuffer.length()));
|
|
return;
|
|
}
|
|
|
|
EmitCs([
|
|
cDstBuffer = std::move(dstBuffer),
|
|
cSrcBuffer = std::move(srcBuffer)
|
|
] (DxvkContext* ctx) {
|
|
ctx->copyBuffer(
|
|
cDstBuffer.buffer(),
|
|
cDstBuffer.offset(),
|
|
cSrcBuffer.buffer(),
|
|
cSrcBuffer.offset(),
|
|
cSrcBuffer.length());
|
|
});
|
|
} else {
|
|
const Rc<DxvkImage> dstImage = GetCommonTexture(pDstResource)->GetImage();
|
|
const Rc<DxvkImage> srcImage = GetCommonTexture(pSrcResource)->GetImage();
|
|
|
|
const DxvkFormatInfo* dstFormatInfo = imageFormatInfo(dstImage->info().format);
|
|
const DxvkFormatInfo* srcFormatInfo = imageFormatInfo(srcImage->info().format);
|
|
|
|
// Copies are only supported on size-compatible formats
|
|
if (dstFormatInfo->elementSize != srcFormatInfo->elementSize) {
|
|
Logger::err(str::format(
|
|
"D3D11: CopyResource: Incompatible texel size"
|
|
"\n Dst texel size: ", dstFormatInfo->elementSize,
|
|
"\n Src texel size: ", srcFormatInfo->elementSize));
|
|
return;
|
|
}
|
|
|
|
// Layer count, mip level count, and sample count must match
|
|
if (srcImage->info().numLayers != dstImage->info().numLayers
|
|
|| srcImage->info().mipLevels != dstImage->info().mipLevels
|
|
|| srcImage->info().sampleCount != dstImage->info().sampleCount) {
|
|
Logger::err(str::format(
|
|
"D3D11: CopyResource: Incompatible images"
|
|
"\n Dst: (", dstImage->info().numLayers,
|
|
",", dstImage->info().mipLevels,
|
|
",", dstImage->info().sampleCount, ")",
|
|
"\n Src: (", srcImage->info().numLayers,
|
|
",", srcImage->info().mipLevels,
|
|
",", srcImage->info().sampleCount, ")"));
|
|
return;
|
|
}
|
|
|
|
for (uint32_t i = 0; i < srcImage->info().mipLevels; i++) {
|
|
VkImageSubresourceLayers dstLayers = { dstFormatInfo->aspectMask, i, 0, dstImage->info().numLayers };
|
|
VkImageSubresourceLayers srcLayers = { srcFormatInfo->aspectMask, i, 0, srcImage->info().numLayers };
|
|
|
|
VkExtent3D extent = srcImage->mipLevelExtent(i);
|
|
|
|
EmitCs([
|
|
cDstImage = dstImage,
|
|
cSrcImage = srcImage,
|
|
cDstLayers = dstLayers,
|
|
cSrcLayers = srcLayers,
|
|
cExtent = extent
|
|
] (DxvkContext* ctx) {
|
|
ctx->copyImage(
|
|
cDstImage, cDstLayers, VkOffset3D { 0, 0, 0 },
|
|
cSrcImage, cSrcLayers, VkOffset3D { 0, 0, 0 },
|
|
cExtent);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::CopyStructureCount(
|
|
ID3D11Buffer* pDstBuffer,
|
|
UINT DstAlignedByteOffset,
|
|
ID3D11UnorderedAccessView* pSrcView) {
|
|
auto buf = static_cast<D3D11Buffer*>(pDstBuffer);
|
|
auto uav = static_cast<D3D11UnorderedAccessView*>(pSrcView);
|
|
|
|
EmitCs([
|
|
cDstSlice = buf->GetBufferSlice(DstAlignedByteOffset),
|
|
cSrcSlice = uav->GetCounterSlice()
|
|
] (DxvkContext* ctx) {
|
|
ctx->copyBuffer(
|
|
cDstSlice.buffer(),
|
|
cDstSlice.offset(),
|
|
cSrcSlice.buffer(),
|
|
cSrcSlice.offset(),
|
|
sizeof(uint32_t));
|
|
});
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::ClearRenderTargetView(
|
|
ID3D11RenderTargetView* pRenderTargetView,
|
|
const FLOAT ColorRGBA[4]) {
|
|
auto rtv = static_cast<D3D11RenderTargetView*>(pRenderTargetView);
|
|
|
|
if (rtv == nullptr)
|
|
return;
|
|
|
|
const Rc<DxvkImageView> view = rtv->GetImageView();
|
|
|
|
VkClearValue clearValue;
|
|
clearValue.color.float32[0] = ColorRGBA[0];
|
|
clearValue.color.float32[1] = ColorRGBA[1];
|
|
clearValue.color.float32[2] = ColorRGBA[2];
|
|
clearValue.color.float32[3] = ColorRGBA[3];
|
|
|
|
VkClearRect clearRect;
|
|
clearRect.rect.offset.x = 0;
|
|
clearRect.rect.offset.y = 0;
|
|
clearRect.rect.extent.width = view->mipLevelExtent(0).width;
|
|
clearRect.rect.extent.height = view->mipLevelExtent(0).height;
|
|
clearRect.baseArrayLayer = 0;
|
|
clearRect.layerCount = view->info().numLayers;
|
|
|
|
if (m_parent->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0)
|
|
clearRect.layerCount = 1;
|
|
|
|
EmitCs([
|
|
cClearValue = clearValue,
|
|
cClearRect = clearRect,
|
|
cImageView = view
|
|
] (DxvkContext* ctx) {
|
|
ctx->clearRenderTarget(
|
|
cImageView, cClearRect,
|
|
VK_IMAGE_ASPECT_COLOR_BIT,
|
|
cClearValue);
|
|
});
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::ClearUnorderedAccessViewUint(
|
|
ID3D11UnorderedAccessView* pUnorderedAccessView,
|
|
const UINT Values[4]) {
|
|
auto uav = static_cast<D3D11UnorderedAccessView*>(pUnorderedAccessView);
|
|
|
|
if (uav == nullptr)
|
|
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;
|
|
|
|
// FIXME support packed formats
|
|
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
|
|
VkClearColorValue clearValue;
|
|
clearValue.uint32[0] = Values[0];
|
|
clearValue.uint32[1] = Values[1];
|
|
clearValue.uint32[2] = Values[2];
|
|
clearValue.uint32[3] = Values[3];
|
|
|
|
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);
|
|
});
|
|
}
|
|
} 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),
|
|
cClearValue);
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::ClearUnorderedAccessViewFloat(
|
|
ID3D11UnorderedAccessView* pUnorderedAccessView,
|
|
const FLOAT Values[4]) {
|
|
auto uav = static_cast<D3D11UnorderedAccessView*>(pUnorderedAccessView);
|
|
|
|
if (uav == nullptr)
|
|
return;
|
|
|
|
VkClearColorValue clearValue;
|
|
clearValue.float32[0] = Values[0];
|
|
clearValue.float32[1] = Values[1];
|
|
clearValue.float32[2] = Values[2];
|
|
clearValue.float32[3] = Values[3];
|
|
|
|
if (uav->GetResourceType() == D3D11_RESOURCE_DIMENSION_BUFFER) {
|
|
EmitCs([
|
|
cClearValue = clearValue,
|
|
cDstView = uav->GetBufferView()
|
|
] (DxvkContext* ctx) {
|
|
ctx->clearBufferView(
|
|
cDstView, 0,
|
|
cDstView->elementCount(),
|
|
cClearValue);
|
|
});
|
|
} else {
|
|
EmitCs([
|
|
cClearValue = clearValue,
|
|
cDstView = uav->GetImageView()
|
|
] (DxvkContext* ctx) {
|
|
ctx->clearImageView(cDstView,
|
|
VkOffset3D { 0, 0, 0 },
|
|
cDstView->mipLevelExtent(0),
|
|
cClearValue);
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::ClearDepthStencilView(
|
|
ID3D11DepthStencilView* pDepthStencilView,
|
|
UINT ClearFlags,
|
|
FLOAT Depth,
|
|
UINT8 Stencil) {
|
|
auto dsv = static_cast<D3D11DepthStencilView*>(pDepthStencilView);
|
|
|
|
if (dsv == nullptr)
|
|
return;
|
|
|
|
// Figure out which aspects to clear based
|
|
// on the image format and the clear flags.
|
|
const Rc<DxvkImageView> view = dsv->GetImageView();
|
|
|
|
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 &= imageFormatInfo(view->info().format)->aspectMask;
|
|
|
|
VkClearValue clearValue;
|
|
clearValue.depthStencil.depth = Depth;
|
|
clearValue.depthStencil.stencil = Stencil;
|
|
|
|
VkClearRect clearRect;
|
|
clearRect.rect.offset.x = 0;
|
|
clearRect.rect.offset.y = 0;
|
|
clearRect.rect.extent.width = view->mipLevelExtent(0).width;
|
|
clearRect.rect.extent.height = view->mipLevelExtent(0).height;
|
|
clearRect.baseArrayLayer = 0;
|
|
clearRect.layerCount = view->info().numLayers;
|
|
|
|
if (m_parent->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0)
|
|
clearRect.layerCount = 1;
|
|
|
|
EmitCs([
|
|
cClearValue = clearValue,
|
|
cClearRect = clearRect,
|
|
cAspectMask = aspectMask,
|
|
cImageView = view
|
|
] (DxvkContext* ctx) {
|
|
ctx->clearRenderTarget(
|
|
cImageView, cClearRect,
|
|
cAspectMask, cClearValue);
|
|
});
|
|
}
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::ClearView(
|
|
ID3D11View* pView,
|
|
const FLOAT Color[4],
|
|
const D3D11_RECT* pRect,
|
|
UINT NumRects) {
|
|
Logger::err("D3D11DeviceContext::ClearView: not implemented");
|
|
}
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::GenerateMips(ID3D11ShaderResourceView* pShaderResourceView) {
|
|
auto view = static_cast<D3D11ShaderResourceView*>(pShaderResourceView);
|
|
|
|
if (view->GetResourceType() != D3D11_RESOURCE_DIMENSION_BUFFER) {
|
|
EmitCs([cDstImageView = view->GetImageView()]
|
|
(DxvkContext* ctx) {
|
|
ctx->generateMipmaps(cDstImageView);
|
|
});
|
|
} else {
|
|
Logger::err("D3D11: GenerateMips called on a buffer");
|
|
}
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::UpdateSubresource(
|
|
ID3D11Resource* pDstResource,
|
|
UINT DstSubresource,
|
|
const D3D11_BOX* pDstBox,
|
|
const void* pSrcData,
|
|
UINT SrcRowPitch,
|
|
UINT SrcDepthPitch) {
|
|
// 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 (offset + size > bufferSlice.length()) {
|
|
Logger::err(str::format(
|
|
"D3D11: UpdateSubresource: Buffer update range out of bounds",
|
|
"\n Dst slice offset: ", bufferSlice.offset(),
|
|
"\n Dst slice length: ", bufferSlice.length(),
|
|
"\n Src slice offset: ", offset,
|
|
"\n Src slice length: ", size));
|
|
return;
|
|
}
|
|
|
|
if (size == 0)
|
|
return;
|
|
|
|
if (((size == bufferSlice.length())
|
|
&& (bufferSlice.buffer()->memFlags() & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT))) {
|
|
D3D11_MAPPED_SUBRESOURCE mappedSr;
|
|
Map(pDstResource, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedSr);
|
|
std::memcpy(mappedSr.pData, pSrcData, size);
|
|
Unmap(pDstResource, 0);
|
|
} else {
|
|
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 {
|
|
const D3D11CommonTexture* textureInfo = GetCommonTexture(pDstResource);
|
|
|
|
const VkImageSubresource subresource =
|
|
textureInfo->GetSubresourceFromIndex(
|
|
VK_IMAGE_ASPECT_COLOR_BIT, DstSubresource);
|
|
|
|
VkOffset3D offset = { 0, 0, 0 };
|
|
VkExtent3D extent = textureInfo->GetImage()->mipLevelExtent(subresource.mipLevel);
|
|
|
|
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;
|
|
}
|
|
|
|
const VkImageSubresourceLayers layers = {
|
|
subresource.aspectMask,
|
|
subresource.mipLevel,
|
|
subresource.arrayLayer, 1 };
|
|
|
|
auto formatInfo = imageFormatInfo(
|
|
textureInfo->GetImage()->info().format);
|
|
|
|
const VkExtent3D regionExtent = util::computeBlockCount(extent, formatInfo->blockSize);
|
|
|
|
const VkDeviceSize bytesPerRow = regionExtent.width * formatInfo->elementSize;
|
|
const VkDeviceSize bytesPerLayer = regionExtent.height * bytesPerRow;
|
|
const VkDeviceSize bytesTotal = regionExtent.depth * bytesPerLayer;
|
|
|
|
DxvkDataSlice imageDataBuffer = AllocUpdateBufferSlice(bytesTotal);
|
|
|
|
util::packImageData(
|
|
reinterpret_cast<char*>(imageDataBuffer.ptr()),
|
|
reinterpret_cast<const char*>(pSrcData),
|
|
regionExtent, formatInfo->elementSize,
|
|
SrcRowPitch, SrcDepthPitch);
|
|
|
|
EmitCs([
|
|
cDstImage = textureInfo->GetImage(),
|
|
cDstLayers = layers,
|
|
cDstOffset = offset,
|
|
cDstExtent = extent,
|
|
cSrcData = std::move(imageDataBuffer),
|
|
cSrcBytesPerRow = bytesPerRow,
|
|
cSrcBytesPerLayer = bytesPerLayer
|
|
] (DxvkContext* ctx) {
|
|
ctx->updateImage(cDstImage, cDstLayers,
|
|
cDstOffset, cDstExtent, cSrcData.ptr(),
|
|
cSrcBytesPerRow, cSrcBytesPerLayer);
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::UpdateSubresource1(
|
|
ID3D11Resource* pDstResource,
|
|
UINT DstSubresource,
|
|
const D3D11_BOX* pDstBox,
|
|
const void* pSrcData,
|
|
UINT SrcRowPitch,
|
|
UINT SrcDepthPitch,
|
|
UINT CopyFlags) {
|
|
UpdateSubresource(pDstResource, DstSubresource, pDstBox, pSrcData, SrcRowPitch, SrcDepthPitch);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::SetResourceMinLOD(
|
|
ID3D11Resource* pResource,
|
|
FLOAT MinLOD) {
|
|
Logger::err("D3D11DeviceContext::SetResourceMinLOD: Not implemented");
|
|
}
|
|
|
|
|
|
FLOAT STDMETHODCALLTYPE D3D11DeviceContext::GetResourceMinLOD(ID3D11Resource* pResource) {
|
|
Logger::err("D3D11DeviceContext::GetResourceMinLOD: Not implemented");
|
|
return 0.0f;
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::ResolveSubresource(
|
|
ID3D11Resource* pDstResource,
|
|
UINT DstSubresource,
|
|
ID3D11Resource* pSrcResource,
|
|
UINT SrcSubresource,
|
|
DXGI_FORMAT Format) {
|
|
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);
|
|
|
|
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) {
|
|
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) {
|
|
ctx->resolveImage(
|
|
cDstImage, cDstSubres,
|
|
cSrcImage, cSrcSubres,
|
|
cFormat);
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::DrawAuto() {
|
|
Logger::err("D3D11DeviceContext::DrawAuto: Not implemented");
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::Draw(
|
|
UINT VertexCount,
|
|
UINT StartVertexLocation) {
|
|
EmitCs([=] (DxvkContext* ctx) {
|
|
ctx->draw(
|
|
VertexCount, 1,
|
|
StartVertexLocation, 0);
|
|
});
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::DrawIndexed(
|
|
UINT IndexCount,
|
|
UINT StartIndexLocation,
|
|
INT BaseVertexLocation) {
|
|
EmitCs([=] (DxvkContext* ctx) {
|
|
ctx->drawIndexed(
|
|
IndexCount, 1,
|
|
StartIndexLocation,
|
|
BaseVertexLocation, 0);
|
|
});
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::DrawInstanced(
|
|
UINT VertexCountPerInstance,
|
|
UINT InstanceCount,
|
|
UINT StartVertexLocation,
|
|
UINT StartInstanceLocation) {
|
|
EmitCs([=] (DxvkContext* ctx) {
|
|
ctx->draw(
|
|
VertexCountPerInstance,
|
|
InstanceCount,
|
|
StartVertexLocation,
|
|
StartInstanceLocation);
|
|
});
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::DrawIndexedInstanced(
|
|
UINT IndexCountPerInstance,
|
|
UINT InstanceCount,
|
|
UINT StartIndexLocation,
|
|
INT BaseVertexLocation,
|
|
UINT StartInstanceLocation) {
|
|
EmitCs([=] (DxvkContext* ctx) {
|
|
ctx->drawIndexed(
|
|
IndexCountPerInstance,
|
|
InstanceCount,
|
|
StartIndexLocation,
|
|
BaseVertexLocation,
|
|
StartInstanceLocation);
|
|
});
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::DrawIndexedInstancedIndirect(
|
|
ID3D11Buffer* pBufferForArgs,
|
|
UINT AlignedByteOffsetForArgs) {
|
|
D3D11Buffer* buffer = static_cast<D3D11Buffer*>(pBufferForArgs);
|
|
|
|
EmitCs([bufferSlice = buffer->GetBufferSlice(AlignedByteOffsetForArgs)]
|
|
(DxvkContext* ctx) {
|
|
ctx->drawIndexedIndirect(
|
|
bufferSlice, 1, 0);
|
|
});
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::DrawInstancedIndirect(
|
|
ID3D11Buffer* pBufferForArgs,
|
|
UINT AlignedByteOffsetForArgs) {
|
|
D3D11Buffer* buffer = static_cast<D3D11Buffer*>(pBufferForArgs);
|
|
|
|
EmitCs([bufferSlice = buffer->GetBufferSlice(AlignedByteOffsetForArgs)]
|
|
(DxvkContext* ctx) {
|
|
ctx->drawIndirect(bufferSlice, 1, 0);
|
|
});
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::Dispatch(
|
|
UINT ThreadGroupCountX,
|
|
UINT ThreadGroupCountY,
|
|
UINT ThreadGroupCountZ) {
|
|
EmitCs([=] (DxvkContext* ctx) {
|
|
ctx->dispatch(
|
|
ThreadGroupCountX,
|
|
ThreadGroupCountY,
|
|
ThreadGroupCountZ);
|
|
});
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::DispatchIndirect(
|
|
ID3D11Buffer* pBufferForArgs,
|
|
UINT AlignedByteOffsetForArgs) {
|
|
D3D11Buffer* buffer = static_cast<D3D11Buffer*>(pBufferForArgs);
|
|
|
|
EmitCs([bufferSlice = buffer->GetBufferSlice(AlignedByteOffsetForArgs)]
|
|
(DxvkContext* ctx) {
|
|
ctx->dispatchIndirect(bufferSlice);
|
|
});
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::IASetInputLayout(ID3D11InputLayout* pInputLayout) {
|
|
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) {
|
|
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) {
|
|
for (uint32_t i = 0; i < NumBuffers; i++) {
|
|
auto newBuffer = static_cast<D3D11Buffer*>(ppVertexBuffers[i]);
|
|
|
|
m_state.ia.vertexBuffers[StartSlot + i].buffer = newBuffer;
|
|
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) {
|
|
auto newBuffer = static_cast<D3D11Buffer*>(pIndexBuffer);
|
|
|
|
m_state.ia.indexBuffer.buffer = newBuffer;
|
|
m_state.ia.indexBuffer.offset = Offset;
|
|
m_state.ia.indexBuffer.format = Format;
|
|
|
|
BindIndexBuffer(newBuffer, Offset, Format);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::IAGetInputLayout(ID3D11InputLayout** ppInputLayout) {
|
|
*ppInputLayout = m_state.ia.inputLayout.ref();
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::IAGetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY* pTopology) {
|
|
*pTopology = m_state.ia.primitiveTopology;
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::IAGetVertexBuffers(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer** ppVertexBuffers,
|
|
UINT* pStrides,
|
|
UINT* pOffsets) {
|
|
for (uint32_t i = 0; i < NumBuffers; i++) {
|
|
if (ppVertexBuffers != nullptr)
|
|
ppVertexBuffers[i] = m_state.ia.vertexBuffers[StartSlot + i].buffer.ref();
|
|
|
|
if (pStrides != nullptr)
|
|
pStrides[i] = m_state.ia.vertexBuffers[StartSlot + i].stride;
|
|
|
|
if (pOffsets != nullptr)
|
|
pOffsets[i] = m_state.ia.vertexBuffers[StartSlot + i].offset;
|
|
}
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::IAGetIndexBuffer(
|
|
ID3D11Buffer** ppIndexBuffer,
|
|
DXGI_FORMAT* pFormat,
|
|
UINT* pOffset) {
|
|
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) {
|
|
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(shader, VK_SHADER_STAGE_VERTEX_BIT);
|
|
}
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::VSSetConstantBuffers(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer* const* ppConstantBuffers) {
|
|
SetConstantBuffers(
|
|
DxbcProgramType::VertexShader,
|
|
m_state.vs.constantBuffers,
|
|
StartSlot, NumBuffers,
|
|
ppConstantBuffers,
|
|
nullptr, nullptr);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::VSSetConstantBuffers1(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer* const* ppConstantBuffers,
|
|
const UINT* pFirstConstant,
|
|
const UINT* pNumConstants) {
|
|
SetConstantBuffers(
|
|
DxbcProgramType::VertexShader,
|
|
m_state.vs.constantBuffers,
|
|
StartSlot, NumBuffers,
|
|
ppConstantBuffers,
|
|
pFirstConstant,
|
|
pNumConstants);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::VSSetShaderResources(
|
|
UINT StartSlot,
|
|
UINT NumViews,
|
|
ID3D11ShaderResourceView* const* ppShaderResourceViews) {
|
|
SetShaderResources(
|
|
DxbcProgramType::VertexShader,
|
|
m_state.vs.shaderResources,
|
|
StartSlot, NumViews,
|
|
ppShaderResourceViews);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::VSSetSamplers(
|
|
UINT StartSlot,
|
|
UINT NumSamplers,
|
|
ID3D11SamplerState* const* ppSamplers) {
|
|
SetSamplers(
|
|
DxbcProgramType::VertexShader,
|
|
m_state.vs.samplers,
|
|
StartSlot, NumSamplers,
|
|
ppSamplers);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::VSGetShader(
|
|
ID3D11VertexShader** ppVertexShader,
|
|
ID3D11ClassInstance** ppClassInstances,
|
|
UINT* pNumClassInstances) {
|
|
if (ppVertexShader != nullptr)
|
|
*ppVertexShader = m_state.vs.shader.ref();
|
|
|
|
if (pNumClassInstances != nullptr)
|
|
*pNumClassInstances = 0;
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::VSGetConstantBuffers(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer** ppConstantBuffers) {
|
|
GetConstantBuffers(
|
|
m_state.vs.constantBuffers,
|
|
StartSlot, NumBuffers,
|
|
ppConstantBuffers,
|
|
nullptr, nullptr);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::VSGetConstantBuffers1(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer** ppConstantBuffers,
|
|
UINT* pFirstConstant,
|
|
UINT* pNumConstants) {
|
|
GetConstantBuffers(
|
|
m_state.vs.constantBuffers,
|
|
StartSlot, NumBuffers,
|
|
ppConstantBuffers,
|
|
pFirstConstant,
|
|
pNumConstants);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::VSGetShaderResources(
|
|
UINT StartSlot,
|
|
UINT NumViews,
|
|
ID3D11ShaderResourceView** ppShaderResourceViews) {
|
|
for (uint32_t i = 0; i < NumViews; i++)
|
|
ppShaderResourceViews[i] = m_state.vs.shaderResources.at(StartSlot + i).ref();
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::VSGetSamplers(
|
|
UINT StartSlot,
|
|
UINT NumSamplers,
|
|
ID3D11SamplerState** ppSamplers) {
|
|
for (uint32_t i = 0; i < NumSamplers; i++)
|
|
ppSamplers[i] = m_state.vs.samplers.at(StartSlot + i).ref();
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::HSSetShader(
|
|
ID3D11HullShader* pHullShader,
|
|
ID3D11ClassInstance* const* ppClassInstances,
|
|
UINT NumClassInstances) {
|
|
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(shader, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
|
|
}
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::HSSetShaderResources(
|
|
UINT StartSlot,
|
|
UINT NumViews,
|
|
ID3D11ShaderResourceView* const* ppShaderResourceViews) {
|
|
SetShaderResources(
|
|
DxbcProgramType::HullShader,
|
|
m_state.hs.shaderResources,
|
|
StartSlot, NumViews,
|
|
ppShaderResourceViews);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::HSSetConstantBuffers(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer* const* ppConstantBuffers) {
|
|
SetConstantBuffers(
|
|
DxbcProgramType::HullShader,
|
|
m_state.hs.constantBuffers,
|
|
StartSlot, NumBuffers,
|
|
ppConstantBuffers,
|
|
nullptr, nullptr);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::HSSetConstantBuffers1(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer* const* ppConstantBuffers,
|
|
const UINT* pFirstConstant,
|
|
const UINT* pNumConstants) {
|
|
SetConstantBuffers(
|
|
DxbcProgramType::HullShader,
|
|
m_state.hs.constantBuffers,
|
|
StartSlot, NumBuffers,
|
|
ppConstantBuffers,
|
|
pFirstConstant,
|
|
pNumConstants);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::HSSetSamplers(
|
|
UINT StartSlot,
|
|
UINT NumSamplers,
|
|
ID3D11SamplerState* const* ppSamplers) {
|
|
SetSamplers(
|
|
DxbcProgramType::HullShader,
|
|
m_state.hs.samplers,
|
|
StartSlot, NumSamplers,
|
|
ppSamplers);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::HSGetShader(
|
|
ID3D11HullShader** ppHullShader,
|
|
ID3D11ClassInstance** ppClassInstances,
|
|
UINT* pNumClassInstances) {
|
|
if (ppHullShader != nullptr)
|
|
*ppHullShader = m_state.hs.shader.ref();
|
|
|
|
if (pNumClassInstances != nullptr)
|
|
*pNumClassInstances = 0;
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::HSGetConstantBuffers(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer** ppConstantBuffers) {
|
|
GetConstantBuffers(
|
|
m_state.hs.constantBuffers,
|
|
StartSlot, NumBuffers,
|
|
ppConstantBuffers,
|
|
nullptr, nullptr);
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::HSGetConstantBuffers1(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer** ppConstantBuffers,
|
|
UINT* pFirstConstant,
|
|
UINT* pNumConstants) {
|
|
GetConstantBuffers(
|
|
m_state.hs.constantBuffers,
|
|
StartSlot, NumBuffers,
|
|
ppConstantBuffers,
|
|
pFirstConstant,
|
|
pNumConstants);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::HSGetShaderResources(
|
|
UINT StartSlot,
|
|
UINT NumViews,
|
|
ID3D11ShaderResourceView** ppShaderResourceViews) {
|
|
for (uint32_t i = 0; i < NumViews; i++)
|
|
ppShaderResourceViews[i] = m_state.hs.shaderResources.at(StartSlot + i).ref();
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::HSGetSamplers(
|
|
UINT StartSlot,
|
|
UINT NumSamplers,
|
|
ID3D11SamplerState** ppSamplers) {
|
|
for (uint32_t i = 0; i < NumSamplers; i++)
|
|
ppSamplers[i] = m_state.hs.samplers.at(StartSlot + i).ref();
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::DSSetShader(
|
|
ID3D11DomainShader* pDomainShader,
|
|
ID3D11ClassInstance* const* ppClassInstances,
|
|
UINT NumClassInstances) {
|
|
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(shader, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT);
|
|
}
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::DSSetShaderResources(
|
|
UINT StartSlot,
|
|
UINT NumViews,
|
|
ID3D11ShaderResourceView* const* ppShaderResourceViews) {
|
|
SetShaderResources(
|
|
DxbcProgramType::DomainShader,
|
|
m_state.ds.shaderResources,
|
|
StartSlot, NumViews,
|
|
ppShaderResourceViews);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::DSSetConstantBuffers(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer* const* ppConstantBuffers) {
|
|
SetConstantBuffers(
|
|
DxbcProgramType::DomainShader,
|
|
m_state.ds.constantBuffers,
|
|
StartSlot, NumBuffers,
|
|
ppConstantBuffers,
|
|
nullptr, nullptr);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::DSSetConstantBuffers1(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer* const* ppConstantBuffers,
|
|
const UINT* pFirstConstant,
|
|
const UINT* pNumConstants) {
|
|
SetConstantBuffers(
|
|
DxbcProgramType::DomainShader,
|
|
m_state.ds.constantBuffers,
|
|
StartSlot, NumBuffers,
|
|
ppConstantBuffers,
|
|
pFirstConstant,
|
|
pNumConstants);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::DSSetSamplers(
|
|
UINT StartSlot,
|
|
UINT NumSamplers,
|
|
ID3D11SamplerState* const* ppSamplers) {
|
|
SetSamplers(
|
|
DxbcProgramType::DomainShader,
|
|
m_state.ds.samplers,
|
|
StartSlot, NumSamplers,
|
|
ppSamplers);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::DSGetShader(
|
|
ID3D11DomainShader** ppDomainShader,
|
|
ID3D11ClassInstance** ppClassInstances,
|
|
UINT* pNumClassInstances) {
|
|
if (ppDomainShader != nullptr)
|
|
*ppDomainShader = m_state.ds.shader.ref();
|
|
|
|
if (pNumClassInstances != nullptr)
|
|
*pNumClassInstances = 0;
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::DSGetConstantBuffers(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer** ppConstantBuffers) {
|
|
GetConstantBuffers(
|
|
m_state.ds.constantBuffers,
|
|
StartSlot, NumBuffers,
|
|
ppConstantBuffers,
|
|
nullptr, nullptr);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::DSGetConstantBuffers1(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer** ppConstantBuffers,
|
|
UINT* pFirstConstant,
|
|
UINT* pNumConstants) {
|
|
GetConstantBuffers(
|
|
m_state.ds.constantBuffers,
|
|
StartSlot, NumBuffers,
|
|
ppConstantBuffers,
|
|
pFirstConstant,
|
|
pNumConstants);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::DSGetShaderResources(
|
|
UINT StartSlot,
|
|
UINT NumViews,
|
|
ID3D11ShaderResourceView** ppShaderResourceViews) {
|
|
for (uint32_t i = 0; i < NumViews; i++)
|
|
ppShaderResourceViews[i] = m_state.ds.shaderResources.at(StartSlot + i).ref();
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::DSGetSamplers(
|
|
UINT StartSlot,
|
|
UINT NumSamplers,
|
|
ID3D11SamplerState** ppSamplers) {
|
|
for (uint32_t i = 0; i < NumSamplers; i++)
|
|
ppSamplers[i] = m_state.ds.samplers.at(StartSlot + i).ref();
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::GSSetShader(
|
|
ID3D11GeometryShader* pShader,
|
|
ID3D11ClassInstance* const* ppClassInstances,
|
|
UINT NumClassInstances) {
|
|
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(shader, VK_SHADER_STAGE_GEOMETRY_BIT);
|
|
}
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::GSSetConstantBuffers(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer* const* ppConstantBuffers) {
|
|
SetConstantBuffers(
|
|
DxbcProgramType::GeometryShader,
|
|
m_state.gs.constantBuffers,
|
|
StartSlot, NumBuffers,
|
|
ppConstantBuffers,
|
|
nullptr, nullptr);
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::GSSetConstantBuffers1(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer* const* ppConstantBuffers,
|
|
const UINT* pFirstConstant,
|
|
const UINT* pNumConstants) {
|
|
SetConstantBuffers(
|
|
DxbcProgramType::GeometryShader,
|
|
m_state.gs.constantBuffers,
|
|
StartSlot, NumBuffers,
|
|
ppConstantBuffers,
|
|
pFirstConstant,
|
|
pNumConstants);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::GSSetShaderResources(
|
|
UINT StartSlot,
|
|
UINT NumViews,
|
|
ID3D11ShaderResourceView* const* ppShaderResourceViews) {
|
|
SetShaderResources(
|
|
DxbcProgramType::GeometryShader,
|
|
m_state.gs.shaderResources,
|
|
StartSlot, NumViews,
|
|
ppShaderResourceViews);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::GSSetSamplers(
|
|
UINT StartSlot,
|
|
UINT NumSamplers,
|
|
ID3D11SamplerState* const* ppSamplers) {
|
|
SetSamplers(
|
|
DxbcProgramType::GeometryShader,
|
|
m_state.gs.samplers,
|
|
StartSlot, NumSamplers,
|
|
ppSamplers);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::GSGetShader(
|
|
ID3D11GeometryShader** ppGeometryShader,
|
|
ID3D11ClassInstance** ppClassInstances,
|
|
UINT* pNumClassInstances) {
|
|
if (ppGeometryShader != nullptr)
|
|
*ppGeometryShader = m_state.gs.shader.ref();
|
|
|
|
if (pNumClassInstances != nullptr)
|
|
*pNumClassInstances = 0;
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::GSGetConstantBuffers(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer** ppConstantBuffers) {
|
|
GetConstantBuffers(
|
|
m_state.gs.constantBuffers,
|
|
StartSlot, NumBuffers,
|
|
ppConstantBuffers,
|
|
nullptr, nullptr);
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::GSGetConstantBuffers1(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer** ppConstantBuffers,
|
|
UINT* pFirstConstant,
|
|
UINT* pNumConstants) {
|
|
GetConstantBuffers(
|
|
m_state.gs.constantBuffers,
|
|
StartSlot, NumBuffers,
|
|
ppConstantBuffers,
|
|
pFirstConstant,
|
|
pNumConstants);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::GSGetShaderResources(
|
|
UINT StartSlot,
|
|
UINT NumViews,
|
|
ID3D11ShaderResourceView** ppShaderResourceViews) {
|
|
for (uint32_t i = 0; i < NumViews; i++)
|
|
ppShaderResourceViews[i] = m_state.gs.shaderResources.at(StartSlot + i).ref();
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::GSGetSamplers(
|
|
UINT StartSlot,
|
|
UINT NumSamplers,
|
|
ID3D11SamplerState** ppSamplers) {
|
|
for (uint32_t i = 0; i < NumSamplers; i++)
|
|
ppSamplers[i] = m_state.gs.samplers.at(StartSlot + i).ref();
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::PSSetShader(
|
|
ID3D11PixelShader* pPixelShader,
|
|
ID3D11ClassInstance* const* ppClassInstances,
|
|
UINT NumClassInstances) {
|
|
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(shader, VK_SHADER_STAGE_FRAGMENT_BIT);
|
|
}
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::PSSetConstantBuffers(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer* const* ppConstantBuffers) {
|
|
SetConstantBuffers(
|
|
DxbcProgramType::PixelShader,
|
|
m_state.ps.constantBuffers,
|
|
StartSlot, NumBuffers,
|
|
ppConstantBuffers,
|
|
nullptr, nullptr);
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::PSSetConstantBuffers1(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer* const* ppConstantBuffers,
|
|
const UINT* pFirstConstant,
|
|
const UINT* pNumConstants) {
|
|
SetConstantBuffers(
|
|
DxbcProgramType::PixelShader,
|
|
m_state.ps.constantBuffers,
|
|
StartSlot, NumBuffers,
|
|
ppConstantBuffers,
|
|
pFirstConstant,
|
|
pNumConstants);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::PSSetShaderResources(
|
|
UINT StartSlot,
|
|
UINT NumViews,
|
|
ID3D11ShaderResourceView* const* ppShaderResourceViews) {
|
|
SetShaderResources(
|
|
DxbcProgramType::PixelShader,
|
|
m_state.ps.shaderResources,
|
|
StartSlot, NumViews,
|
|
ppShaderResourceViews);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::PSSetSamplers(
|
|
UINT StartSlot,
|
|
UINT NumSamplers,
|
|
ID3D11SamplerState* const* ppSamplers) {
|
|
SetSamplers(
|
|
DxbcProgramType::PixelShader,
|
|
m_state.ps.samplers,
|
|
StartSlot, NumSamplers,
|
|
ppSamplers);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::PSGetShader(
|
|
ID3D11PixelShader** ppPixelShader,
|
|
ID3D11ClassInstance** ppClassInstances,
|
|
UINT* pNumClassInstances) {
|
|
if (ppPixelShader != nullptr)
|
|
*ppPixelShader = m_state.ps.shader.ref();
|
|
|
|
if (pNumClassInstances != nullptr)
|
|
*pNumClassInstances = 0;
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::PSGetConstantBuffers(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer** ppConstantBuffers) {
|
|
GetConstantBuffers(
|
|
m_state.ps.constantBuffers,
|
|
StartSlot, NumBuffers,
|
|
ppConstantBuffers,
|
|
nullptr, nullptr);
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::PSGetConstantBuffers1(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer** ppConstantBuffers,
|
|
UINT* pFirstConstant,
|
|
UINT* pNumConstants) {
|
|
GetConstantBuffers(
|
|
m_state.ps.constantBuffers,
|
|
StartSlot, NumBuffers,
|
|
ppConstantBuffers,
|
|
pFirstConstant,
|
|
pNumConstants);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::PSGetShaderResources(
|
|
UINT StartSlot,
|
|
UINT NumViews,
|
|
ID3D11ShaderResourceView** ppShaderResourceViews) {
|
|
for (uint32_t i = 0; i < NumViews; i++)
|
|
ppShaderResourceViews[i] = m_state.ps.shaderResources.at(StartSlot + i).ref();
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::PSGetSamplers(
|
|
UINT StartSlot,
|
|
UINT NumSamplers,
|
|
ID3D11SamplerState** ppSamplers) {
|
|
for (uint32_t i = 0; i < NumSamplers; i++)
|
|
ppSamplers[i] = m_state.ps.samplers.at(StartSlot + i).ref();
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::CSSetShader(
|
|
ID3D11ComputeShader* pComputeShader,
|
|
ID3D11ClassInstance* const* ppClassInstances,
|
|
UINT NumClassInstances) {
|
|
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(shader, VK_SHADER_STAGE_COMPUTE_BIT);
|
|
}
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::CSSetConstantBuffers(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer* const* ppConstantBuffers) {
|
|
SetConstantBuffers(
|
|
DxbcProgramType::ComputeShader,
|
|
m_state.cs.constantBuffers,
|
|
StartSlot, NumBuffers,
|
|
ppConstantBuffers,
|
|
nullptr, nullptr);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::CSSetConstantBuffers1(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer* const* ppConstantBuffers,
|
|
const UINT* pFirstConstant,
|
|
const UINT* pNumConstants) {
|
|
SetConstantBuffers(
|
|
DxbcProgramType::ComputeShader,
|
|
m_state.cs.constantBuffers,
|
|
StartSlot, NumBuffers,
|
|
ppConstantBuffers,
|
|
pFirstConstant,
|
|
pNumConstants);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::CSSetShaderResources(
|
|
UINT StartSlot,
|
|
UINT NumViews,
|
|
ID3D11ShaderResourceView* const* ppShaderResourceViews) {
|
|
SetShaderResources(
|
|
DxbcProgramType::ComputeShader,
|
|
m_state.cs.shaderResources,
|
|
StartSlot, NumViews,
|
|
ppShaderResourceViews);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::CSSetSamplers(
|
|
UINT StartSlot,
|
|
UINT NumSamplers,
|
|
ID3D11SamplerState* const* ppSamplers) {
|
|
SetSamplers(
|
|
DxbcProgramType::ComputeShader,
|
|
m_state.cs.samplers,
|
|
StartSlot, NumSamplers,
|
|
ppSamplers);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::CSSetUnorderedAccessViews(
|
|
UINT StartSlot,
|
|
UINT NumUAVs,
|
|
ID3D11UnorderedAccessView* const* ppUnorderedAccessViews,
|
|
const UINT* pUAVInitialCounts) {
|
|
SetUnorderedAccessViews(
|
|
DxbcProgramType::ComputeShader,
|
|
m_state.cs.unorderedAccessViews,
|
|
StartSlot, NumUAVs,
|
|
ppUnorderedAccessViews);
|
|
|
|
if (pUAVInitialCounts != nullptr) {
|
|
InitUnorderedAccessViewCounters(
|
|
NumUAVs, ppUnorderedAccessViews,
|
|
pUAVInitialCounts);
|
|
}
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::CSGetShader(
|
|
ID3D11ComputeShader** ppComputeShader,
|
|
ID3D11ClassInstance** ppClassInstances,
|
|
UINT* pNumClassInstances) {
|
|
if (ppComputeShader != nullptr)
|
|
*ppComputeShader = m_state.cs.shader.ref();
|
|
|
|
if (pNumClassInstances != nullptr)
|
|
*pNumClassInstances = 0;
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::CSGetConstantBuffers(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer** ppConstantBuffers) {
|
|
GetConstantBuffers(
|
|
m_state.cs.constantBuffers,
|
|
StartSlot, NumBuffers,
|
|
ppConstantBuffers,
|
|
nullptr, nullptr);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::CSGetConstantBuffers1(
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer** ppConstantBuffers,
|
|
UINT* pFirstConstant,
|
|
UINT* pNumConstants) {
|
|
GetConstantBuffers(
|
|
m_state.cs.constantBuffers,
|
|
StartSlot, NumBuffers,
|
|
ppConstantBuffers,
|
|
pFirstConstant,
|
|
pNumConstants);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::CSGetShaderResources(
|
|
UINT StartSlot,
|
|
UINT NumViews,
|
|
ID3D11ShaderResourceView** ppShaderResourceViews) {
|
|
for (uint32_t i = 0; i < NumViews; i++)
|
|
ppShaderResourceViews[i] = m_state.cs.shaderResources.at(StartSlot + i).ref();
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::CSGetSamplers(
|
|
UINT StartSlot,
|
|
UINT NumSamplers,
|
|
ID3D11SamplerState** ppSamplers) {
|
|
for (uint32_t i = 0; i < NumSamplers; i++)
|
|
ppSamplers[i] = m_state.cs.samplers.at(StartSlot + i).ref();
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::CSGetUnorderedAccessViews(
|
|
UINT StartSlot,
|
|
UINT NumUAVs,
|
|
ID3D11UnorderedAccessView** ppUnorderedAccessViews) {
|
|
for (uint32_t i = 0; i < NumUAVs; i++)
|
|
ppUnorderedAccessViews[i] = m_state.cs.unorderedAccessViews.at(StartSlot + i).ref();
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::OMSetRenderTargets(
|
|
UINT NumViews,
|
|
ID3D11RenderTargetView* const* ppRenderTargetViews,
|
|
ID3D11DepthStencilView* pDepthStencilView) {
|
|
SetRenderTargets(NumViews, ppRenderTargetViews, pDepthStencilView);
|
|
BindFramebuffer(std::exchange(m_state.om.isUavRendering, false));
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::OMSetRenderTargetsAndUnorderedAccessViews(
|
|
UINT NumRTVs,
|
|
ID3D11RenderTargetView* const* ppRenderTargetViews,
|
|
ID3D11DepthStencilView* pDepthStencilView,
|
|
UINT UAVStartSlot,
|
|
UINT NumUAVs,
|
|
ID3D11UnorderedAccessView* const* ppUnorderedAccessViews,
|
|
const UINT* pUAVInitialCounts) {
|
|
bool spillOnBind = m_state.om.isUavRendering;
|
|
|
|
if (NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL)
|
|
SetRenderTargets(NumRTVs, ppRenderTargetViews, pDepthStencilView);
|
|
|
|
if (NumUAVs != D3D11_KEEP_UNORDERED_ACCESS_VIEWS) {
|
|
// Check whether there actually are any UAVs bound
|
|
m_state.om.isUavRendering = false;
|
|
|
|
for (uint32_t i = 0; i < NumUAVs && !m_state.om.isUavRendering; i++)
|
|
m_state.om.isUavRendering = ppUnorderedAccessViews[i] != nullptr;
|
|
|
|
// UAVs are made available to all shader stages in
|
|
// the graphics pipeline even though this code may
|
|
// suggest that they are limited to the pixel shader.
|
|
// This behaviour is only required for FL_11_1.
|
|
SetUnorderedAccessViews(
|
|
DxbcProgramType::PixelShader,
|
|
m_state.ps.unorderedAccessViews,
|
|
UAVStartSlot, NumUAVs,
|
|
ppUnorderedAccessViews);
|
|
|
|
if (pUAVInitialCounts != nullptr) {
|
|
InitUnorderedAccessViewCounters(NumUAVs,
|
|
ppUnorderedAccessViews, pUAVInitialCounts);
|
|
}
|
|
}
|
|
|
|
BindFramebuffer(spillOnBind);
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::OMSetBlendState(
|
|
ID3D11BlendState* pBlendState,
|
|
const FLOAT BlendFactor[4],
|
|
UINT SampleMask) {
|
|
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) {
|
|
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) {
|
|
if (ppRenderTargetViews != nullptr) {
|
|
for (UINT i = 0; i < NumViews; i++)
|
|
ppRenderTargetViews[i] = m_state.om.renderTargetViews[i].ref();
|
|
}
|
|
|
|
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);
|
|
|
|
if (ppUnorderedAccessViews != nullptr) {
|
|
for (UINT i = 0; i < NumUAVs; i++)
|
|
ppUnorderedAccessViews[i] = m_state.ps.unorderedAccessViews[UAVStartSlot + i].ref();
|
|
}
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::OMGetBlendState(
|
|
ID3D11BlendState** ppBlendState,
|
|
FLOAT BlendFactor[4],
|
|
UINT* pSampleMask) {
|
|
if (ppBlendState != nullptr)
|
|
*ppBlendState = m_state.om.cbState.ref();
|
|
|
|
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) {
|
|
if (ppDepthStencilState != nullptr)
|
|
*ppDepthStencilState = m_state.om.dsState.ref();
|
|
|
|
if (pStencilRef != nullptr)
|
|
*pStencilRef = m_state.om.stencilRef;
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::RSSetState(ID3D11RasterizerState* pRasterizerState) {
|
|
auto rasterizerState = static_cast<D3D11RasterizerState*>(pRasterizerState);
|
|
|
|
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();
|
|
ApplyViewportState();
|
|
}
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::RSSetViewports(
|
|
UINT NumViewports,
|
|
const D3D11_VIEWPORT* pViewports) {
|
|
m_state.rs.numViewports = NumViewports;
|
|
|
|
for (uint32_t i = 0; i < NumViewports; i++)
|
|
m_state.rs.viewports.at(i) = pViewports[i];
|
|
|
|
ApplyViewportState();
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::RSSetScissorRects(
|
|
UINT NumRects,
|
|
const D3D11_RECT* pRects) {
|
|
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)
|
|
m_state.rs.scissors.at(i) = pRects[i];
|
|
}
|
|
|
|
if (m_state.rs.state != nullptr) {
|
|
D3D11_RASTERIZER_DESC rsDesc;
|
|
m_state.rs.state->GetDesc(&rsDesc);
|
|
|
|
if (rsDesc.ScissorEnable)
|
|
ApplyViewportState();
|
|
}
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::RSGetState(ID3D11RasterizerState** ppRasterizerState) {
|
|
if (ppRasterizerState != nullptr)
|
|
*ppRasterizerState = m_state.rs.state.ref();
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::RSGetViewports(
|
|
UINT* pNumViewports,
|
|
D3D11_VIEWPORT* pViewports) {
|
|
if (pViewports != nullptr) {
|
|
for (uint32_t i = 0; i < *pNumViewports; i++) {
|
|
if (i < m_state.rs.numViewports) {
|
|
pViewports[i] = m_state.rs.viewports.at(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 = m_state.rs.numViewports;
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::RSGetScissorRects(
|
|
UINT* pNumRects,
|
|
D3D11_RECT* pRects) {
|
|
if (pRects != nullptr) {
|
|
for (uint32_t i = 0; i < *pNumRects; i++) {
|
|
if (i < m_state.rs.numScissors) {
|
|
pRects[i] = m_state.rs.scissors.at(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) {
|
|
// TODO implement properly, including pOffsets
|
|
for (uint32_t i = 0; i < D3D11_SO_STREAM_COUNT; i++) {
|
|
m_state.so.targets[i] = (ppSOTargets != nullptr && i < NumBuffers)
|
|
? static_cast<D3D11Buffer*>(ppSOTargets[i])
|
|
: nullptr;
|
|
}
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::SOGetTargets(
|
|
UINT NumBuffers,
|
|
ID3D11Buffer** ppSOTargets) {
|
|
for (uint32_t i = 0; i < NumBuffers; i++)
|
|
ppSOTargets[i] = m_state.so.targets[i].ref();
|
|
}
|
|
|
|
|
|
void STDMETHODCALLTYPE D3D11DeviceContext::TransitionSurfaceLayout(
|
|
IDXGIVkInteropSurface* pSurface,
|
|
const VkImageSubresourceRange* pSubresources,
|
|
VkImageLayout OldLayout,
|
|
VkImageLayout NewLayout) {
|
|
// 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() {
|
|
if (m_state.ia.inputLayout != nullptr) {
|
|
EmitCs([cInputLayout = m_state.ia.inputLayout] (DxvkContext* ctx) {
|
|
cInputLayout->BindToContext(ctx);
|
|
});
|
|
} else {
|
|
EmitCs([] (DxvkContext* ctx) {
|
|
ctx->setInputLayout(0, nullptr, 0, nullptr);
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::ApplyPrimitiveTopology() {
|
|
if (m_state.ia.primitiveTopology == D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED)
|
|
return;
|
|
|
|
const DxvkInputAssemblyState iaState =
|
|
[Topology = m_state.ia.primitiveTopology] () -> DxvkInputAssemblyState {
|
|
if (Topology >= D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST
|
|
&& Topology <= D3D11_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST) {
|
|
// Tessellation patch. The number of control points per
|
|
// patch can be inferred from the enum value in D3D11.
|
|
return { VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, VK_FALSE,
|
|
uint32_t(Topology - D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + 1) };
|
|
} else {
|
|
switch (Topology) {
|
|
case D3D11_PRIMITIVE_TOPOLOGY_POINTLIST:
|
|
return { VK_PRIMITIVE_TOPOLOGY_POINT_LIST, VK_FALSE, 0 };
|
|
|
|
case D3D11_PRIMITIVE_TOPOLOGY_LINELIST:
|
|
return { VK_PRIMITIVE_TOPOLOGY_LINE_LIST, VK_FALSE, 0 };
|
|
|
|
case D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP:
|
|
return { VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, VK_TRUE, 0 };
|
|
|
|
case D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST:
|
|
return { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_FALSE, 0 };
|
|
|
|
case D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP:
|
|
return { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, VK_TRUE, 0 };
|
|
|
|
case D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ:
|
|
return { VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY, VK_FALSE, 0 };
|
|
|
|
case D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ:
|
|
return { VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY, VK_TRUE, 0 };
|
|
|
|
case D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ:
|
|
return { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY, VK_FALSE, 0 };
|
|
|
|
case D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ:
|
|
return { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY, VK_TRUE, 0 };
|
|
|
|
default:
|
|
Logger::err(str::format("D3D11: Invalid primitive topology: ", Topology));
|
|
return { };
|
|
}
|
|
}
|
|
}();
|
|
|
|
EmitCs([iaState] (DxvkContext* ctx) {
|
|
ctx->setInputAssemblyState(iaState);
|
|
});
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::ApplyBlendState() {
|
|
EmitCs([
|
|
cBlendState = m_state.om.cbState != nullptr
|
|
? m_state.om.cbState
|
|
: m_defaultBlendState,
|
|
cSampleMask = m_state.om.sampleMask
|
|
] (DxvkContext* ctx) {
|
|
cBlendState->BindToContext(ctx, cSampleMask);
|
|
});
|
|
}
|
|
|
|
|
|
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() {
|
|
EmitCs([
|
|
cDepthStencilState = m_state.om.dsState != nullptr
|
|
? m_state.om.dsState
|
|
: m_defaultDepthStencilState
|
|
] (DxvkContext* ctx) {
|
|
cDepthStencilState->BindToContext(ctx);
|
|
});
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::ApplyStencilRef() {
|
|
EmitCs([
|
|
cStencilRef = m_state.om.stencilRef
|
|
] (DxvkContext* ctx) {
|
|
ctx->setStencilReference(cStencilRef);
|
|
});
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::ApplyRasterizerState() {
|
|
EmitCs([
|
|
cRasterizerState = m_state.rs.state != nullptr
|
|
? m_state.rs.state
|
|
: m_defaultRasterizerState
|
|
] (DxvkContext* ctx) {
|
|
cRasterizerState->BindToContext(ctx);
|
|
});
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::ApplyViewportState() {
|
|
// We cannot set less than one viewport in Vulkan, and
|
|
// rendering with no active viewport is illegal anyway.
|
|
if (m_state.rs.numViewports == 0)
|
|
return;
|
|
|
|
std::array<VkViewport, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE> viewports;
|
|
std::array<VkRect2D, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE> scissors;
|
|
|
|
// 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.at(i);
|
|
|
|
viewports.at(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 && (i < m_state.rs.numScissors)) {
|
|
D3D11_RECT sr = m_state.rs.scissors.at(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.at(i) = VkRect2D { srPosA, srSize };
|
|
} else {
|
|
scissors.at(i) = VkRect2D {
|
|
VkOffset2D { 0, 0 },
|
|
VkExtent2D {
|
|
D3D11_VIEWPORT_BOUNDS_MAX,
|
|
D3D11_VIEWPORT_BOUNDS_MAX } };
|
|
}
|
|
}
|
|
|
|
EmitCs([
|
|
cViewportCount = m_state.rs.numViewports,
|
|
cViewports = viewports,
|
|
cScissors = scissors
|
|
] (DxvkContext* ctx) {
|
|
ctx->setViewports(
|
|
cViewportCount,
|
|
cViewports.data(),
|
|
cScissors.data());
|
|
});
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::BindFramebuffer(BOOL Spill) {
|
|
// NOTE According to the Microsoft docs, we are supposed to
|
|
// unbind overlapping shader resource views. Since this comes
|
|
// with a large performance penalty we'll ignore this until an
|
|
// application actually relies on this behaviour.
|
|
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.at(i) != nullptr) {
|
|
attachments.color[i] = {
|
|
m_state.om.renderTargetViews.at(i)->GetImageView(),
|
|
m_state.om.renderTargetViews.at(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),
|
|
cSpill = Spill
|
|
] (DxvkContext* ctx) {
|
|
ctx->bindRenderTargets(cAttachments, cSpill);
|
|
});
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::BindVertexBuffer(
|
|
UINT Slot,
|
|
D3D11Buffer* pBuffer,
|
|
UINT Offset,
|
|
UINT Stride) {
|
|
EmitCs([
|
|
cSlotId = Slot,
|
|
cBufferSlice = pBuffer != nullptr ? pBuffer->GetBufferSlice(Offset) : DxvkBufferSlice(),
|
|
cStride = pBuffer != nullptr ? Stride : 0
|
|
] (DxvkContext* ctx) {
|
|
ctx->bindVertexBuffer(cSlotId, cBufferSlice, cStride);
|
|
});
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::BindIndexBuffer(
|
|
D3D11Buffer* pBuffer,
|
|
UINT Offset,
|
|
DXGI_FORMAT Format) {
|
|
// As in Vulkan, the index format can be either a 32-bit
|
|
// or 16-bit unsigned integer, no other formats are allowed.
|
|
VkIndexType indexType = VK_INDEX_TYPE_UINT32;
|
|
|
|
if (pBuffer != nullptr) {
|
|
switch (Format) {
|
|
case DXGI_FORMAT_R16_UINT: indexType = VK_INDEX_TYPE_UINT16; break;
|
|
case DXGI_FORMAT_R32_UINT: indexType = VK_INDEX_TYPE_UINT32; break;
|
|
default: Logger::err(str::format("D3D11: Invalid index format: ", Format));
|
|
}
|
|
}
|
|
|
|
EmitCs([
|
|
cBufferSlice = pBuffer != nullptr ? pBuffer->GetBufferSlice(Offset) : DxvkBufferSlice(),
|
|
cIndexType = indexType
|
|
] (DxvkContext* ctx) {
|
|
ctx->bindIndexBuffer(cBufferSlice, cIndexType);
|
|
});
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::BindConstantBuffer(
|
|
UINT Slot,
|
|
const D3D11ConstantBufferBinding* pBufferBinding) {
|
|
EmitCs([
|
|
cSlotId = Slot,
|
|
cBufferSlice = pBufferBinding->buffer != nullptr
|
|
? pBufferBinding->buffer->GetBufferSlice(
|
|
pBufferBinding->constantOffset * 16,
|
|
pBufferBinding->constantCount * 16)
|
|
: 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,
|
|
UINT CtrSlot,
|
|
D3D11UnorderedAccessView* pUav) {
|
|
EmitCs([
|
|
cUavSlotId = UavSlot,
|
|
cCtrSlotId = CtrSlot,
|
|
cImageView = pUav != nullptr ? pUav->GetImageView() : nullptr,
|
|
cBufferView = pUav != nullptr ? pUav->GetBufferView() : nullptr,
|
|
cCounterSlice = pUav != nullptr ? pUav->GetCounterSlice() : DxvkBufferSlice()
|
|
] (DxvkContext* ctx) {
|
|
ctx->bindResourceView (cUavSlotId, cImageView, cBufferView);
|
|
ctx->bindResourceBuffer (cCtrSlotId, cCounterSlice);
|
|
});
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::SetConstantBuffers(
|
|
DxbcProgramType ShaderStage,
|
|
D3D11ConstantBufferBindings& Bindings,
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer* const* ppConstantBuffers,
|
|
const UINT* pFirstConstant,
|
|
const UINT* pNumConstants) {
|
|
const uint32_t slotId = computeResourceSlotId(
|
|
ShaderStage, DxbcBindingType::ConstantBuffer,
|
|
StartSlot);
|
|
|
|
for (uint32_t i = 0; i < NumBuffers; i++) {
|
|
auto newBuffer = static_cast<D3D11Buffer*>(ppConstantBuffers[i]);
|
|
|
|
UINT constantOffset = 0;
|
|
UINT constantCount = newBuffer != nullptr
|
|
? newBuffer->GetSize() / 16
|
|
: 0;
|
|
|
|
if (newBuffer != nullptr && pFirstConstant != nullptr && pNumConstants != nullptr) {
|
|
constantOffset = pFirstConstant[i];
|
|
constantCount = pNumConstants [i];
|
|
}
|
|
|
|
if (Bindings[StartSlot + i].buffer != newBuffer
|
|
|| Bindings[StartSlot + i].constantOffset != constantOffset
|
|
|| Bindings[StartSlot + i].constantCount != constantCount) {
|
|
Bindings[StartSlot + i].buffer = newBuffer;
|
|
Bindings[StartSlot + i].constantOffset = constantOffset;
|
|
Bindings[StartSlot + i].constantCount = constantCount;
|
|
|
|
BindConstantBuffer(slotId + i, &Bindings[StartSlot + i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::SetSamplers(
|
|
DxbcProgramType ShaderStage,
|
|
D3D11SamplerBindings& Bindings,
|
|
UINT StartSlot,
|
|
UINT NumSamplers,
|
|
ID3D11SamplerState* const* ppSamplers) {
|
|
const uint32_t slotId = computeResourceSlotId(
|
|
ShaderStage, DxbcBindingType::ImageSampler,
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::SetShaderResources(
|
|
DxbcProgramType ShaderStage,
|
|
D3D11ShaderResourceBindings& Bindings,
|
|
UINT StartSlot,
|
|
UINT NumResources,
|
|
ID3D11ShaderResourceView* const* ppResources) {
|
|
const uint32_t slotId = computeResourceSlotId(
|
|
ShaderStage, DxbcBindingType::ShaderResource,
|
|
StartSlot);
|
|
|
|
for (uint32_t i = 0; i < NumResources; i++) {
|
|
auto resView = static_cast<D3D11ShaderResourceView*>(ppResources[i]);
|
|
|
|
if (Bindings[StartSlot + i] != resView) {
|
|
Bindings[StartSlot + i] = resView;
|
|
BindShaderResource(slotId + i, resView);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::SetUnorderedAccessViews(
|
|
DxbcProgramType ShaderStage,
|
|
D3D11UnorderedAccessBindings& Bindings,
|
|
UINT StartSlot,
|
|
UINT NumUAVs,
|
|
ID3D11UnorderedAccessView* const* ppUnorderedAccessViews) {
|
|
const uint32_t uavSlotId = computeResourceSlotId(
|
|
ShaderStage, DxbcBindingType::UnorderedAccessView,
|
|
StartSlot);
|
|
|
|
const uint32_t ctrSlotId = computeResourceSlotId(
|
|
ShaderStage, DxbcBindingType::UavCounter,
|
|
StartSlot);
|
|
|
|
for (uint32_t i = 0; i < NumUAVs; i++) {
|
|
auto uav = static_cast<D3D11UnorderedAccessView*>(ppUnorderedAccessViews[i]);
|
|
|
|
if (Bindings[StartSlot + i] != uav) {
|
|
Bindings[StartSlot + i] = uav;
|
|
BindUnorderedAccessView(uavSlotId + i, ctrSlotId + i, uav);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::SetRenderTargets(
|
|
UINT NumViews,
|
|
ID3D11RenderTargetView* const* ppRenderTargetViews,
|
|
ID3D11DepthStencilView* pDepthStencilView) {
|
|
// Native D3D11 does not change the render targets if
|
|
// the parameters passed to this method are invalid.
|
|
if (!ValidateRenderTargets(NumViews, ppRenderTargetViews, pDepthStencilView))
|
|
return;
|
|
|
|
for (UINT i = 0; i < m_state.om.renderTargetViews.size(); i++) {
|
|
m_state.om.renderTargetViews.at(i) = i < NumViews
|
|
? static_cast<D3D11RenderTargetView*>(ppRenderTargetViews[i])
|
|
: nullptr;
|
|
}
|
|
|
|
m_state.om.depthStencilView = static_cast<D3D11DepthStencilView*>(pDepthStencilView);
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::InitUnorderedAccessViewCounters(
|
|
UINT NumUAVs,
|
|
ID3D11UnorderedAccessView* const* ppUnorderedAccessViews,
|
|
const UINT* pUAVInitialCounts) {
|
|
for (uint32_t i = 0; i < NumUAVs; i++) {
|
|
auto uav = static_cast<D3D11UnorderedAccessView*>(ppUnorderedAccessViews[i]);
|
|
|
|
if (uav != nullptr) {
|
|
const DxvkBufferSlice counterSlice = uav->GetCounterSlice();
|
|
const D3D11UavCounter counterValue = { pUAVInitialCounts[i] };
|
|
|
|
if (counterSlice.defined() && counterValue.atomicCtr != 0xFFFFFFFFu) {
|
|
EmitCs([counterSlice, counterValue] (DxvkContext* ctx) {
|
|
ctx->clearBuffer(
|
|
counterSlice.buffer(),
|
|
counterSlice.offset(),
|
|
counterSlice.length(),
|
|
counterValue.atomicCtr);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::GetConstantBuffers(
|
|
const D3D11ConstantBufferBindings& Bindings,
|
|
UINT StartSlot,
|
|
UINT NumBuffers,
|
|
ID3D11Buffer** ppConstantBuffers,
|
|
UINT* pFirstConstant,
|
|
UINT* pNumConstants) {
|
|
for (uint32_t i = 0; i < NumBuffers; i++) {
|
|
if (ppConstantBuffers != nullptr)
|
|
ppConstantBuffers[i] = Bindings[StartSlot + i].buffer.ref();
|
|
|
|
if (pFirstConstant != nullptr)
|
|
pFirstConstant[i] = Bindings[StartSlot + i].constantOffset;
|
|
|
|
if (pNumConstants != nullptr)
|
|
pNumConstants[i] = Bindings[StartSlot + i].constantCount;
|
|
}
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::RestoreState() {
|
|
BindFramebuffer(m_state.om.isUavRendering);
|
|
|
|
BindShader(m_state.vs.shader.ptr(), VK_SHADER_STAGE_VERTEX_BIT);
|
|
BindShader(m_state.hs.shader.ptr(), VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
|
|
BindShader(m_state.ds.shader.ptr(), VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT);
|
|
BindShader(m_state.gs.shader.ptr(), VK_SHADER_STAGE_GEOMETRY_BIT);
|
|
BindShader(m_state.ps.shader.ptr(), VK_SHADER_STAGE_FRAGMENT_BIT);
|
|
BindShader(m_state.cs.shader.ptr(), VK_SHADER_STAGE_COMPUTE_BIT);
|
|
|
|
ApplyInputLayout();
|
|
ApplyPrimitiveTopology();
|
|
ApplyBlendState();
|
|
ApplyBlendFactor();
|
|
ApplyDepthStencilState();
|
|
ApplyStencilRef();
|
|
ApplyRasterizerState();
|
|
ApplyViewportState();
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::RestoreConstantBuffers(
|
|
DxbcProgramType Stage,
|
|
D3D11ConstantBufferBindings& Bindings) {
|
|
const uint32_t slotId = computeResourceSlotId(
|
|
Stage, DxbcBindingType::ConstantBuffer, 0);
|
|
|
|
for (uint32_t i = 0; i < Bindings.size(); i++)
|
|
BindConstantBuffer(slotId + i, &Bindings[i]);
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::RestoreSamplers(
|
|
DxbcProgramType Stage,
|
|
D3D11SamplerBindings& Bindings) {
|
|
const uint32_t slotId = computeResourceSlotId(
|
|
Stage, DxbcBindingType::ImageSampler, 0);
|
|
|
|
for (uint32_t i = 0; i < Bindings.size(); i++)
|
|
BindSampler(slotId + i, Bindings[i].ptr());
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::RestoreShaderResources(
|
|
DxbcProgramType Stage,
|
|
D3D11ShaderResourceBindings& Bindings) {
|
|
const uint32_t slotId = computeResourceSlotId(
|
|
Stage, DxbcBindingType::ShaderResource, 0);
|
|
|
|
for (uint32_t i = 0; i < Bindings.size(); i++)
|
|
BindShaderResource(slotId + i, Bindings[i].ptr());
|
|
}
|
|
|
|
|
|
void D3D11DeviceContext::RestoreUnorderedAccessViews(
|
|
DxbcProgramType Stage,
|
|
D3D11UnorderedAccessBindings& Bindings) {
|
|
const uint32_t uavSlotId = computeResourceSlotId(
|
|
Stage, DxbcBindingType::UnorderedAccessView, 0);
|
|
|
|
const uint32_t ctrSlotId = computeResourceSlotId(
|
|
Stage, DxbcBindingType::UavCounter, 0);
|
|
|
|
for (uint32_t i = 0; i < Bindings.size(); i++) {
|
|
BindUnorderedAccessView(
|
|
uavSlotId + i, ctrSlotId + i,
|
|
Bindings[i].ptr());
|
|
}
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
}
|