mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-01-18 20:52:10 +01:00
[d3d11] Use EmitCs for buffer mapping
This commit is contained in:
parent
f25b3c8b32
commit
aaf7b05625
@ -11,7 +11,8 @@ namespace dxvk {
|
||||
const D3D11_BUFFER_DESC* pDesc)
|
||||
: m_device (pDevice),
|
||||
m_desc (*pDesc),
|
||||
m_buffer (CreateBuffer(pDesc)) {
|
||||
m_buffer (CreateBuffer(pDesc)),
|
||||
m_bufferInfo{ m_buffer->slice() } {
|
||||
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,17 @@ namespace dxvk {
|
||||
class D3D11DeviceContext;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Common buffer info
|
||||
*
|
||||
* Stores where the buffer was last
|
||||
* mapped on the immediate context.
|
||||
*/
|
||||
struct D3D11BufferInfo {
|
||||
DxvkPhysicalBufferSlice mappedSlice;
|
||||
};
|
||||
|
||||
|
||||
class D3D11Buffer : public D3D11DeviceChild<ID3D11Buffer> {
|
||||
static constexpr VkDeviceSize BufferSliceAlignment = 64;
|
||||
public:
|
||||
@ -49,12 +60,17 @@ namespace dxvk {
|
||||
return DxvkBufferSlice(m_buffer, offset, m_buffer->info().size - offset);
|
||||
}
|
||||
|
||||
D3D11BufferInfo* GetBufferInfo() {
|
||||
return &m_bufferInfo;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
const Com<D3D11Device> m_device;
|
||||
const D3D11_BUFFER_DESC m_desc;
|
||||
|
||||
Rc<DxvkBuffer> m_buffer;
|
||||
D3D11BufferInfo m_bufferInfo;
|
||||
|
||||
Rc<DxvkBuffer> CreateBuffer(
|
||||
const D3D11_BUFFER_DESC* pDesc) const;
|
||||
|
@ -77,8 +77,8 @@ namespace dxvk {
|
||||
pResource->GetType(&resourceDim);
|
||||
|
||||
if (resourceDim == D3D11_RESOURCE_DIMENSION_BUFFER) {
|
||||
const D3D11Buffer* resource = static_cast<D3D11Buffer*>(pResource);
|
||||
const Rc<DxvkBuffer> buffer = resource->GetBufferSlice().buffer();
|
||||
D3D11Buffer* resource = static_cast<D3D11Buffer*>(pResource);
|
||||
Rc<DxvkBuffer> buffer = resource->GetBufferSlice().buffer();
|
||||
|
||||
if (!(buffer->memFlags() & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) {
|
||||
Logger::err("D3D11: Cannot map a device-local buffer");
|
||||
@ -88,26 +88,42 @@ namespace dxvk {
|
||||
if (pMappedResource == nullptr)
|
||||
return S_FALSE;
|
||||
|
||||
if (buffer->isInUse()) {
|
||||
// Don't wait if the application tells us not to
|
||||
if (MapFlags & D3D11_MAP_FLAG_DO_NOT_WAIT)
|
||||
return DXGI_ERROR_WAS_STILL_DRAWING;
|
||||
DxvkPhysicalBufferSlice physicalSlice;
|
||||
|
||||
if (MapType == D3D11_MAP_WRITE_DISCARD) {
|
||||
// Allocate a new backing slice for the buffer and set
|
||||
// it as the 'new' mapped slice. This assumes that the
|
||||
// only way to invalidate a buffer is by mapping it.
|
||||
physicalSlice = buffer->allocPhysicalSlice();
|
||||
resource->GetBufferInfo()->mappedSlice = physicalSlice;
|
||||
|
||||
// Invalidate the buffer in order to avoid synchronization
|
||||
// if the application does not need the buffer contents to
|
||||
// be preserved. The No Overwrite mode does not require any
|
||||
// sort of synchronization, but should be used with care.
|
||||
if (MapType == D3D11_MAP_WRITE_DISCARD) {
|
||||
m_context->invalidateBuffer(buffer, buffer->allocPhysicalSlice());
|
||||
} else if (MapType != D3D11_MAP_WRITE_NO_OVERWRITE) {
|
||||
this->Flush();
|
||||
this->Synchronize();
|
||||
EmitCs([
|
||||
cBuffer = buffer,
|
||||
cPhysicalSlice = physicalSlice
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->invalidateBuffer(cBuffer, cPhysicalSlice);
|
||||
});
|
||||
} else if (MapType == D3D11_MAP_WRITE_NO_OVERWRITE) {
|
||||
// Use map pointer from previous map operation. This
|
||||
// way we don't have to synchronize with the CS thread.
|
||||
physicalSlice = resource->GetBufferInfo()->mappedSlice;
|
||||
} else {
|
||||
// Synchronize with CS thread so that we know whether
|
||||
// the buffer is currently in use by the GPU or not
|
||||
// TODO implement
|
||||
|
||||
if (buffer->isInUse()) {
|
||||
if (MapFlags & D3D11_MAP_FLAG_DO_NOT_WAIT)
|
||||
return DXGI_ERROR_WAS_STILL_DRAWING;
|
||||
|
||||
Flush();
|
||||
Synchronize();
|
||||
}
|
||||
}
|
||||
|
||||
pMappedResource->pData = buffer->mapPtr(0);
|
||||
pMappedResource->RowPitch = buffer->info().size;
|
||||
pMappedResource->DepthPitch = buffer->info().size;
|
||||
pMappedResource->pData = physicalSlice.mapPtr(0);
|
||||
pMappedResource->RowPitch = physicalSlice.length();
|
||||
pMappedResource->DepthPitch = physicalSlice.length();
|
||||
return S_OK;
|
||||
} else {
|
||||
// Mapping an image is sadly not as simple as mapping a buffer
|
||||
@ -136,14 +152,23 @@ namespace dxvk {
|
||||
const VkExtent3D levelExtent = textureInfo->image
|
||||
->mipLevelExtent(textureInfo->mappedSubresource.mipLevel);
|
||||
|
||||
const VkExtent3D blockCount = {
|
||||
levelExtent.width / formatInfo->blockSize.width,
|
||||
levelExtent.height / formatInfo->blockSize.height,
|
||||
levelExtent.depth / formatInfo->blockSize.depth };
|
||||
const VkExtent3D blockCount = util::computeBlockCount(
|
||||
levelExtent, formatInfo->blockSize);
|
||||
|
||||
DxvkPhysicalBufferSlice physicalSlice;
|
||||
|
||||
// When using any map mode which requires the image contents
|
||||
// to be preserved, copy the image's contents into the buffer.
|
||||
if (MapType != D3D11_MAP_WRITE_DISCARD) {
|
||||
if (MapType == D3D11_MAP_WRITE_DISCARD) {
|
||||
physicalSlice = textureInfo->imageBuffer->allocPhysicalSlice();
|
||||
|
||||
EmitCs([
|
||||
cImageBuffer = textureInfo->imageBuffer,
|
||||
cPhysicalSlice = physicalSlice
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->invalidateBuffer(cImageBuffer, cPhysicalSlice);
|
||||
});
|
||||
} else {
|
||||
const VkImageSubresourceLayers subresourceLayers = {
|
||||
textureInfo->mappedSubresource.aspectMask,
|
||||
textureInfo->mappedSubresource.mipLevel,
|
||||
@ -156,31 +181,13 @@ namespace dxvk {
|
||||
cLevelExtent = levelExtent
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->copyImageToBuffer(
|
||||
cImageBuffer, 0, { 0u, 0u },
|
||||
cImage, cSubresources,
|
||||
VkOffset3D { 0, 0, 0 },
|
||||
cImageBuffer, 0, VkExtent2D { 0u, 0u },
|
||||
cImage, cSubresources, VkOffset3D { 0, 0, 0 },
|
||||
cLevelExtent);
|
||||
});
|
||||
}
|
||||
|
||||
DxvkPhysicalBufferSlice physicalSlice;
|
||||
|
||||
if (MapType == D3D11_MAP_WRITE_DISCARD) {
|
||||
physicalSlice = textureInfo->imageBuffer->allocPhysicalSlice();
|
||||
|
||||
EmitCs([
|
||||
cImageBuffer = textureInfo->imageBuffer,
|
||||
cPhysicalSlice = physicalSlice
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->invalidateBuffer(cImageBuffer, cPhysicalSlice);
|
||||
});
|
||||
} else {
|
||||
// TODO sync with CS thread here
|
||||
|
||||
if (textureInfo->image->isInUse()) {
|
||||
this->Flush();
|
||||
this->Synchronize();
|
||||
}
|
||||
Flush();
|
||||
Synchronize();
|
||||
|
||||
physicalSlice = textureInfo->imageBuffer->slice();
|
||||
}
|
||||
@ -229,7 +236,10 @@ namespace dxvk {
|
||||
|
||||
|
||||
void D3D11ImmediateContext::Synchronize() {
|
||||
// TODO sync with CS thread
|
||||
// FIXME waiting until the device finished executing *all*
|
||||
// pending commands is too pessimistic. Instead we should
|
||||
// wait for individual command submissions to complete.
|
||||
// This will require changes in the DxvkDevice class.
|
||||
m_device->waitForIdle();
|
||||
}
|
||||
|
||||
|
@ -72,6 +72,16 @@ namespace dxvk {
|
||||
DxvkCsChunk();
|
||||
~DxvkCsChunk();
|
||||
|
||||
/**
|
||||
* \brief Number of commands recorded to the chunk
|
||||
*
|
||||
* Can be used to check whether the chunk needs to
|
||||
* be dispatched or just to keep track of statistics.
|
||||
*/
|
||||
size_t commandCount() const {
|
||||
return m_commandCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Tries to add a command to the chunk
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user