mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-02-27 04:54:15 +01:00
[d3d9] Improve code readability with comments
This commit is contained in:
parent
19fea8c48d
commit
48d8e7c402
@ -80,6 +80,7 @@ namespace dxvk {
|
|||||||
] (DxvkContext* ctx) {
|
] (DxvkContext* ctx) {
|
||||||
ctx->beginRecording(cDevice->createCommandList());
|
ctx->beginRecording(cDevice->createCommandList());
|
||||||
|
|
||||||
|
// Disable logic op once and for all.
|
||||||
DxvkLogicOpState loState;
|
DxvkLogicOpState loState;
|
||||||
loState.enableLogicOp = VK_FALSE;
|
loState.enableLogicOp = VK_FALSE;
|
||||||
loState.logicOp = VK_LOGIC_OP_CLEAR;
|
loState.logicOp = VK_LOGIC_OP_CLEAR;
|
||||||
@ -93,6 +94,8 @@ namespace dxvk {
|
|||||||
|
|
||||||
m_dxsoOptions = DxsoOptions(this, m_d3d9Options);
|
m_dxsoOptions = DxsoOptions(this, m_d3d9Options);
|
||||||
|
|
||||||
|
// Check if VK_EXT_robustness2 is supported, so we can optimize the number of constants we need to copy.
|
||||||
|
// Also check the required alignments.
|
||||||
const bool supportsRobustness2 = m_dxvkDevice->features().extRobustness2.robustBufferAccess2;
|
const bool supportsRobustness2 = m_dxvkDevice->features().extRobustness2.robustBufferAccess2;
|
||||||
bool useRobustConstantAccess = supportsRobustness2;
|
bool useRobustConstantAccess = supportsRobustness2;
|
||||||
if (useRobustConstantAccess) {
|
if (useRobustConstantAccess) {
|
||||||
@ -110,6 +113,7 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!useRobustConstantAccess) {
|
if (!useRobustConstantAccess) {
|
||||||
|
// Disable optimized constant copies, we always have to copy all constants.
|
||||||
m_vsFloatConstsCount = m_vsLayout.floatCount;
|
m_vsFloatConstsCount = m_vsLayout.floatCount;
|
||||||
m_vsIntConstsCount = m_vsLayout.intCount;
|
m_vsIntConstsCount = m_vsLayout.intCount;
|
||||||
m_vsBoolConstsCount = m_vsLayout.boolCount;
|
m_vsBoolConstsCount = m_vsLayout.boolCount;
|
||||||
@ -120,8 +124,10 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for VK_EXT_graphics_pipeline_libraries
|
||||||
m_usingGraphicsPipelines = dxvkDevice->features().extGraphicsPipelineLibrary.graphicsPipelineLibrary;
|
m_usingGraphicsPipelines = dxvkDevice->features().extGraphicsPipelineLibrary.graphicsPipelineLibrary;
|
||||||
|
|
||||||
|
// Check for VK_EXT_depth_bias_control and set up initial state
|
||||||
m_depthBiasRepresentation = { VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORMAT_EXT, false };
|
m_depthBiasRepresentation = { VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORMAT_EXT, false };
|
||||||
if (dxvkDevice->features().extDepthBiasControl.depthBiasControl) {
|
if (dxvkDevice->features().extDepthBiasControl.depthBiasControl) {
|
||||||
if (dxvkDevice->features().extDepthBiasControl.depthBiasExact)
|
if (dxvkDevice->features().extDepthBiasControl.depthBiasExact)
|
||||||
@ -628,11 +634,14 @@ namespace dxvk {
|
|||||||
try {
|
try {
|
||||||
void* initialData = nullptr;
|
void* initialData = nullptr;
|
||||||
|
|
||||||
|
// On Windows Vista (so most likely D3D9Ex), pSharedHandle can be used to pass initial data for a texture,
|
||||||
|
// but only for a very specific type of texture.
|
||||||
if (Pool == D3DPOOL_SYSTEMMEM && Levels == 1 && pSharedHandle != nullptr) {
|
if (Pool == D3DPOOL_SYSTEMMEM && Levels == 1 && pSharedHandle != nullptr) {
|
||||||
initialData = *(reinterpret_cast<void**>(pSharedHandle));
|
initialData = *(reinterpret_cast<void**>(pSharedHandle));
|
||||||
pSharedHandle = nullptr;
|
pSharedHandle = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shared textures have to be in POOL_DEFAULT
|
||||||
if (pSharedHandle != nullptr && Pool != D3DPOOL_DEFAULT)
|
if (pSharedHandle != nullptr && Pool != D3DPOOL_DEFAULT)
|
||||||
return D3DERR_INVALIDCALL;
|
return D3DERR_INVALIDCALL;
|
||||||
|
|
||||||
@ -700,6 +709,7 @@ namespace dxvk {
|
|||||||
m_initializer->InitTexture(texture->GetCommonTexture());
|
m_initializer->InitTexture(texture->GetCommonTexture());
|
||||||
*ppVolumeTexture = texture.ref();
|
*ppVolumeTexture = texture.ref();
|
||||||
|
|
||||||
|
// The device cannot be reset if there's any remaining default resources
|
||||||
if (desc.Pool == D3DPOOL_DEFAULT)
|
if (desc.Pool == D3DPOOL_DEFAULT)
|
||||||
m_losableResourceCounter++;
|
m_losableResourceCounter++;
|
||||||
|
|
||||||
@ -757,6 +767,7 @@ namespace dxvk {
|
|||||||
m_initializer->InitTexture(texture->GetCommonTexture());
|
m_initializer->InitTexture(texture->GetCommonTexture());
|
||||||
*ppCubeTexture = texture.ref();
|
*ppCubeTexture = texture.ref();
|
||||||
|
|
||||||
|
// The device cannot be reset if there's any remaining default resources
|
||||||
if (desc.Pool == D3DPOOL_DEFAULT)
|
if (desc.Pool == D3DPOOL_DEFAULT)
|
||||||
m_losableResourceCounter++;
|
m_losableResourceCounter++;
|
||||||
|
|
||||||
@ -799,6 +810,8 @@ namespace dxvk {
|
|||||||
const Com<D3D9VertexBuffer> buffer = new D3D9VertexBuffer(this, &desc);
|
const Com<D3D9VertexBuffer> buffer = new D3D9VertexBuffer(this, &desc);
|
||||||
m_initializer->InitBuffer(buffer->GetCommonBuffer());
|
m_initializer->InitBuffer(buffer->GetCommonBuffer());
|
||||||
*ppVertexBuffer = buffer.ref();
|
*ppVertexBuffer = buffer.ref();
|
||||||
|
|
||||||
|
// The device cannot be reset if there's any remaining default resources
|
||||||
if (desc.Pool == D3DPOOL_DEFAULT)
|
if (desc.Pool == D3DPOOL_DEFAULT)
|
||||||
m_losableResourceCounter++;
|
m_losableResourceCounter++;
|
||||||
|
|
||||||
@ -840,6 +853,8 @@ namespace dxvk {
|
|||||||
const Com<D3D9IndexBuffer> buffer = new D3D9IndexBuffer(this, &desc);
|
const Com<D3D9IndexBuffer> buffer = new D3D9IndexBuffer(this, &desc);
|
||||||
m_initializer->InitBuffer(buffer->GetCommonBuffer());
|
m_initializer->InitBuffer(buffer->GetCommonBuffer());
|
||||||
*ppIndexBuffer = buffer.ref();
|
*ppIndexBuffer = buffer.ref();
|
||||||
|
|
||||||
|
// The device cannot be reset if there's any remaining default resources
|
||||||
if (desc.Pool == D3DPOOL_DEFAULT)
|
if (desc.Pool == D3DPOOL_DEFAULT)
|
||||||
m_losableResourceCounter++;
|
m_losableResourceCounter++;
|
||||||
|
|
||||||
@ -963,8 +978,10 @@ namespace dxvk {
|
|||||||
0u };
|
0u };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The source surface must be in D3DPOOL_SYSTEMMEM so we just treat it as just another texture upload except with a different source.
|
||||||
UpdateTextureFromBuffer(dstTextureInfo, srcTextureInfo, dst->GetSubresource(), src->GetSubresource(), srcOffset, extent, dstOffset);
|
UpdateTextureFromBuffer(dstTextureInfo, srcTextureInfo, dst->GetSubresource(), src->GetSubresource(), srcOffset, extent, dstOffset);
|
||||||
|
|
||||||
|
// The contents of the mapping no longer match the image.
|
||||||
dstTextureInfo->SetNeedsReadback(dst->GetSubresource(), true);
|
dstTextureInfo->SetNeedsReadback(dst->GetSubresource(), true);
|
||||||
|
|
||||||
if (dstTextureInfo->IsAutomaticMip())
|
if (dstTextureInfo->IsAutomaticMip())
|
||||||
@ -1008,6 +1025,8 @@ namespace dxvk {
|
|||||||
if (srcFirstMipExtent != dstFirstMipExtent) {
|
if (srcFirstMipExtent != dstFirstMipExtent) {
|
||||||
// UpdateTexture can be used with textures that have different mip lengths.
|
// UpdateTexture can be used with textures that have different mip lengths.
|
||||||
// It will either match the the top mips or the bottom ones.
|
// It will either match the the top mips or the bottom ones.
|
||||||
|
// If the largest mip maps don't match in size, we try to take the smallest ones
|
||||||
|
// of the source.
|
||||||
|
|
||||||
srcMipOffset = srcTexInfo->Desc()->MipLevels - mipLevels;
|
srcMipOffset = srcTexInfo->Desc()->MipLevels - mipLevels;
|
||||||
srcFirstMipExtent = util::computeMipLevelExtent(srcTexInfo->GetExtent(), srcMipOffset);
|
srcFirstMipExtent = util::computeMipLevelExtent(srcTexInfo->GetExtent(), srcMipOffset);
|
||||||
@ -1018,10 +1037,12 @@ namespace dxvk {
|
|||||||
return D3DERR_INVALIDCALL;
|
return D3DERR_INVALIDCALL;
|
||||||
|
|
||||||
for (uint32_t a = 0; a < arraySlices; a++) {
|
for (uint32_t a = 0; a < arraySlices; a++) {
|
||||||
|
// The docs claim that the dirty box is just a performance optimization, however in practice games rely on it.
|
||||||
const D3DBOX& box = srcTexInfo->GetDirtyBox(a);
|
const D3DBOX& box = srcTexInfo->GetDirtyBox(a);
|
||||||
if (box.Left >= box.Right || box.Top >= box.Bottom || box.Front >= box.Back)
|
if (box.Left >= box.Right || box.Top >= box.Bottom || box.Front >= box.Back)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// The dirty box is only tracked for mip level 0
|
||||||
VkExtent3D mip0Extent = {
|
VkExtent3D mip0Extent = {
|
||||||
uint32_t(box.Right - box.Left),
|
uint32_t(box.Right - box.Left),
|
||||||
uint32_t(box.Bottom - box.Top),
|
uint32_t(box.Bottom - box.Top),
|
||||||
@ -1030,13 +1051,17 @@ namespace dxvk {
|
|||||||
VkOffset3D mip0Offset = { int32_t(box.Left), int32_t(box.Top), int32_t(box.Front) };
|
VkOffset3D mip0Offset = { int32_t(box.Left), int32_t(box.Top), int32_t(box.Front) };
|
||||||
|
|
||||||
for (uint32_t dstMip = 0; dstMip < mipLevels; dstMip++) {
|
for (uint32_t dstMip = 0; dstMip < mipLevels; dstMip++) {
|
||||||
|
// Scale the dirty box for the respective mip level
|
||||||
uint32_t srcMip = dstMip + srcMipOffset;
|
uint32_t srcMip = dstMip + srcMipOffset;
|
||||||
uint32_t srcSubresource = srcTexInfo->CalcSubresource(a, srcMip);
|
uint32_t srcSubresource = srcTexInfo->CalcSubresource(a, srcMip);
|
||||||
uint32_t dstSubresource = dstTexInfo->CalcSubresource(a, dstMip);
|
uint32_t dstSubresource = dstTexInfo->CalcSubresource(a, dstMip);
|
||||||
VkExtent3D extent = util::computeMipLevelExtent(mip0Extent, srcMip);
|
VkExtent3D extent = util::computeMipLevelExtent(mip0Extent, srcMip);
|
||||||
VkOffset3D offset = util::computeMipLevelOffset(mip0Offset, srcMip);
|
VkOffset3D offset = util::computeMipLevelOffset(mip0Offset, srcMip);
|
||||||
|
|
||||||
|
// The source surface must be in D3DPOOL_SYSTEMMEM so we just treat it as just another texture upload except with a different source.
|
||||||
UpdateTextureFromBuffer(dstTexInfo, srcTexInfo, dstSubresource, srcSubresource, offset, extent, offset);
|
UpdateTextureFromBuffer(dstTexInfo, srcTexInfo, dstSubresource, srcSubresource, offset, extent, offset);
|
||||||
|
|
||||||
|
// The contents of the mapping no longer match the image.
|
||||||
dstTexInfo->SetNeedsReadback(dstSubresource, true);
|
dstTexInfo->SetNeedsReadback(dstSubresource, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1567,8 +1592,11 @@ namespace dxvk {
|
|||||||
|
|
||||||
m_state.renderTargets[RenderTargetIndex] = rt;
|
m_state.renderTargets[RenderTargetIndex] = rt;
|
||||||
|
|
||||||
|
// Update feedback loop tracking bitmasks
|
||||||
UpdateActiveRTs(RenderTargetIndex);
|
UpdateActiveRTs(RenderTargetIndex);
|
||||||
|
|
||||||
|
// Update render target alpha swizzle bitmask if we need to fix up the alpha channel
|
||||||
|
// for XRGB formats
|
||||||
uint32_t originalAlphaSwizzleRTs = m_alphaSwizzleRTs;
|
uint32_t originalAlphaSwizzleRTs = m_alphaSwizzleRTs;
|
||||||
|
|
||||||
m_alphaSwizzleRTs &= ~(1 << RenderTargetIndex);
|
m_alphaSwizzleRTs &= ~(1 << RenderTargetIndex);
|
||||||
@ -1643,6 +1671,7 @@ namespace dxvk {
|
|||||||
ConsiderFlush(GpuFlushType::ImplicitWeakHint);
|
ConsiderFlush(GpuFlushType::ImplicitWeakHint);
|
||||||
m_flags.set(D3D9DeviceFlag::DirtyFramebuffer);
|
m_flags.set(D3D9DeviceFlag::DirtyFramebuffer);
|
||||||
|
|
||||||
|
// Update depth bias if necessary
|
||||||
if (ds != nullptr && m_depthBiasRepresentation.depthBiasRepresentation != VK_DEPTH_BIAS_REPRESENTATION_FLOAT_EXT) {
|
if (ds != nullptr && m_depthBiasRepresentation.depthBiasRepresentation != VK_DEPTH_BIAS_REPRESENTATION_FLOAT_EXT) {
|
||||||
const int32_t vendorId = m_dxvkDevice->adapter()->deviceProperties().vendorID;
|
const int32_t vendorId = m_dxvkDevice->adapter()->deviceProperties().vendorID;
|
||||||
const bool exact = m_depthBiasRepresentation.depthBiasExact;
|
const bool exact = m_depthBiasRepresentation.depthBiasExact;
|
||||||
@ -3519,6 +3548,9 @@ namespace dxvk {
|
|||||||
|
|
||||||
m_state.indices = buffer;
|
m_state.indices = buffer;
|
||||||
|
|
||||||
|
// Don't unbind the buffer if the game sets a nullptr here.
|
||||||
|
// Operation Flashpoint Red River breaks if we do that.
|
||||||
|
// EndScene will clean it up if necessary.
|
||||||
if (buffer != nullptr)
|
if (buffer != nullptr)
|
||||||
BindIndices();
|
BindIndices();
|
||||||
|
|
||||||
@ -4212,17 +4244,24 @@ namespace dxvk {
|
|||||||
// We need to check our ops and disable respective stages.
|
// We need to check our ops and disable respective stages.
|
||||||
// Given we have transition from a null resource to
|
// Given we have transition from a null resource to
|
||||||
// a valid resource or vice versa.
|
// a valid resource or vice versa.
|
||||||
if (StateSampler < caps::MaxTexturesPS) {
|
const bool isPSSampler = StateSampler < caps::MaxTexturesPS;
|
||||||
const uint32_t offset = StateSampler * 2;
|
if (isPSSampler) {
|
||||||
const uint32_t textureType = newTexture != nullptr
|
const uint32_t textureType = newTexture != nullptr
|
||||||
? uint32_t(newTexture->GetType() - D3DRTYPE_TEXTURE)
|
? uint32_t(newTexture->GetType() - D3DRTYPE_TEXTURE)
|
||||||
: 0;
|
: 0;
|
||||||
|
// There are 4 texture types, so we need 2 bits.
|
||||||
|
const uint32_t offset = StateSampler * 2;
|
||||||
const uint32_t textureBitMask = 0b11u << offset;
|
const uint32_t textureBitMask = 0b11u << offset;
|
||||||
const uint32_t textureBits = textureType << offset;
|
const uint32_t textureBits = textureType << offset;
|
||||||
|
|
||||||
|
// In fixed function shaders and SM < 3 we put the type mask
|
||||||
|
// into a spec constant to select the used sampler type.
|
||||||
m_textureTypes &= ~textureBitMask;
|
m_textureTypes &= ~textureBitMask;
|
||||||
m_textureTypes |= textureBits;
|
m_textureTypes |= textureBits;
|
||||||
|
|
||||||
|
// If we either bind a new texture or unbind the old one,
|
||||||
|
// we need to update the fixed function shader
|
||||||
|
// because we generate a different shader based on whether each texture is bound.
|
||||||
if (newTexture == nullptr || oldTexture == nullptr)
|
if (newTexture == nullptr || oldTexture == nullptr)
|
||||||
m_flags.set(D3D9DeviceFlag::DirtyFFPixelShader);
|
m_flags.set(D3D9DeviceFlag::DirtyFFPixelShader);
|
||||||
}
|
}
|
||||||
@ -4512,7 +4551,7 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool D3D9DeviceEx::ShouldRecord() {
|
inline bool D3D9DeviceEx::ShouldRecord() {
|
||||||
return m_recorder != nullptr && !m_recorder->IsApplying();
|
return m_recorder != nullptr && !m_recorder->IsApplying();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4651,7 +4690,6 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto& formatMapping = pResource->GetFormatMapping();
|
auto& formatMapping = pResource->GetFormatMapping();
|
||||||
|
|
||||||
const DxvkFormatInfo* formatInfo = formatMapping.IsValid()
|
const DxvkFormatInfo* formatInfo = formatMapping.IsValid()
|
||||||
? lookupFormatInfo(formatMapping.FormatColor) : UnsupportedFormatInfo(pResource->Desc()->Format);
|
? lookupFormatInfo(formatMapping.FormatColor) : UnsupportedFormatInfo(pResource->Desc()->Format);
|
||||||
|
|
||||||
@ -4663,6 +4701,7 @@ namespace dxvk {
|
|||||||
|
|
||||||
bool fullResource = pBox == nullptr;
|
bool fullResource = pBox == nullptr;
|
||||||
if (unlikely(!fullResource)) {
|
if (unlikely(!fullResource)) {
|
||||||
|
// Check whether the box passed as argument matches or exceeds the entire texture.
|
||||||
VkOffset3D lockOffset;
|
VkOffset3D lockOffset;
|
||||||
VkExtent3D lockExtent;
|
VkExtent3D lockExtent;
|
||||||
|
|
||||||
@ -4677,7 +4716,7 @@ namespace dxvk {
|
|||||||
// If we are not locking the entire image
|
// If we are not locking the entire image
|
||||||
// a partial discard is meant to occur.
|
// a partial discard is meant to occur.
|
||||||
// We can't really implement that, so just ignore discard
|
// We can't really implement that, so just ignore discard
|
||||||
// if we are not locking the full resource
|
// if we are not locking the full resource.
|
||||||
|
|
||||||
// DISCARD is also ignored for MANAGED and SYSTEMEM.
|
// DISCARD is also ignored for MANAGED and SYSTEMEM.
|
||||||
// DISCARD is not ignored for non-DYNAMIC unlike what the docs say.
|
// DISCARD is not ignored for non-DYNAMIC unlike what the docs say.
|
||||||
@ -4700,7 +4739,6 @@ namespace dxvk {
|
|||||||
needsReadback &= pResource->GetImage() != nullptr || !(Flags & D3DLOCK_DISCARD);
|
needsReadback &= pResource->GetImage() != nullptr || !(Flags & D3DLOCK_DISCARD);
|
||||||
pResource->SetNeedsReadback(Subresource, false);
|
pResource->SetNeedsReadback(Subresource, false);
|
||||||
|
|
||||||
|
|
||||||
if (unlikely(pResource->GetMapMode() == D3D9_COMMON_TEXTURE_MAP_MODE_BACKED || needsReadback)) {
|
if (unlikely(pResource->GetMapMode() == D3D9_COMMON_TEXTURE_MAP_MODE_BACKED || needsReadback)) {
|
||||||
// Create mapping buffer if it doesn't exist yet. (POOL_DEFAULT)
|
// Create mapping buffer if it doesn't exist yet. (POOL_DEFAULT)
|
||||||
pResource->CreateBuffer(!needsReadback);
|
pResource->CreateBuffer(!needsReadback);
|
||||||
@ -4710,6 +4748,10 @@ namespace dxvk {
|
|||||||
void* mapPtr = pResource->GetData(Subresource);
|
void* mapPtr = pResource->GetData(Subresource);
|
||||||
|
|
||||||
if (unlikely(needsReadback)) {
|
if (unlikely(needsReadback)) {
|
||||||
|
// The texture was written to on the GPU.
|
||||||
|
// This can be either the image (for D3DPOOL_DEFAULT)
|
||||||
|
// or the buffer directly (for D3DPOOL_SYSTEMMEM).
|
||||||
|
|
||||||
DxvkBufferSlice mappedBufferSlice = pResource->GetBufferSlice(Subresource);
|
DxvkBufferSlice mappedBufferSlice = pResource->GetBufferSlice(Subresource);
|
||||||
const Rc<DxvkBuffer> mappedBuffer = pResource->GetBuffer();
|
const Rc<DxvkBuffer> mappedBuffer = pResource->GetBuffer();
|
||||||
|
|
||||||
@ -4736,6 +4778,9 @@ namespace dxvk {
|
|||||||
// lock MSAA render targets even though
|
// lock MSAA render targets even though
|
||||||
// that's entirely illegal and they explicitly
|
// that's entirely illegal and they explicitly
|
||||||
// tell us that they do NOT want to lock them...
|
// tell us that they do NOT want to lock them...
|
||||||
|
//
|
||||||
|
// resourceImage is null because the image reference was moved to mappedImage
|
||||||
|
// for images that need to be resolved.
|
||||||
if (resourceImage != nullptr) {
|
if (resourceImage != nullptr) {
|
||||||
EmitCs([
|
EmitCs([
|
||||||
cMainImage = resourceImage,
|
cMainImage = resourceImage,
|
||||||
@ -4763,6 +4808,8 @@ namespace dxvk {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if packedFormat is VK_FORMAT_UNDEFINED
|
||||||
|
// DxvkContext::copyImageToBuffer will automatically take the format from the image
|
||||||
VkFormat packedFormat = GetPackedDepthStencilFormat(desc.Format);
|
VkFormat packedFormat = GetPackedDepthStencilFormat(desc.Format);
|
||||||
|
|
||||||
EmitCs([
|
EmitCs([
|
||||||
@ -4780,6 +4827,7 @@ namespace dxvk {
|
|||||||
TrackTextureMappingBufferSequenceNumber(pResource, Subresource);
|
TrackTextureMappingBufferSequenceNumber(pResource, Subresource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait until the buffer is idle which may include the copy (and resolve) we just issued.
|
||||||
if (!WaitForResource(*mappedBuffer, pResource->GetMappingBufferSequenceNumber(Subresource), Flags))
|
if (!WaitForResource(*mappedBuffer, pResource->GetMappingBufferSequenceNumber(Subresource), Flags))
|
||||||
return D3DERR_WASSTILLDRAWING;
|
return D3DERR_WASSTILLDRAWING;
|
||||||
}
|
}
|
||||||
@ -4787,7 +4835,8 @@ namespace dxvk {
|
|||||||
const bool atiHack = desc.Format == D3D9Format::ATI1 || desc.Format == D3D9Format::ATI2;
|
const bool atiHack = desc.Format == D3D9Format::ATI1 || desc.Format == D3D9Format::ATI2;
|
||||||
// Set up map pointer.
|
// Set up map pointer.
|
||||||
if (atiHack) {
|
if (atiHack) {
|
||||||
// We need to lie here. The game is expected to use this info and do a workaround.
|
// The API didn't treat this as a block compressed format here.
|
||||||
|
// So we need to lie here. The game is expected to use this info and do a workaround.
|
||||||
// It's stupid. I know.
|
// It's stupid. I know.
|
||||||
pLockedBox->RowPitch = align(std::max(desc.Width >> MipLevel, 1u), 4);
|
pLockedBox->RowPitch = align(std::max(desc.Width >> MipLevel, 1u), 4);
|
||||||
pLockedBox->SlicePitch = pLockedBox->RowPitch * std::max(desc.Height >> MipLevel, 1u);
|
pLockedBox->SlicePitch = pLockedBox->RowPitch * std::max(desc.Height >> MipLevel, 1u);
|
||||||
@ -4806,6 +4855,7 @@ namespace dxvk {
|
|||||||
|
|
||||||
pResource->SetLocked(Subresource, true);
|
pResource->SetLocked(Subresource, true);
|
||||||
|
|
||||||
|
// Make sure the amount of mapped texture memory stays below the threshold.
|
||||||
UnmapTextures();
|
UnmapTextures();
|
||||||
|
|
||||||
const bool readOnly = Flags & D3DLOCK_READONLY;
|
const bool readOnly = Flags & D3DLOCK_READONLY;
|
||||||
@ -4826,6 +4876,7 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (IsPoolManaged(desc.Pool) && !readOnly) {
|
if (IsPoolManaged(desc.Pool) && !readOnly) {
|
||||||
|
// Managed textures are uploaded at draw time.
|
||||||
pResource->SetNeedsUpload(Subresource, true);
|
pResource->SetNeedsUpload(Subresource, true);
|
||||||
|
|
||||||
for (uint32_t i : bit::BitMask(m_activeTextures)) {
|
for (uint32_t i : bit::BitMask(m_activeTextures)) {
|
||||||
@ -4908,6 +4959,7 @@ namespace dxvk {
|
|||||||
|
|
||||||
const D3DBOX& box = pResource->GetDirtyBox(subresource.arrayLayer);
|
const D3DBOX& box = pResource->GetDirtyBox(subresource.arrayLayer);
|
||||||
|
|
||||||
|
// The dirty box is only tracked for mip 0. Scale it for the mip level we're gonna upload.
|
||||||
VkExtent3D mip0Extent = { box.Right - box.Left, box.Bottom - box.Top, box.Back - box.Front };
|
VkExtent3D mip0Extent = { box.Right - box.Left, box.Bottom - box.Top, box.Back - box.Front };
|
||||||
VkExtent3D extent = util::computeMipLevelExtent(mip0Extent, subresource.mipLevel);
|
VkExtent3D extent = util::computeMipLevelExtent(mip0Extent, subresource.mipLevel);
|
||||||
VkOffset3D mip0Offset = { int32_t(box.Left), int32_t(box.Top), int32_t(box.Front) };
|
VkOffset3D mip0Offset = { int32_t(box.Left), int32_t(box.Top), int32_t(box.Front) };
|
||||||
@ -4929,6 +4981,8 @@ namespace dxvk {
|
|||||||
VkOffset3D SrcOffset,
|
VkOffset3D SrcOffset,
|
||||||
VkExtent3D SrcExtent,
|
VkExtent3D SrcExtent,
|
||||||
VkOffset3D DestOffset) {
|
VkOffset3D DestOffset) {
|
||||||
|
// Wait until the amount of used staging memory is under a certain threshold to avoid using
|
||||||
|
// too much memory and even more so to avoid using too much address space.
|
||||||
WaitStagingBuffer();
|
WaitStagingBuffer();
|
||||||
|
|
||||||
const Rc<DxvkImage> image = pDestTexture->GetImage();
|
const Rc<DxvkImage> image = pDestTexture->GetImage();
|
||||||
@ -4959,6 +5013,9 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (likely(convertFormat.FormatType == D3D9ConversionFormat_None)) {
|
if (likely(convertFormat.FormatType == D3D9ConversionFormat_None)) {
|
||||||
|
// The texture does not use a format that needs to be converted in a compute shader.
|
||||||
|
// So we just need to make sure the passed size and offset are not out of range and properly aligned,
|
||||||
|
// copy the data to a staging buffer and then copy that on the GPU to the actual image.
|
||||||
VkOffset3D alignedDestOffset = {
|
VkOffset3D alignedDestOffset = {
|
||||||
int32_t(alignDown(DestOffset.x, formatInfo->blockSize.width)),
|
int32_t(alignDown(DestOffset.x, formatInfo->blockSize.width)),
|
||||||
int32_t(alignDown(DestOffset.y, formatInfo->blockSize.height)),
|
int32_t(alignDown(DestOffset.y, formatInfo->blockSize.height)),
|
||||||
@ -4985,6 +5042,8 @@ namespace dxvk {
|
|||||||
+ srcOffsetBlockCount.y * pitch
|
+ srcOffsetBlockCount.y * pitch
|
||||||
+ srcOffsetBlockCount.x * formatInfo->elementSize;
|
+ srcOffsetBlockCount.x * formatInfo->elementSize;
|
||||||
|
|
||||||
|
// Get the mapping pointer from MapTexture to map the texture and keep track of that
|
||||||
|
// in case it is unmappable.
|
||||||
const void* mapPtr = MapTexture(pSrcTexture, SrcSubresource);
|
const void* mapPtr = MapTexture(pSrcTexture, SrcSubresource);
|
||||||
VkDeviceSize dirtySize = extentBlockCount.width * extentBlockCount.height * extentBlockCount.depth * formatInfo->elementSize;
|
VkDeviceSize dirtySize = extentBlockCount.width * extentBlockCount.height * extentBlockCount.depth * formatInfo->elementSize;
|
||||||
D3D9BufferSlice slice = AllocStagingBuffer(dirtySize);
|
D3D9BufferSlice slice = AllocStagingBuffer(dirtySize);
|
||||||
@ -5013,8 +5072,10 @@ namespace dxvk {
|
|||||||
TrackTextureMappingBufferSequenceNumber(pSrcTexture, SrcSubresource);
|
TrackTextureMappingBufferSequenceNumber(pSrcTexture, SrcSubresource);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// The texture uses a format which gets converted by a compute shader.
|
||||||
const void* mapPtr = MapTexture(pSrcTexture, SrcSubresource);
|
const void* mapPtr = MapTexture(pSrcTexture, SrcSubresource);
|
||||||
|
|
||||||
|
// The compute shader does not support only converting a subrect of the texture
|
||||||
if (unlikely(SrcOffset.x != 0 || SrcOffset.y != 0 || SrcOffset.z != 0
|
if (unlikely(SrcOffset.x != 0 || SrcOffset.y != 0 || SrcOffset.z != 0
|
||||||
|| DestOffset.x != 0 || DestOffset.y != 0 || DestOffset.z != 0
|
|| DestOffset.x != 0 || DestOffset.y != 0 || DestOffset.z != 0
|
||||||
|| SrcExtent != srcTexLevelExtent)) {
|
|| SrcExtent != srcTexLevelExtent)) {
|
||||||
@ -5141,14 +5202,17 @@ namespace dxvk {
|
|||||||
const bool directMapping = pResource->GetMapMode() == D3D9_COMMON_BUFFER_MAP_MODE_DIRECT;
|
const bool directMapping = pResource->GetMapMode() == D3D9_COMMON_BUFFER_MAP_MODE_DIRECT;
|
||||||
const bool needsReadback = pResource->NeedsReadback();
|
const bool needsReadback = pResource->NeedsReadback();
|
||||||
|
|
||||||
Rc<DxvkBuffer> mappingBuffer = pResource->GetBuffer<D3D9_COMMON_BUFFER_TYPE_MAPPING>();
|
|
||||||
|
|
||||||
uint8_t* data = nullptr;
|
uint8_t* data = nullptr;
|
||||||
|
|
||||||
if ((Flags & D3DLOCK_DISCARD) && (directMapping || needsReadback)) {
|
if ((Flags & D3DLOCK_DISCARD) && (directMapping || needsReadback)) {
|
||||||
|
// If we're not directly mapped and don't need readback,
|
||||||
|
// the buffer is not currently getting used anyway
|
||||||
|
// so there's no reason to waste memory by discarding.
|
||||||
|
|
||||||
// Allocate a new backing slice for the buffer and set
|
// Allocate a new backing slice for the buffer and set
|
||||||
// it as the 'new' mapped slice. This assumes that the
|
// it as the 'new' mapped slice. This assumes that the
|
||||||
// only way to invalidate a buffer is by mapping it.
|
// only way to invalidate a buffer is by mapping it.
|
||||||
|
Rc<DxvkBuffer> mappingBuffer = pResource->GetBuffer<D3D9_COMMON_BUFFER_TYPE_MAPPING>();
|
||||||
auto bufferSlice = pResource->DiscardMapSlice();
|
auto bufferSlice = pResource->DiscardMapSlice();
|
||||||
data = reinterpret_cast<uint8_t*>(bufferSlice->mapPtr());
|
data = reinterpret_cast<uint8_t*>(bufferSlice->mapPtr());
|
||||||
|
|
||||||
@ -5162,17 +5226,21 @@ namespace dxvk {
|
|||||||
pResource->SetNeedsReadback(false);
|
pResource->SetNeedsReadback(false);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// The application either didn't specify DISCARD or the buffer is guaranteed to be idle anyway.
|
||||||
|
|
||||||
// Use map pointer from previous map operation. This
|
// Use map pointer from previous map operation. This
|
||||||
// way we don't have to synchronize with the CS thread
|
// way we don't have to synchronize with the CS thread
|
||||||
// if the map mode is D3DLOCK_NOOVERWRITE.
|
// if the map mode is D3DLOCK_NOOVERWRITE.
|
||||||
data = reinterpret_cast<uint8_t*>(pResource->GetMappedSlice()->mapPtr());
|
data = reinterpret_cast<uint8_t*>(pResource->GetMappedSlice()->mapPtr());
|
||||||
|
|
||||||
const bool needsReadback = pResource->NeedsReadback();
|
|
||||||
const bool readOnly = Flags & D3DLOCK_READONLY;
|
const bool readOnly = Flags & D3DLOCK_READONLY;
|
||||||
// NOOVERWRITE promises that they will not write in a currently used area.
|
// NOOVERWRITE promises that they will not write in a currently used area.
|
||||||
const bool noOverwrite = Flags & D3DLOCK_NOOVERWRITE;
|
const bool noOverwrite = Flags & D3DLOCK_NOOVERWRITE;
|
||||||
const bool directMapping = pResource->GetMapMode() == D3D9_COMMON_BUFFER_MAP_MODE_DIRECT;
|
const bool directMapping = pResource->GetMapMode() == D3D9_COMMON_BUFFER_MAP_MODE_DIRECT;
|
||||||
|
|
||||||
|
// If we're not directly mapped, we can rely on needsReadback to tell us if a sync is required.
|
||||||
const bool skipWait = (!needsReadback && (readOnly || !directMapping)) || noOverwrite;
|
const bool skipWait = (!needsReadback && (readOnly || !directMapping)) || noOverwrite;
|
||||||
|
|
||||||
if (!skipWait) {
|
if (!skipWait) {
|
||||||
const Rc<DxvkBuffer> mappingBuffer = pResource->GetBuffer<D3D9_COMMON_BUFFER_TYPE_MAPPING>();
|
const Rc<DxvkBuffer> mappingBuffer = pResource->GetBuffer<D3D9_COMMON_BUFFER_TYPE_MAPPING>();
|
||||||
if (!WaitForResource(*mappingBuffer, pResource->GetMappingBufferSequenceNumber(), Flags))
|
if (!WaitForResource(*mappingBuffer, pResource->GetMappingBufferSequenceNumber(), Flags))
|
||||||
@ -5184,7 +5252,6 @@ namespace dxvk {
|
|||||||
|
|
||||||
// The offset/size is not clamped to or affected by the desc size.
|
// The offset/size is not clamped to or affected by the desc size.
|
||||||
data += OffsetToLock;
|
data += OffsetToLock;
|
||||||
|
|
||||||
*ppbData = reinterpret_cast<void*>(data);
|
*ppbData = reinterpret_cast<void*>(data);
|
||||||
|
|
||||||
DWORD oldFlags = pResource->GetMapFlags();
|
DWORD oldFlags = pResource->GetMapFlags();
|
||||||
@ -5197,13 +5264,18 @@ namespace dxvk {
|
|||||||
pResource->SetMapFlags(Flags | oldFlags);
|
pResource->SetMapFlags(Flags | oldFlags);
|
||||||
pResource->IncrementLockCount();
|
pResource->IncrementLockCount();
|
||||||
|
|
||||||
|
// We just mapped a buffer which may have come with an address space cost.
|
||||||
|
// Unmap textures if the amount of mapped texture memory is exceeding the threshold.
|
||||||
UnmapTextures();
|
UnmapTextures();
|
||||||
|
|
||||||
return D3D_OK;
|
return D3D_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HRESULT D3D9DeviceEx::FlushBuffer(
|
HRESULT D3D9DeviceEx::FlushBuffer(
|
||||||
D3D9CommonBuffer* pResource) {
|
D3D9CommonBuffer* pResource) {
|
||||||
|
// Wait until the amount of used staging memory is under a certain threshold to avoid using
|
||||||
|
// too much memory and even more so to avoid using too much address space.
|
||||||
WaitStagingBuffer();
|
WaitStagingBuffer();
|
||||||
|
|
||||||
auto dstBuffer = pResource->GetBufferSlice<D3D9_COMMON_BUFFER_TYPE_REAL>();
|
auto dstBuffer = pResource->GetBufferSlice<D3D9_COMMON_BUFFER_TYPE_REAL>();
|
||||||
@ -5245,14 +5317,19 @@ namespace dxvk {
|
|||||||
if (pResource->DecrementLockCount() != 0)
|
if (pResource->DecrementLockCount() != 0)
|
||||||
return D3D_OK;
|
return D3D_OK;
|
||||||
|
|
||||||
|
// Nothing else to do for directly mapped buffers. Those were already written.
|
||||||
if (pResource->GetMapMode() != D3D9_COMMON_BUFFER_MAP_MODE_BUFFER)
|
if (pResource->GetMapMode() != D3D9_COMMON_BUFFER_MAP_MODE_BUFFER)
|
||||||
return D3D_OK;
|
return D3D_OK;
|
||||||
|
|
||||||
|
// There is no part of the buffer that hasn't been uploaded yet.
|
||||||
|
// This shouldn't happen.
|
||||||
if (pResource->DirtyRange().IsDegenerate())
|
if (pResource->DirtyRange().IsDegenerate())
|
||||||
return D3D_OK;
|
return D3D_OK;
|
||||||
|
|
||||||
pResource->SetMapFlags(0);
|
pResource->SetMapFlags(0);
|
||||||
|
|
||||||
|
// Only D3DPOOL_DEFAULT buffers get uploaded in UnlockBuffer.
|
||||||
|
// D3DPOOL_SYSTEMMEM and D3DPOOL_MANAGED get uploaded at draw time.
|
||||||
if (pResource->Desc()->Pool != D3DPOOL_DEFAULT)
|
if (pResource->Desc()->Pool != D3DPOOL_DEFAULT)
|
||||||
return D3D_OK;
|
return D3D_OK;
|
||||||
|
|
||||||
@ -5613,6 +5690,7 @@ namespace dxvk {
|
|||||||
? sizeof(D3D9FixedFunctionVertexBlendDataSW)
|
? sizeof(D3D9FixedFunctionVertexBlendDataSW)
|
||||||
: sizeof(D3D9FixedFunctionVertexBlendDataHW));
|
: sizeof(D3D9FixedFunctionVertexBlendDataHW));
|
||||||
|
|
||||||
|
// Allocate constant buffer for values that would otherwise get passed as spec constants for fast-linked pipelines to use.
|
||||||
if (m_usingGraphicsPipelines) {
|
if (m_usingGraphicsPipelines) {
|
||||||
m_specBuffer = D3D9ConstantBuffer(this,
|
m_specBuffer = D3D9ConstantBuffer(this,
|
||||||
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
||||||
@ -5640,11 +5718,15 @@ namespace dxvk {
|
|||||||
|
|
||||||
uint32_t floatCount = m_vsFloatConstsCount;
|
uint32_t floatCount = m_vsFloatConstsCount;
|
||||||
if (constSet.meta.needsConstantCopies) {
|
if (constSet.meta.needsConstantCopies) {
|
||||||
|
// If the shader requires us to preserve shader defined constants,
|
||||||
|
// we copy those over. We need to adjust the amount of used floats accordingly.
|
||||||
auto shader = GetCommonShader(m_state.vertexShader);
|
auto shader = GetCommonShader(m_state.vertexShader);
|
||||||
floatCount = std::max(floatCount, shader->GetMaxDefinedConstant() + 1);
|
floatCount = std::max(floatCount, shader->GetMaxDefinedConstant() + 1);
|
||||||
}
|
}
|
||||||
|
// If we statically know which is the last float constant accessed by the shader, we don't need to copy the rest.
|
||||||
floatCount = std::min(floatCount, constSet.meta.maxConstIndexF);
|
floatCount = std::min(floatCount, constSet.meta.maxConstIndexF);
|
||||||
|
|
||||||
|
// Calculate data sizes for each constant type.
|
||||||
const uint32_t floatDataSize = floatCount * sizeof(Vector4);
|
const uint32_t floatDataSize = floatCount * sizeof(Vector4);
|
||||||
const uint32_t intDataSize = std::min(constSet.meta.maxConstIndexI, m_vsIntConstsCount) * sizeof(Vector4i);
|
const uint32_t intDataSize = std::min(constSet.meta.maxConstIndexI, m_vsIntConstsCount) * sizeof(Vector4i);
|
||||||
const uint32_t boolDataSize = divCeil(std::min(constSet.meta.maxConstIndexB, m_vsBoolConstsCount), 32u) * uint32_t(sizeof(uint32_t));
|
const uint32_t boolDataSize = divCeil(std::min(constSet.meta.maxConstIndexB, m_vsBoolConstsCount), 32u) * uint32_t(sizeof(uint32_t));
|
||||||
@ -5655,6 +5737,8 @@ namespace dxvk {
|
|||||||
auto mapPtr = CopySoftwareConstants(constSet.buffer, Src.fConsts, floatDataSize);
|
auto mapPtr = CopySoftwareConstants(constSet.buffer, Src.fConsts, floatDataSize);
|
||||||
|
|
||||||
if (constSet.meta.needsConstantCopies) {
|
if (constSet.meta.needsConstantCopies) {
|
||||||
|
// Copy shader defined constants over so they can be accessed
|
||||||
|
// with relative addressing.
|
||||||
Vector4* data = reinterpret_cast<Vector4*>(mapPtr);
|
Vector4* data = reinterpret_cast<Vector4*>(mapPtr);
|
||||||
|
|
||||||
auto& shaderConsts = GetCommonShader(m_state.vertexShader)->GetConstants();
|
auto& shaderConsts = GetCommonShader(m_state.vertexShader)->GetConstants();
|
||||||
@ -5702,14 +5786,19 @@ namespace dxvk {
|
|||||||
|
|
||||||
uint32_t floatCount = ShaderStage == DxsoProgramType::VertexShader ? m_vsFloatConstsCount : m_psFloatConstsCount;
|
uint32_t floatCount = ShaderStage == DxsoProgramType::VertexShader ? m_vsFloatConstsCount : m_psFloatConstsCount;
|
||||||
if (constSet.meta.needsConstantCopies) {
|
if (constSet.meta.needsConstantCopies) {
|
||||||
|
// If the shader requires us to preserve shader defined constants,
|
||||||
|
// we copy those over. We need to adjust the amount of used floats accordingly.
|
||||||
auto shader = GetCommonShader(Shader);
|
auto shader = GetCommonShader(Shader);
|
||||||
floatCount = std::max(floatCount, shader->GetMaxDefinedConstant() + 1);
|
floatCount = std::max(floatCount, shader->GetMaxDefinedConstant() + 1);
|
||||||
}
|
}
|
||||||
|
// If we statically know which is the last float constant accessed by the shader, we don't need to copy the rest.
|
||||||
floatCount = std::min(constSet.meta.maxConstIndexF, floatCount);
|
floatCount = std::min(constSet.meta.maxConstIndexF, floatCount);
|
||||||
|
|
||||||
|
// There are very few int constants, so we put those into the same buffer at the start.
|
||||||
|
// We always allocate memory for all possible int constants to make sure alignment works out.
|
||||||
const uint32_t intRange = caps::MaxOtherConstants * sizeof(Vector4i);
|
const uint32_t intRange = caps::MaxOtherConstants * sizeof(Vector4i);
|
||||||
const uint32_t intDataSize = constSet.meta.maxConstIndexI * sizeof(Vector4i);
|
|
||||||
uint32_t floatDataSize = floatCount * sizeof(Vector4);
|
uint32_t floatDataSize = floatCount * sizeof(Vector4);
|
||||||
|
// Determine amount of floats and buffer size based on highest used float constant and alignment
|
||||||
const uint32_t alignment = constSet.buffer.GetAlignment();
|
const uint32_t alignment = constSet.buffer.GetAlignment();
|
||||||
const uint32_t bufferSize = align(std::max(floatDataSize + intRange, alignment), alignment);
|
const uint32_t bufferSize = align(std::max(floatDataSize + intRange, alignment), alignment);
|
||||||
floatDataSize = bufferSize - intRange;
|
floatDataSize = bufferSize - intRange;
|
||||||
@ -5717,12 +5806,15 @@ namespace dxvk {
|
|||||||
void* mapPtr = constSet.buffer.Alloc(bufferSize);
|
void* mapPtr = constSet.buffer.Alloc(bufferSize);
|
||||||
auto* dst = reinterpret_cast<HardwareLayoutType*>(mapPtr);
|
auto* dst = reinterpret_cast<HardwareLayoutType*>(mapPtr);
|
||||||
|
|
||||||
|
const uint32_t intDataSize = constSet.meta.maxConstIndexI * sizeof(Vector4i);
|
||||||
if (constSet.meta.maxConstIndexI != 0)
|
if (constSet.meta.maxConstIndexI != 0)
|
||||||
std::memcpy(dst->iConsts, Src.iConsts, intDataSize);
|
std::memcpy(dst->iConsts, Src.iConsts, intDataSize);
|
||||||
if (constSet.meta.maxConstIndexF != 0)
|
if (constSet.meta.maxConstIndexF != 0)
|
||||||
std::memcpy(dst->fConsts, Src.fConsts, floatDataSize);
|
std::memcpy(dst->fConsts, Src.fConsts, floatDataSize);
|
||||||
|
|
||||||
if (constSet.meta.needsConstantCopies) {
|
if (constSet.meta.needsConstantCopies) {
|
||||||
|
// Copy shader defined constants over so they can be accessed
|
||||||
|
// with relative addressing.
|
||||||
Vector4* data = reinterpret_cast<Vector4*>(dst->fConsts);
|
Vector4* data = reinterpret_cast<Vector4*>(dst->fConsts);
|
||||||
|
|
||||||
auto& shaderConsts = GetCommonShader(Shader)->GetConstants();
|
auto& shaderConsts = GetCommonShader(Shader)->GetConstants();
|
||||||
@ -6549,6 +6641,9 @@ namespace dxvk {
|
|||||||
if (i != 0)
|
if (i != 0)
|
||||||
mode.writeMask = cWriteMasks[i - 1];
|
mode.writeMask = cWriteMasks[i - 1];
|
||||||
|
|
||||||
|
// Adjust the blend factor based on the render target alpha swizzle bit mask.
|
||||||
|
// Specific formats such as the XRGB ones require a ONE swizzle for alpha
|
||||||
|
// which cannot be directly applied with the image view of the attachment.
|
||||||
const bool alphaSwizzle = cAlphaMasks & (1 << i);
|
const bool alphaSwizzle = cAlphaMasks & (1 << i);
|
||||||
|
|
||||||
auto NormalizeFactor = [alphaSwizzle](VkBlendFactor Factor) {
|
auto NormalizeFactor = [alphaSwizzle](VkBlendFactor Factor) {
|
||||||
@ -8405,6 +8500,7 @@ namespace dxvk {
|
|||||||
ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, i, cSpecInfo.data[i]);
|
ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, i, cSpecInfo.data[i]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Write spec constants into buffer for fast-linked pipelines to use it.
|
||||||
if (m_usingGraphicsPipelines) {
|
if (m_usingGraphicsPipelines) {
|
||||||
// TODO: Make uploading specialization information less naive.
|
// TODO: Make uploading specialization information less naive.
|
||||||
auto mapPtr = m_specBuffer.AllocSlice();
|
auto mapPtr = m_specBuffer.AllocSlice();
|
||||||
|
@ -673,6 +673,9 @@ namespace dxvk {
|
|||||||
|
|
||||||
static DxvkDeviceFeatures GetDeviceFeatures(const Rc<DxvkAdapter>& adapter);
|
static DxvkDeviceFeatures GetDeviceFeatures(const Rc<DxvkAdapter>& adapter);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Returns whether the Vulkan device supports the required features for ProcessVertices
|
||||||
|
*/
|
||||||
bool SupportsSWVP();
|
bool SupportsSWVP();
|
||||||
|
|
||||||
bool IsExtended();
|
bool IsExtended();
|
||||||
@ -729,10 +732,17 @@ namespace dxvk {
|
|||||||
UINT Face,
|
UINT Face,
|
||||||
UINT MipLevel);
|
UINT MipLevel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Uploads the given texture subresource from its local system memory copy.
|
||||||
|
*/
|
||||||
HRESULT FlushImage(
|
HRESULT FlushImage(
|
||||||
D3D9CommonTexture* pResource,
|
D3D9CommonTexture* pResource,
|
||||||
UINT Subresource);
|
UINT Subresource);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Copies the given part of a texture from the local system memory copy of the source texture
|
||||||
|
* to the image of the destination texture.
|
||||||
|
*/
|
||||||
void UpdateTextureFromBuffer(
|
void UpdateTextureFromBuffer(
|
||||||
D3D9CommonTexture* pDestTexture,
|
D3D9CommonTexture* pDestTexture,
|
||||||
D3D9CommonTexture* pSrcTexture,
|
D3D9CommonTexture* pSrcTexture,
|
||||||
@ -752,6 +762,9 @@ namespace dxvk {
|
|||||||
void** ppbData,
|
void** ppbData,
|
||||||
DWORD Flags);
|
DWORD Flags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Uploads the given buffer from its local system memory copy.
|
||||||
|
*/
|
||||||
HRESULT FlushBuffer(
|
HRESULT FlushBuffer(
|
||||||
D3D9CommonBuffer* pResource);
|
D3D9CommonBuffer* pResource);
|
||||||
|
|
||||||
@ -877,9 +890,21 @@ namespace dxvk {
|
|||||||
|
|
||||||
void UpdateClipPlanes();
|
void UpdateClipPlanes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Updates the push constant data at the given offset with data from the specified pointer.
|
||||||
|
*
|
||||||
|
* \param Offset Offset at which the push constant data gets written.
|
||||||
|
* \param Length Length of the push constant data to write.
|
||||||
|
* \param pData Push constant data
|
||||||
|
*/
|
||||||
template <uint32_t Offset, uint32_t Length>
|
template <uint32_t Offset, uint32_t Length>
|
||||||
void UpdatePushConstant(const void* pData);
|
void UpdatePushConstant(const void* pData);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Updates the specified push constant based on the device state.
|
||||||
|
*
|
||||||
|
* \param Item Render state push constant to update
|
||||||
|
*/
|
||||||
template <D3D9RenderStateItem Item>
|
template <D3D9RenderStateItem Item>
|
||||||
void UpdatePushConstant();
|
void UpdatePushConstant();
|
||||||
|
|
||||||
@ -971,12 +996,28 @@ namespace dxvk {
|
|||||||
|
|
||||||
HRESULT InitialReset(D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode);
|
HRESULT InitialReset(D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Returns the allocator used for unmappable system memory texture data
|
||||||
|
*/
|
||||||
D3D9MemoryAllocator* GetAllocator() {
|
D3D9MemoryAllocator* GetAllocator() {
|
||||||
return &m_memoryAllocator;
|
return &m_memoryAllocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Gets the pointer of the system memory copy of the texture
|
||||||
|
*
|
||||||
|
* Also tracks the texture if it is unmappable.
|
||||||
|
*/
|
||||||
void* MapTexture(D3D9CommonTexture* pTexture, UINT Subresource);
|
void* MapTexture(D3D9CommonTexture* pTexture, UINT Subresource);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Moves the texture to the front of the LRU list of mapped textures
|
||||||
|
*/
|
||||||
void TouchMappedTexture(D3D9CommonTexture* pTexture);
|
void TouchMappedTexture(D3D9CommonTexture* pTexture);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Removes the texture from the LRU list of mapped textures
|
||||||
|
*/
|
||||||
void RemoveMappedTexture(D3D9CommonTexture* pTexture);
|
void RemoveMappedTexture(D3D9CommonTexture* pTexture);
|
||||||
|
|
||||||
bool IsD3D8Compatible() const {
|
bool IsD3D8Compatible() const {
|
||||||
@ -998,34 +1039,59 @@ namespace dxvk {
|
|||||||
void NotifyFullscreen(HWND window, bool fullscreen);
|
void NotifyFullscreen(HWND window, bool fullscreen);
|
||||||
void NotifyWindowActivated(HWND window, bool activated);
|
void NotifyWindowActivated(HWND window, bool activated);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Increases the amount of D3DPOOL_DEFAULT resources that block a device reset
|
||||||
|
*/
|
||||||
void IncrementLosableCounter() {
|
void IncrementLosableCounter() {
|
||||||
m_losableResourceCounter++;
|
m_losableResourceCounter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Decreases the amount of D3DPOOL_DEFAULT resources that block a device reset
|
||||||
|
*/
|
||||||
void DecrementLosableCounter() {
|
void DecrementLosableCounter() {
|
||||||
m_losableResourceCounter--;
|
m_losableResourceCounter--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Returns whether the device is configured to only support vertex processing.
|
||||||
|
*/
|
||||||
bool CanOnlySWVP() const {
|
bool CanOnlySWVP() const {
|
||||||
return m_behaviorFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING;
|
return m_behaviorFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Returns whether the device can be set to do software vertex processing.
|
||||||
|
* It may also be set up to only support software vertex processing.
|
||||||
|
*/
|
||||||
bool CanSWVP() const {
|
bool CanSWVP() const {
|
||||||
return m_behaviorFlags & (D3DCREATE_MIXED_VERTEXPROCESSING | D3DCREATE_SOFTWARE_VERTEXPROCESSING);
|
return m_behaviorFlags & (D3DCREATE_MIXED_VERTEXPROCESSING | D3DCREATE_SOFTWARE_VERTEXPROCESSING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Returns whether or not the device is currently set to do software vertex processing.
|
||||||
|
*/
|
||||||
bool IsSWVP() const {
|
bool IsSWVP() const {
|
||||||
return m_isSWVP;
|
return m_isSWVP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Returns the number of vertex shader modules generated for fixed function state.
|
||||||
|
*/
|
||||||
UINT GetFixedFunctionVSCount() const {
|
UINT GetFixedFunctionVSCount() const {
|
||||||
return m_ffModules.GetVSCount();
|
return m_ffModules.GetVSCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Returns the number of fragment shader modules generated for fixed function state.
|
||||||
|
*/
|
||||||
UINT GetFixedFunctionFSCount() const {
|
UINT GetFixedFunctionFSCount() const {
|
||||||
return m_ffModules.GetFSCount();
|
return m_ffModules.GetFSCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Returns the number of shader modules generated for ProcessVertices.
|
||||||
|
*/
|
||||||
UINT GetSWVPShaderCount() const {
|
UINT GetSWVPShaderCount() const {
|
||||||
return m_swvpEmulator.GetShaderCount();
|
return m_swvpEmulator.GetShaderCount();
|
||||||
}
|
}
|
||||||
@ -1072,7 +1138,11 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Device Reset detection for D3D9SwapChainEx::Present
|
/**
|
||||||
|
* \brief Returns whether the device has been reset and marks it as true.
|
||||||
|
* Used for the deferred surface creation workaround.
|
||||||
|
* (Device Reset detection for D3D9SwapChainEx::Present)
|
||||||
|
*/
|
||||||
bool IsDeviceReset() {
|
bool IsDeviceReset() {
|
||||||
return std::exchange(m_deviceHasBeenReset, false);
|
return std::exchange(m_deviceHasBeenReset, false);
|
||||||
}
|
}
|
||||||
@ -1082,13 +1152,25 @@ namespace dxvk {
|
|||||||
|
|
||||||
void DetermineConstantLayouts(bool canSWVP);
|
void DetermineConstantLayouts(bool canSWVP);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Allocates buffer memory for DrawPrimitiveUp draws
|
||||||
|
*/
|
||||||
D3D9BufferSlice AllocUPBuffer(VkDeviceSize size);
|
D3D9BufferSlice AllocUPBuffer(VkDeviceSize size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Allocates buffer memory for resource uploads
|
||||||
|
*/
|
||||||
D3D9BufferSlice AllocStagingBuffer(VkDeviceSize size);
|
D3D9BufferSlice AllocStagingBuffer(VkDeviceSize size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Waits until the amount of used staging memory is below a certain threshold.
|
||||||
|
*/
|
||||||
void WaitStagingBuffer();
|
void WaitStagingBuffer();
|
||||||
|
|
||||||
bool ShouldRecord();
|
/**
|
||||||
|
* \brief Returns whether the device is currently recording a StateBlock
|
||||||
|
*/
|
||||||
|
inline bool ShouldRecord();
|
||||||
|
|
||||||
HRESULT CreateShaderModule(
|
HRESULT CreateShaderModule(
|
||||||
D3D9CommonShader* pShaderModule,
|
D3D9CommonShader* pShaderModule,
|
||||||
@ -1105,6 +1187,9 @@ namespace dxvk {
|
|||||||
return (vertexCount - 1) * stride + std::max(m_state.vertexDecl->GetSize(0), stride);
|
return (vertexCount - 1) * stride + std::max(m_state.vertexDecl->GetSize(0), stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Writes data to the given pointer and zeroes any access buffer space
|
||||||
|
*/
|
||||||
inline void FillUPVertexBuffer(void* buffer, const void* userData, uint32_t dataSize, uint32_t bufferSize) {
|
inline void FillUPVertexBuffer(void* buffer, const void* userData, uint32_t dataSize, uint32_t bufferSize) {
|
||||||
uint8_t* data = reinterpret_cast<uint8_t*>(buffer);
|
uint8_t* data = reinterpret_cast<uint8_t*>(buffer);
|
||||||
// Don't copy excess data if we don't end up needing it.
|
// Don't copy excess data if we don't end up needing it.
|
||||||
@ -1256,25 +1341,24 @@ namespace dxvk {
|
|||||||
D3D9CommonTexture* pResource,
|
D3D9CommonTexture* pResource,
|
||||||
UINT Subresource);
|
UINT Subresource);
|
||||||
|
|
||||||
void UnmapTextures();
|
|
||||||
|
|
||||||
uint64_t GetCurrentSequenceNumber();
|
uint64_t GetCurrentSequenceNumber();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the swapchain that was used the most recently for presenting
|
* \brief Will unmap the least recently used textures if the amount of mapped texture memory exceeds a threshold.
|
||||||
|
*/
|
||||||
|
void UnmapTextures();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the swapchain that was used the most recently for presenting
|
||||||
* Has to be externally synchronized.
|
* Has to be externally synchronized.
|
||||||
*
|
|
||||||
* @return D3D9SwapChainEx* Swapchain
|
|
||||||
*/
|
*/
|
||||||
D3D9SwapChainEx* GetMostRecentlyUsedSwapchain() {
|
D3D9SwapChainEx* GetMostRecentlyUsedSwapchain() {
|
||||||
return m_mostRecentlyUsedSwapchain;
|
return m_mostRecentlyUsedSwapchain;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the swapchain that was used the most recently for presenting
|
* \brief Set the swapchain that was used the most recently for presenting
|
||||||
* Has to be externally synchronized.
|
* Has to be externally synchronized.
|
||||||
*
|
|
||||||
* @param swapchain Swapchain
|
|
||||||
*/
|
*/
|
||||||
void SetMostRecentlyUsedSwapchain(D3D9SwapChainEx* swapchain) {
|
void SetMostRecentlyUsedSwapchain(D3D9SwapChainEx* swapchain) {
|
||||||
m_mostRecentlyUsedSwapchain = swapchain;
|
m_mostRecentlyUsedSwapchain = swapchain;
|
||||||
|
@ -861,14 +861,17 @@ namespace dxvk {
|
|||||||
DxsoRegisterValue DxsoCompiler::emitLoadConstant(
|
DxsoRegisterValue DxsoCompiler::emitLoadConstant(
|
||||||
const DxsoBaseRegister& reg,
|
const DxsoBaseRegister& reg,
|
||||||
const DxsoBaseRegister* relative) {
|
const DxsoBaseRegister* relative) {
|
||||||
// struct cBuffer_t {
|
|
||||||
|
// SWVP cbuffers: Member Binding index
|
||||||
|
// float f[8192]; 0
|
||||||
|
// int32_t i[2048]; 1
|
||||||
|
// bool (uint32_t bitmask) i[[256]]; 2
|
||||||
|
|
||||||
|
// HWVP cbuffer: Member Member index
|
||||||
|
// int32_t i[16]; 0
|
||||||
|
// float f[256 or 224]; 1
|
||||||
//
|
//
|
||||||
// Type Member Index
|
// bools as spec constant bitmasks
|
||||||
//
|
|
||||||
// float f[256 or 224]; 0
|
|
||||||
// int32_t i[16]; 1
|
|
||||||
// uint32_t boolBitmask; 2
|
|
||||||
// }
|
|
||||||
DxsoRegisterValue result = { };
|
DxsoRegisterValue result = { };
|
||||||
|
|
||||||
switch (reg.id.type) {
|
switch (reg.id.type) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user